The normal flow for OAuth2 as described in this SO reply is as follows:
Send API request with access token
If access token is invalid, try to update it using refresh token
if refresh request passes, update the access token and re-send the initial API request
If refresh request fails, ask user to re-authenticate
This is all well and good for most API calls, but I wonder one thing: Authentication.
When a user attempts to sign in to my fancy new webapp using their favourite service, should I use their refresh token (or cached access token in the case of OAuth1) to attempt a sign in, or should I always go and get a fresh token from the service provider (Google, Facebook, etc) and discard the stored access and refresh tokens?
User authentication and OAuth 2.0 are two different things. The difference is explained in detail in: http://oauth.net/articles/authentication/. Even when building user authentication/SSO protocols on top of OAuth 2.0 - which is what OpenID Connect does and some vendor-specific implementations - the refresh_token still always applies to the access_token not to the user authentication event or identity token.
You can not use a refresh token on its own to refresh a user's login session since some interaction with the user (may be active, may be passive) through the browser is required to confirm that the user is (still) present.
To refresh a user's login session you will always have to redirect to the identity provider and get fresh authentication information. Note that that interaction will probably also give you a new refresh token that could be used to refresh the access token.
Related
We have implemented the below process for revoking OAuth access tokens / refresh tokens to de-link an external app from our application.
On logout / user initiated de-linking action, we delete the access token and refresh token that was obtained from the initial authorization flow
User has to go through the authorization flow again once again to obtain the access token and refresh token
We are not calling any token revoke function / API call to the authorization server
My question is:
Does the authorization server automatically revoke the first set of access token + refresh token if a new authorization flow has been initiated by our app?
Are there any potential pitfalls to avoid in this approach?
The reason we took this approach is because most 3rd party apps do not offer revoke access related APIs and require the user to go to the 3rd party app to remove access / de-link the authorized apps.
Does the authorization server automatically revoke the first set of access token + refresh token if a new authorization flow has been initiated by our app?
No, most won't. Consider a scenario where a user is logged into your application from multiple devices. Each would get a valid access/refresh token.
So, you can't rely on this.
I am developing mobile application that works with server side using OAuth2. For authorization we use OpenID Connect with authorization code flow. Typical step in the authorization process on mobile devices in this flow is to open authorization url in system browser and then capture redirect url with authorization code.
In case when user is required to enter login and password in browser it is OK. But we have some clients authorized by IP and in this case system browser auto closes immediately after launch and returns successful authorization. Such useless browser launch is annoying and I'd like to prevent it.
The only idea I have right now is to make direct HTTP authorize request with prompt=none parameter as described in https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest to try authorize by IP. And in case of login_required or interaction_required errors repeat it in system browser without prompt parameter.
prompt=none
The Authorization Server MUST NOT display any authentication or
consent user interface pages. An error is returned if an End-User is
not already authenticated or the Client does not have pre-configured
consent for the requested Claims or does not fulfill other conditions
for processing the request. The error code will typically be
login_required, interaction_required, or another code defined in
Section 3.1.2.6. This can be used as a method to check for existing
authentication and/or consent
Is there any other way to detect moment in authorization flow when user interaction with web page is really needed? So I can open browser only if it is needed. And without additional requests useless for most clients.
Since you use OpenID Connect, you might think of enabling some other mechanism to maintain authorized state between application, backend and identity server.
One such scenario could be usage of Access and Refresh tokens,
First login, end user authentication is mandatory
Your app receive tokens (ID token, access token and refresh token)
Customer use the app and app use access token to communicate with the backend
Customer use the application second time
You know previous access token is expired so you obtain a new access token using refresh token
Of course refresh token can expire or identity serve can revoke the access token for some reason (ex- user changing password). But IMO this is the best solution provided by specification itself.
I am building a (set of) web application; the backend has REST-like API, the frontend will be some REST JS app, android apps etc; and I'm trying to come up with an SSO functionality.
Looking at Oauth2/OIDC it seems the best way would be to use Implicit flow; however, the access tokens in implicit flow (in oidc) have a set expiration. The refresh token is not part of implicit flow.
How do I ensure that the user will stay logged in? I.e. when the access token expires, the frontend application will try to obtain a new one from an auth server; that is supposed to ask for username/password. Alternatively, it can build a session with the frontend (using cookies), but how is that different from a refresh token?
It seems to me that getting the access token e.g. from the android app means at least opening the web browser; depending on the expiry length, that could be quite often. Is that the correct flow or am I missing something?
You are right, the issuance of a refresh token is not allowed with the Implicit grant type.
However, the refresh token and the access token are not needed to know if the user is logged in or not (the access token only allows you to access on protected resources). You have to use the ID Token which is issued in the authorization response.
You can verify if the user is still logged in by sending an authorization request with the query parameter prompt=none (see section 3.1.2.1. Authentication Request). I recommend you to send the current ID Token using the id_token_hint query parameter as mentioned in the same section:
ID Token previously issued by the Authorization Server being passed as a hint about the End-User's current or past authenticated session with the Client. If the End-User identified by the ID Token is logged in or is logged in by the request, then the Authorization Server returns a positive response; otherwise, it SHOULD return an error, such as login_required. When possible, an id_token_hint SHOULD be present when prompt=none is used
If you receive an error (login_required or interaction_required) then the user may be logged out.
Another way could be to use the Session Management feature. But as this specification is not yet approved (draft 27), it may be subject to changes and may not be available. However it is a very simple way to know the status of the user.
Consider sample OAuth2 flow: we go through OAuth2 authentication for a web server app.
Authorization code request is being sent - user is presented with "log in" UI.
After he inputs credentials - we get authorization code and use it for access/refresh tokens.
Let's say there is a business reason to re-authenticate the user before his token expires.
For that - authorization code request is issud again - however this time it is not resulting in "log in" UI and new authorization code is granted without user input. Why's that?
Why that happens? Is it some state stored on client's browser?
It means that the OAuth server thought the user had already logged in and that re-authentication could be omitted. So, probably some state is cached on your browser for the login session.
If the OAuth server supports OpenID Connect, try to add 'prompt=login' parameter to the authorization request and you will always see the login UI. See "3.1.2.1. Authentication Request" in OpenID Connect Core 1.0 for details.
I am trying to get access tokens from OAuth.io for any Google based provider however whenever I authenticate I get an access_token but no refresh_token. I have chosen offline for the access_type but still no joy.
I have tried looking through the documentation for a solution but it barely covers anything related to the refresh token.
To get the refresh token from Google, you need 2 things:
The offline option
cf https://developers.google.com/accounts/docs/OAuth2WebServer
"A token that may be used to obtain a new access token. Refresh tokens are valid until the user revokes access. This field is only present if access_type=offline is included in the authorization code request."
The option approval_prompt set to "force"
cf https://developers.google.com/accounts/docs/OAuth2WebServer
"Important: When your application receives a refresh token, it is important to store that refresh token for future use. If your application loses the refresh token, it will have to re-prompt the user for consent before obtaining another refresh token. If you need to re-prompt the user for consent, include the approval_prompt parameter in the authorization code request, and set the value to force."
so your script should look something like
OAuth.popup('google', {
authorize: {
approval_prompt: 'force'
}
}).then(function(google) {
console.log(google.refresh_token)
//send the refresh token to your server
})
If you are working client-side (Javascript / iOS / Android / Phonegap), you may also need to activate the following option: Send refresh token to front-end in the OAuth.io dashboard > General > advanced option to allow your client side SDK to retrieve the refresh token
https://jsfiddle.net/Lqyc5jpw/