OAuth2 Password Grant vs OpenID Connect - api

I've been reading about OAuth and OpenID Connect extensively, but this question is specifically about the OAuth2 Resource Owner Password Grant (aka OAuth2 Resource owner credentials Grant, aka OAuth2 Password Grant)
Some resources (like the book "OAuth2 in Action" by Justin Richer) says not to use OAuth2 Resource Owner Password Grant for authentication - see section 6.1.3 in the book.
Other good resources like the following all say we can use the OAuth2 Resource Owner Password Grant to essentially authenticate users via trusted apps:
https://www.oauth.com/oauth2-servers/access-tokens/password-grant/
https://stormpath.com/blog/the-ultimate-guide-to-mobile-api-security
https://www.youtube.com/watch?v=FNz0Lupp8HM&index=60&list=PLyUlngzGzkztgTizxM6_zqiw8sRj7vBm0
https://docs.apigee.com/api-services/content/implementing-password-grant-type
https://oauth2.thephpleague.com/authorization-server/which-grant/
https://aaronparecki.com/oauth-2-simplified/#others
But I'm having a hard time understanding why we shouldn't use the OAuth2 Resource Owner Password Grant as essentially proof of a successful authentication?
My understanding of Resource Owner Password Grant flow is that a username and password is provided by the end user to the trusted client (my native app), which then forwards it to my API's OAuth server and exchanges it for an access token (and optional refresh token) that it can use for the rest of the authenticated API endpoints. The native app doesn't save the username/password, but instead relies on the short-lived access token and the longer-lived refresh token (to get fresh access tokens when they expire).
Why would I even need OpenID Connect? Why can't I just use OAuth2 Resource Owner Password Grant as an authentication mechanism?
Both the native app and the API are developed by the same person (me).
Any explanations would be welcome. Thank you.

If both the server and the client application are yours, you may use Resource Owner Password Credentials flow to get access tokens.
If the server is yours but client applications are not yours (= if client applications are developed by third-party vendors), your server should not allow client applications to use Resource Owner Password Credentials flow. It's because Resource Owner Password Credentials flow cannot prevent third-party client applications from stealing end-users' passwords.
The specification of OpenID Connect does not describe how an OpenID provider should authenticate end-users. Instead, the specification describes how an OpenID provider should generate ID tokens. Because an ID token contains a signature generated by the OpenID provider, client applications that receive the ID token can verify that the ID token has been really signed by the OpenID provider.
That is, OpenID Connect is a specification as to how to make the result of end-user authentication be verifiable. It's not a specification as to how to authenticate end-users.

The resource owner credentials grant is of the higher risk then any other grants and defeats the purpose of the protocol, which aims to hide user credentials from the client application.
In the case of native app - you are right, its possible to analyze your app and retrieve the consumer key from it. Also I can imagine someone creates an app similar to yours, and fishes user's password out of it, and executes other potentially malicious actions without users noticing.
I suggest you read the specifications of OAuth2 and OpenID Connect.
Why should you NOT use the resource owner password grant (from OAuth2 spec):
The resource owner password credentials grant type is often used for
legacy or migration reasons. It reduces the overall risk of storing
usernames and passwords by the client but does not eliminate the need
to expose highly privileged credentials to the client.
This grant type carries a higher risk than other grant types because
it maintains the password anti-pattern this protocol seeks to avoid.
The client could abuse the password, or the password could
unintentionally be disclosed to an attacker (e.g., via log files or
other records kept by the client).
Additionally, because the resource owner does not have control over
the authorization process (the resource owner's involvement ends when
it hands over its credentials to the client), the client can obtain
access tokens with a broader scope than desired by the resource
owner. The authorization server should consider the scope and
lifetime of access tokens issued via this grant type.
The authorization server and client SHOULD minimize use of this grant
type and utilize other grant types whenever possible.

OAuth 2.0, regardless of the grant type, is not an authentication protocol.
OpenID Connect is an Authentication Protocol built on top of OAuth 2.0
These are some references (Several are from folks that wrote the OAuth 2.0 and/or OpenID Connect):
http://www.thread-safe.com/2012/01/problem-with-oauth-for-authentication.html
https://twitter.com/ve7jtb/status/740650395735871488
https://nat.sakimura.org/2013/07/05/identity-authentication-oauth-openid-connect/
http://ldapwiki.com/wiki/OAuth%202.0%20NOT%20an%20Authentication%20protocol

Related

Need an OAuth2 server that supports "client credentials" grant type

I need to get authenticated using OAuth2 client credentials as the grant type. The app would need to call the OAuth2 server with only the client id and client secret, get authenticated and receive an access token back, then the app can use the access token to obtain the application's data. There is no regular user involved and the data belongs to the app. This is the same concept as your application connects to the database with a user name and user password belong to the application. The user uses the application without any knowledge of backend database accesses.
There are so many OAuth2 servers that support "code" grant type such as Google, Facebook, Github, but I have not found anyone that supports client credentials. Google asks me to set a service account, it is not the same as client credentials. Does anyone know an OAuth2 server that I use to test my client credential grant code? Thanks.
Keycloak has support for client credentials as authentication for the token endpoint.
https://www.keycloak.org/docs/latest/authorization_services/#_authentication_methods

Can I use OAuth for authentication for trusted client (mobile app)?

I know how OAuth2 and OpenID Connect works. But there is still some confusion bothering me.
We develop our own Auth Server, service API and mobile app. So, the client app is trusted and we use "password" grant type. The app user repository follows the same user database in auth server.
Our customers login to the app by username/password. The app then submits the user credential to the Auth Server token endpoint, which will return the (bearer) access token and ID token (JWT) to the client.
The ID token contains basic user information so that the app can greet user like "Welcome Tony Stark!".
The access token can be used to access API (e.g. update user profile).
OAuth by design is not a tool for authentication. Ref: https://www.scottbrady91.com/OAuth/OAuth-is-Not-Authentication
My questions are
1) Do we need to verify the signature of the ID token if the client only is only interested to get the user information? Also note that the ID token is coming from the token endpoint via https connection.
2) Let's forget about the ID token. Can we treat the user has passed the authentication check (i.e. login success) if the client obtains an access token from the Auth Server? This flow is very similar to simple password login without OAuth.
3) The client can access protected APIs with the access token. Without access token, the client can only invoke some public APIs. Is it equivalent to what can be done with and without login? It seems the access token can be treated as "login session cookie".
4) There is no 3rd party involvement in my case. Everything (client, auth server, service API) is developed and owned by the same organization. Does it still make sense to use OAuth?
Typically a mobile app is considered a public client. Unless you're limiting who has access to the mobile app, it can't be considered trusted as someone could mess with the app outside of your control even if you developed it.
Also, the resource credentials grant type is generally not a good idea.
One thing is that the OpenID Connect spec requires authorization code, id token, or a hybrid flow:
Authentication can follow one of three paths: the Authorization Code
Flow (response_type=code), the Implicit Flow (response_type=id_token
token or response_type=id_token), or the Hybrid Flow (using other
Response Type values defined in OAuth 2.0 Multiple Response Type
Encoding Practices [OAuth.Responses]).
Some other reasons:
Why the Resource Owner Password Credentials Grant Type is not Authentication nor Suitable for Modern Applications
The OpenID Connect RFC says you MUST verify the ID token:
When using the Implicit Flow, the contents of the ID Token MUST be validated in the same manner as for the Authorization Code Flow, as defined in Section 3.1.3.7, with the exception of the differences specified in this section.
Although, you may qualify for this exception from 3.1.3.7 if using TLS:
If the ID Token is received via direct communication between the Client and the Token Endpoint (which it is in this flow), the TLS server validation MAY be used to validate the issuer in place of checking the token signature. The Client MUST validate the signature of all other ID Tokens according to JWS [JWS] using the algorithm specified in the JWT alg Header Parameter. The Client MUST use the keys provided by the Issuer.
If you're able to trust the client, and the user/pass check you've implemented, then you should be able to trust that an access token has been granted to an authenticated identity according to the OAuth 2.0 spec.
The access token in OAuth 2.0 also contains scopes and should limit what can be done with that access token. A login without OAuth doesn't necessarily.
It's a good idea to use OAuth to protect the credentials of the resource owner. If you were to use the resource owner credentials grant type, this still provides some benefits as the user could enter the password only when the client doesn't have a valid access token, ie, the user can enter her password once for an access token and validate the user using that instead of entering the password again or storing it somewhere.
Even though this grant type requires direct client access to the
resource owner credentials, the resource owner credentials are used
for a single request and are exchanged for an access token. This
grant type can eliminate the need for the client to store the
resource owner credentials for future use, by exchanging the
credentials with a long-lived access token or refresh token.
OAuth 2.0 RFC6749
1) Do we need to verify the signature of the ID token if the client
only is only interested to get the user information? Also note that
the ID token is coming from the token endpoint via https connection.
YES.
2) Let's forget about the ID token. Can we treat the user has passed
the authentication check (i.e. login success) if the client obtains an
access token from the Auth Server? This flow is very similar to simple
password login without OAuth.
If I understand the premise. Yes..There is no requirement for using the ID Token.
3) The client can access protected APIs with the access token. Without
access token, the client can only invoke some public APIs. Is it
equivalent to what can be done with and without login? It seems the
access token can be treated as "login session cookie".
The access token is a access (like a key) that for the OAuth Client to use that was delegated permissions from the resource owner.
4) There is no 3rd party involvement in my case. Everything (client,
auth server, service API) is developed and owned by the same
organization. Does it still make sense to use OAuth?
Yes. OAuth and OpenID Connect are used by many, many organizations and is a test solution.
You should not try to re-invent the "wheel". Use known trusted libraries for Authentication, Authorization and cryptographic operations. OpenID Connect has some certified Implementations

How to authenticate SPA users using oAuth2?

Alright, I've spent several days looking for a proper solution on how to properly authenticate users when working with SPAs.
I have my own website.
I have my own API.
I have my own Single Page Application.
I have my own database of users.
The Goal: I need to get an access_token by providing a username and a password.
I looked at OAuth2 Implicit Grant, but it requires users to Approve/Decline the app after successful authentication. It doesn't work in my case since I own both the app and the API.
I looked at OAuth2 Password Grant, which is not perfect since I need to expose client_id/client_secret.
The reason I'm looking at OAuth2 is because the API will eventually be public.
Is there a standard way of doing this? My current options:
Forget about OAuth2 and manually generate access_token when user POSTs username/password (in this case I'd have to introduce OAuth2 when API goes public)
Use OAuth2 Password Grant and inject client_id/client_secret on the server, so just to keep client app very simple (also avoid all of those dev/staging/prod client_id/client_secret pairs)
Implicit Grant
You are right that Implicit grant type does not look appropriate. But I think your reason for not favoring it is incorrect because the approval step is not mandatory and in Spring OAuth 2 implementation (I don't know which implementation you are using) you can configure the Authorization server to auto approve authorization requests so that the approval step is skipped.
The reasons I think the "Implicit flow" is not suitable are
​The client authentication step by providing client secret and authorization code is missing. So less security.
The access token is sent back as a URL fragment (so that the token doesn't go to the server) which will continue to stay in browser history
If XSS attack occurs, the malicious script can very well send the token to the remote server
Resource Owner Password Credentials Grant
If the authorization server and the resource server are the same, I think this is a quick way of getting up and running. RFC 6749 in Section 4.3.2 says:
If the client type is confidential or the client was issued client credentials (or assigned other authentication requirements), the client MUST authenticate with the authorization server as described in Section 3.2.1.
This means that the client authentication with client secret is not mandatory here. Now, for authorization code grant type, we need the client secret because the user provides his/her credentials directly to the authorization server and then when the client requests for the access token, it doesn;t have anything else other than the client secret to prove to the authorization server that this is a genuine request.
But in case of resource owner password credential grant type, the user has provided its credentials to the client itself and the client will then send these same user credentials for requesting access token. Therefore, the access-token request can be authenticated with the user credentials only and if we don't provide a client secret here, I don't think we are losing anything in terms of security.
So, you can definitely use password credential grant type in your SPA.
Authorization Code Grant
I think this should be the preferred option provided the client secret is not stored in the browser. After user authentication (and optionally user approval), the authorization server can redirect the browser to a server side endpoint with the authorization code in the URL. The server side end point will the request for the access token using the authorization code, client id and client secret (which is stored in the server side only). Once the access token is available, the server side endpoint can redirect (HTTP response code 302) the user to the SPA URL with appropriate cookies for CSRF protection and access token. Thus we are not storing the client secret in the browser.
By using authorization code grant type, you are basically making the solution more secured and generic. In future, if you want to do a single sign-on with a different SPA, you can do that easily by reusing the same authorization server with its integration with the authentication database (preferably an LDAP server).
For further details, refer to my StackOverflow answer here.
Building off what has been said already, I would recommend the 'Authorization Code Grant' but with the addition of the PKCE (Proof Key for Code Exchange / 'pixie') extension - for added security, regardless of whether you're implementing a 'public' or 'confidential' type client.
With PKCE, you don't need a client-secret for public clients (/it's kind of like generating a temporary client-secret at the very outset/beginning of each authentication attempt/instance - although even with PKCE for confidential clients you should ideally still use a client secret).

What type of grant is adequate for a React application?

I'm little confused because I don't know what type of grant I should use for my specific scenario.
I've a front-end React application with a back-end using Spring Boot. Additionally, there is a standalone Spring OAuth2 authorization server.
The React application will be a normal public web application where authentication requires username and password credentials.
What type of grant should I use? Is the resource owner password credentials grant a good choice?
There's a lot of things that can influence the best way to approach this; based on the provided information it's possible to showcase applicable options and do some recommendations, but the definitive choice is hard to make without having all the context.
TL;DR On a browser-based application where end-users are issued username/password credentials and the applications needs to make calls to an API on behalf of the users you can either use the implicit grant or the resource owner password credentials grant (ROPC). The use of ROPC should be further restricted to client applications where there is an high degree of trust between the application and the entity that controls the user's credentials.
The use of client credentials is completely out of scope and the authorization code grant may not present any benefit over the implicit grant for what a browser-based application is concerned so by a process of elimination we have two eligible grants.
Resource owner password credentials grant
(check Auth0 ROPC Overview for full details on the steps)
This grant was primarily introduced in OAuth 2.0 as a way to provide a seamless migration path for application that were storing username/password credentials in order to have access to user resources without constantly asking the user to provide the credentials. As you can imagine, storing passwords in plain text is a big no no, so having a way to stop doing that with a very simple migration path (exchange the stored credentials with tokens using this grant) would be a big improvement.
However, access tokens expire so the way to keep obtaining new tokens for access was through the use of refresh tokens. Keeping refresh tokens in storage is better than passwords, but they are still usually long-lived credentials so the act of storing those type of tokens has additional security considerations. Because of this, it's not usually recommended to keep/use refresh tokens in browser-based applications.
If you choose this grant you need to decide what will happen when the access tokens expire.
Implicit grant
(check Auth0 Implicit Grant Overview for full details on the steps)
This grant is a simplified version of the authorization code grant specifically aimed at applications implemented within a browser environment so it does seem be a better fit to your scenario.
An additional benefit is that obtaining new access tokens could happen transparently after the first user authentication, more specifically, by having the authorization server manage some concept of session any implicit grant request for a user that is already authenticated and that already consented to provide that authorization could be done automatically without requiring user interaction.
Conclusion (aka opinion based on what I know which may not be sufficient)
As a general recommendation I would choose the implicit grant over the ROPC grant.

What is the purpose of Resource Owner Password Credential Grant Type in OAuth 2.0?

Based on the answer to my previous question
Ok, OAuth 2.0 is an authorization protocol but when you use ROPC (Resource Owner Password Credential) Grant Type, the way I understand it, you mean to authenticate and authorize isn't it?
Is OpenID still applicable in ROPC? still a little bit confuse with OAuth 2.0 ROPC and OpenID
The Resource Owner Password Credentials grant type does authenticate users but is a non-typical OAuth 2.0 grant type that is only meant for migration purposes, as the spec says:
The resource owner password credentials grant type is often used for
legacy or migration reasons. It reduces the overall risk of storing
usernames and passwords by the client but does not eliminate the need
to expose highly privileged credentials to the client.
This grant type carries a higher risk than other grant types
because it maintains the password anti-pattern this protocol seeks
to avoid.
The Resource Owner Password Credentials grant is not prohibited with OpenID Connect (even though the OpenID Connect spec does not clearly define it beyond OAuth 2.0) but defeats the primary purpose of a federated SSO protocol that OpenID Connect is supposed to be. That is because it locks RPs in to a single authentication method whereby the user credentials are disclosed to the RP. You mileage wrt. to support across Providers may vary.
See also: Does OpenID Connect support the Resource Owner Password Credentials grant?
In my view, the power of resource owner password credentials(ROPC) is utilized properly when we use the refresh token.
Consider a mobile app where user needs to log in. Once logged in and request a token using your clientId, secret, userid and password, normally you get an access token and a refresh token. Access token is normally valid for less time(say 1 hour) and refresh token is valid for a longer time(say 24 hours). ClientId and Secret is stored in the App. UserId and Password is owned by user and never stored anywhere.
When the user tries to access the app after 1 hour, his access token is expired which means in normal scenario, he needs to log in again.
But we can avoid this tedious task of entering his userId and password again by getting a new access token(and new refresh token) by exchanging the refresh token along with the clientId and Secret(no userId and password needed). The new access token will have all the same features of the previous access token. This means as long as user is active atleast 24 hours ago, he doesn't have to log in again. After 24 hours of idle time, both refresh token and access token expires and the log in is required to get a new access token.