Per Google's docs it would seem refresh tokens are only necessary for offline applications (applications that may run into an expired access token when the user isn't around).
Access tokens periodically expire. You can refresh an access token
without prompting the user for permission (including when the user is
not present) if you requested offline access to the scopes associated
with the token.
...
Requesting offline access is a requirement for any application that
needs to access a Google API when the user is not present. For
example, an app that performs backup services or executes actions at
predetermined times needs to be able to refresh its access token when
the user is not present. The default style of access is called online.
However, a description of refresh tokens in general and this question in particular both seem to imply that refresh tokens are needed anytime you want to request a new access token.
I think I would agree with Google's explanation and not use refresh tokens. My experience with OIDC providers has been that refresh works as follows:
User requests protected resource from client server
Client server determines access token has expired.
Client server redirects user to OP auth endpoint
OP authenticates user without interaction due to cookies stored on user's browser with OP's domain.
Client server finishes the request.
The user might see a few redirects but other than that the re-authentication went by without any interaction from them. Given this, is it necessary to bother with refresh tokens if the user will always be present at the application?
My biggest concern with using refresh tokens for online apps is that it takes away transparency from the user.
Refresh tokens facilitate long term access and should be stored safely. But they also don't provide a natural way to "sign out", and (most importantly) it becomes completely opaque how, when and from where your data is accessed, as the often used scope name offline_access suggests.
OIDC offers a front channel mechanism prompt=none that largely leads to the same effect (i.e. new tokens), and without needing intermediate redirects if the re-authentication is performed inside an iframe.
Hence in my opinion you and Google are right and the answer must be: No, don't use refresh tokens if the user is present.
No, it is not necessary to bother with refresh tokens if the user will always be present at the application. The reasoning is largely the OP describes.
But there are reasons why one may still want a refresh token:
as the OP mentions the user might see a few redirects and both the UI expert and the branding guy on your team will hate this
when an access token expires in the middle of an HTML Form POST action, the redirect may have lost the context/POST-data on return; you may want to minimize this or you'll have to take appropriate (complex) POST-data-save actions
if your access token expiry is really short, the redirects create a lot of overhead and nuisance; you may not be able to control access token expiry when dealing a Providers in a different domain and when dealing with multiple Providers it will vary across them
when refreshing the access token with a redirect your application now depends on the Provider keeping an SSO session; not all Providers may do this and if they do they may do it in different ways: the SSO session duration may vary between them and the authentication method may vary; as an example: a Provider that doesn't keep an SSO session but does use 2-factor authentication will have large impact on the user experience
Imagine a scenario where you want to use the access token to update user information in almost real-time from the user info endpoint but the access token expiry is relatively short. Either you'll have to perform a lot of redirects with the nuisance as described, or you can use a refresh token.
Refresh token is essentialy a credential reference, that your client can exchange for access token, when there is no active user session.
For example if you want to periodicaly sync issues from Github with your inhouse system.
It is often misused like some kind of session. It is essential to diffirentiate those things. And scope name offline_access is there for a reason.
So in simple cases - you just rely on OP session and get new token with authorize/token endpoints combo. You should not be prompted to provide credentials as long as session is alive and consent is given for that particular app.
If you need to do some backgound stuff - ask for refresh token also.
As for question: no.
EDIT(More in-depth explanation):
if we are talking about web there are two main cases:
Client that can securely store secrets like usual web app with server page rendering and clients, that cant store secrets, like SPA apps. From that perspective there are two main flows (omitting hybrid to not over-complicate): Authorization Code Flow and Implicit Flow respectively.
Authorization Code Flow
On first request your app checks it own session(client session) and if there is none - redirects to external OP(OpenID Connect provider) authorize url. OP authenticates user according to requirements expressed in request, gathers consent and other stuff and returns authorization code. Then client asks token endpoint with it and receives access_token/id_token pair with optional refresh token if user granted offline access consent. This is important, because user can deny it for your app. After this client can request userInfo endpoint to get all user claims that were granted during consent. Those claims represent user identity and do not contain stuff like authentication method, acr etc. Those claims present in id_token alongside with expiration for example. After that client starts it own session and have option to set its lifetime equal to id_token lifetime or use it own to provide smooth UX for example. At this point you can discard access_token and id_token at all if you don't need access to other APIs(like all scopes in access_token are specific to OP and subject). If you need access to some API you can store access_token and use it for access. It becomes invalid - redirect to OP for new one. Expiration can be more lax here, because of more secure environment on server. So even 1hr is an option. No refresh tokens used at all.
Implicit Flow
In this case your lets say Angular app redirects to OP, gets its id_token and optional access_token from authorize endpoint directly and uses it to access some APIs. On every request expiration is checked an if needed, client sends request to OP in hidden iFrame, so there won't be any visible redirects as long as OP session is alive. There are some great libs for that like openid-client.js. No refresh is allowed here at all.
It is important to differentiate client session from OP session, token lifetime and session lifetime.
To address some specific needs there is Hybrid Flow. It can be used to get authorization code and id_token for your session in one request. No chit chat over network.
So when you think about refresh token just check your needs and map them to a spec :) And if you need it anyway - store it as secure as you can.
Refresh tokens are useful for applications that keep access tokens in a server session. For example if a web application doesn't call a protected service using JavaScript XHR, but calls its backend and the backend calls the service. In this scenario, it's easier to get a new access token whenever it's needed than asking a user for a new one.
In JavaScript applications running in browsers, refresh tokens cannot be used, because you need a client secret to get an access token from the /token endpoint and you cannot keep the secret safe in such applications.
The process for getting new access tokens you described can be improved - an application may ask for a new access token just before the current one expires, so the user doesn't get redirected to the OAuth2 server, but the application calls the /auth endpoint with prompt=none parameter in an iframe.
Related
I was reading the documentation on the Auth0 site regarding Refresh Tokens and SPA, and they state that SPA's should not use Refresh Tokens as they cannot be securely stored in a browser, and instead use Silent Authentication instead to retrieve new Access Tokens.
A Single Page Application (normally implementing Implicit Grant) should not under any circumstances get a Refresh Token. The reason for that is the sensitivity of this piece of information. You can think of it as user credentials, since a Refresh Token allows a user to remain authenticated essentially forever. Therefore you cannot have this information in a browser, it must be stored securely.
I'm confused. From my understanding, the only way to retrieve a new access token would be to submit a new request to the Auth server, along with some form of an Auth0 session cookie to authenticate the user that is logged in. Upon receiving the session cookie the Auth0 server would then be able to issue a new Access Token.
But how is that any different than having a Refresh Token in the browser or in the local storage? What makes the Session Cookie any more secure than a Refresh Token? Why is using a Refresh Token in an SPA a bad thing?
There are a lot of misunderstandings about both cookies and refresh tokens and OAuth2.
First, it is not true that only confidential clients can use a refresh token. The OAuth2 protocol says that confidential clients must authenticate, but does not require confidential clients. Ergo, client authentication is optional on the refresh operation. See RFC 6749, Section 6, Refreshing An Access Token.
Second, you have to understand what the alternatives are:
Forcing the user to enter his or her username and password every 5 minutes (whenever the access token expires)
Long lived access tokens
Authentication via HTTP Cookies
Everybody in the world, who doesn't use refresh tokens, uses option #3. Authentication via cookies is functionally and security-wise 100% equivalent to storing a refresh token. Of course, with both tokens and cookies, there are options for where they are kept:
a. HTTP only,
b. secure (require TLS/SSL) and
c. session (in memory) vs. persistent (local, domain storage)
The "HTTP only" option applies only to cookies and, thus, may represent the only advantage of using cookies over tokens. I.e. tokens are handled via Javascript, so there's no option to keep them away from scripts. That said, the tokens are available only to Javascript from the domain of the page that stored it (or as allowed by CORS policy). So this issue can be overblown.
Of course, care must be taken to always use TLS/SSL to transmit either authentication cookies or tokens. Honestly, since we know most breaches occur from within the private corporate network, end-to-end TLS is a basic requirement anymore.
Finally, whether cookies or tokens are ever persisted, i.e. stored somewhere that survives closing the browser or even rebooting the device, depends on the trade-off you're making between usability and security - for your application.
For applications that require a higher level of security, just keep everything in memory (i.e. session cookies, tokens in a Javascript variable). But for apps that don't require as much security and really want a session life on order of days or weeks, then you need to store them. Either way, that storage is accessible only to pages and scripts from the original domain and, thus, cookies and tokens are functionally equivalent.
This is not true anymore (April 2021), Auth0 site now states a different thing:
Auth0 recommends using refresh token rotation which provides a secure method for using refresh tokens in SPAs while providing end-users with seamless access to resources without the disruption in UX caused by browser privacy technology like ITP.
Auth0’s former guidance was to use the Authorization Code Flow with Proof Key for Code Exchange (PKCE) in conjunction with Silent Authentication in SPAs. This is a more secure solution than the Implicit Flow but not as secure as the Authorization Code Flow with Proof Key for Code Exchange (PKCE) with refresh token rotation.
Please note the importance of enabling rotation in refresh token.
The refresh tokens are not used in SPAs, because in order to use it - and to get a new access token from the /token, the SPA needs to have a client secret, which cannot be stored securely in a browser. But since the OAuth 2.0 for Native Apps RFC recommends not requiring a client secret for the /token endpoint (for public clients), the refresh tokens could be used even in SPAs.
To get a refresh token, you need to use the Auth code grant, which passes the code in a redirect URL, which goes to the server hosting the SPA (which can be an extra point of attack). The Implicit grant delivers tokens just to a browser (hash part of the redirect URL doesn't get to the server).
The difference between using a refresh token and an SSO session cookie - the cookie is probably more secure, since it can be marked as HttpOnly, making it inaccessible for attacks using JavaScript code.
Update
With PKCE extension, the Authorization code flow (with a refresh token) became a recommended flow even for browser based applications. For details see the latest version of the OAuth 2.0 for Browser-Based Apps RFC.
Good question - So there is no really secure way to store any tokens on a Browser (or any other confidential info) - see links such as this. Hence Single Page Apps (SPA) should not store a refresh token - a refresh token is particularly problematic, because it is long lived (long expiration or no expiration), and if stolen then an attacker can continue to refresh access tokens after each individually expires.
It would be better to just retrieve your access token when you need it (for instance to call an API) and either store only in memory (still vulnerable to XSS / CSRF) but better - or use and forget. Then make another checkSession call next time you need an access token.
To your question - the checkSession request does not require sending a Token. It is literally as the name suggests - a "check session" against the Authorization Server to see if a Session exists. If it does, then the Authorization Server response will include a fresh access token. See here for an example usage with SPA
Please feel free to leave me comments beneath this answer if anything requires more clarification etc.
As said in OAuth2 rfc6749
The implicit grant type is used to obtain access tokens (it does not
support the issuance of refresh tokens) and is optimized for public
clients known to operate a particular redirection URI. These clients
are typically implemented in a browser using a scripting language
Refresh tokens are not suitable for implicit grant.
My question is:
How a mobile app, will refresh the access_token once it expires?
How the big ones in the market are doing this? Which practices they follow?
I know it is not following security recomendations, but it´s a good practice to make an long-lived access_token in this case? It can get annoying to need to re-authenticate each 30 min you use an app, or you close and reopen it.
As necessary permissions don´t change, a silent log-in on every app start, will be a choice to consider?
You don't necessarily need a refresh token to allow continued usage once an access token expires. If you must insist your clients use the implicit flow, then they may be able to make use of cookies and redirects to keep getting short-lived tokens without user interaction. Providing your client apps are using an HTTP agent which can use permanent cookies. e.g. apps that run in a web browser.
The key then is keeping the user signed into the identity provider the first time the token is requested.
This is done for example by the Identity provider (you I guess?) creating an HTTP cookie for the user agent to persist. Most big identity providers will do this - i.e. keep you signed in.
Now, when the token expires your client app will send the user back through the Oauth process again but, because the user has remained logged in to the identity provider, the identity provider can authenticate the user from the cookie without prompting for credentials.
If your clients instigate this token renewal on a background thread they can request the token as normal and, through the magic of HTTP redirects and cookies, get back a new token from you with no user action required.
Again - this alternative to refresh tokens relies on the client device being able to utilise permanent cookies, and your users remaining signed in and your auth server handling http cookies. If your clients are using native apps this solution may not work.
As in the future you will have 100s of clients maybe your auth plaform should offer different auth flows to different clients.
This article on mobile apps and implicit flow may be of interest to you.
Native apps are supposed to use the Auth code grant. So you can use refresh tokens. There is an RFC that discusses reasons (mainly security) for that as well as platform specific details. There is an important implication - the /token endpoint of your OAuth2 provider should not require authentication for getting tokens, because your application cannot keep its client secret safe.
Watching this video, it details in OAuth2 that the client application first has to get the authorization grant from the Authorization server and then use that grant to get a token before being able to access the resource server. What purpose does the grant serve? Why not give the client the token right away after the user signs on with his/her username and password?
Because it is more secure, for some application types.
What you describe is so called authorization-code-flow. It is normally used for "classical" web applications, where only the backend needs to access resource server. The exchange of authorization code to access token happens on the backend and access token never leaves it. Exchange can be done only once and in addition client id and secret (stored on the backend) are necessary.
Single-Page-Applications often use implicit-flow where access token is delivered to the frontend directly in the URL.
See more here:
IdentityServer Flows
EDIT: Q: "I still don't see how it is more secure given that you have to have the grant in order to get the token. Why need 2 things instead of just 1 thing to access the resource? If someone steals the token, they can access the resource anyway – stackjlei"
"Stealing" access token will work independent on how your application acquires it. However, stealing access token on the backend is much more difficult than on the frontend.
Authorization code is delivered to the backend also over the frontend but the risk that someone intercepts and uses it is tiny:
It can be exchanged only once.
You need client-id and client-secret in order to exchange it. Client-secret is only available on the backend.
Normally, authorization code will be exchanged by your backend to access-token immediately. So the lifetime of it is just several seconds. It does not matter if someone gets hold of used authorization code afterwards.
In your scenario there could be two servers, an Authorization and a Resource one.
It could be only one as well, but let's imagine this scenario.
The purpose of the Authorization Server is to issue short lived access tokens to known clients. The clients identify themselves via their CLientID and CLientSecret.
The Authorization Server ( AS ) holds the list of clients and their secrets and first checks to make sure the passed values match its list. If they do, it issues a short lived token.
Then the client can talk to the Resource Server ( RS ), while the token is valid. Once the token expires, a new one can be requested or the expired one can be refreshed if that is allowed by the Authorization Server.
The whole point here is security, Normally, the access tokens are passed in the Authorization header of the request and that request needs to be over https to make sure that the data can't be stolen. If, somehow, someone gets hold of an access token, they can only use it until it expires, hence why the short life of the tokens is actually very important. That's why you don't issue one token which never expires.
You have different type of OAuth. On type doesn't require to use the 'grant' authorization. It depend who are the user/application, the ressource owner and the server API.
This way, you - as a user - don't send the password to the application. The application will only use the grant token to gain access to your ressources.
I think this tuto is a pretty good thing if you want more details
https://www.digitalocean.com/community/tutorials/an-introduction-to-oauth-2
I have two clients, one Public Client used by regular end-users logging in via our web page or native apps and one Confidential Client for our admin system. Both issues two JWT's, one Access Token and one Refresh Token.
The Public Client is not allowed to issue admin rights. The Access Token is short lived, and the Refresh Token has infinite life span.
The Confidential Client is allowed to issue admin scopes. The Access Token is short lived, and the Refresh Token lives 24 hrs.
Is it possible, using Spring Security and their oAuth2 implementation, to downgrade the admin user once the refresh token is expired? That is, once the user have been logged in for 24hrs, the user is not totally logged out, but on the next login he gets two new JWT's, one Access Token for regular user access and one matching Refresh Token for that access level. I guess I'm looking for some kind of hook in the Spring Security framework that allows me to handle token expiration in a customised way.
There's a sentence on your question that confuses me a bit, but I wanted to elaborate on other aspects so this did not fit in a comment.
... the user is not totally logged out, but on the next login he gets two new JWT's, one Access Token for regular user access and one matching Refresh Token for that access level.
What do you exactly mean with on the next login? My confusion here is that if the objective is not to logout the user, then there won't be a next login. I guess this could mean that almost to the end of the refresh token expiration you would want to do your downgrade request and use the still valid refresh token to get a new pair of tokens with less permissions.
According to the OAuth specification you can perform a refresh token request and ask the server for an access token that has less scopes than the one you currently have. However, it also dictates that if a new refresh token is returned, then that token needs to have the exact same scope as the refresh token included in the request.
Personally, for this scenario I would consider instead of downgrading tokens just ensure that in order to perform any administrator related operation the user must be an administrator and actually provided his credentials in the last 24 hours. You could accomplish this by tracking the date and time a given user actually performed a login (by providing their credentials) and then authorize administrator actions based on that value. This way you can increase the lifetime of refresh tokens for the confidential client and only force the administrators to login again if they want to perform a privileged tasks and their current tokens aren't fresh enough.
Finally, still on the subject of refresh tokens (with focus on the security considerations section)... when you say web app for the public client I'm assuming it's a browser-based Javascript application. If this is correct it's generally not recommended to use refresh tokens for these applications because refresh tokens are usually long-lived (in your case they seem to never expire) and the browser cannot ensure secure storage for them. This increases the likelihood of them leaking which would give an attacker access to the application for the lifetime of the token. You may have other constraints that make this security consideration not applicable, but I wanted to call your attention to it nonetheless.
In the answer to the question Why do access tokens expire?, the first point provided states:
[Bearer-Tokens are] short-lived and requiring refresh, they limit the time an attacker can abuse a stolen token.
But when an Access-Token is used (From a native-app), the Client uses the Refresh-Token to get a new Access Token, and sends that new token back to the requestor. So if an attacker uses somebody else's access token, he'll just be sent a brand new access token every time.
So who cares about how long the token lasts? If an attacker gets it, they have taken over the session For As Long As The Refresh Token Lasts
I already know a dozen answers to my question, but I have questions to each answer. My original question was so long because I explained every scenario and how they are inconsequential or false (as far as I know). So please try to help me understand and I'll comment if I think the answer has caveats.
Addition/Edit - Hoping for more answers with my additional information
Web Page calls a Client with Resource Owner (User) Credentials
Client calls the Auth Server and gets an Access and Refresh Token. The Access Token will expire in 5 minutes, the Refresh Token will expire in hours or days or whatever.
Client sends the Access Token to the Web Page
Resource Owner (User) uses the web page
Web Page sends the Access Token to the Client
Client sends the Access Token to the Resource Server
Resource Server checks the Access Token in any number of ways
Resource Server sends Resources to the Client
Client sends Resources to the Resource Owner
Resource Owner (user) Continues to use the Web Page
The Client, either during Each Request or every 4 minutes and 30 seconds, uses the Refresh Token to get a new Access Token
The Client, either during Each Request or every 4 minutes and 30 seconds, sends a New Access Token to the Active Resource Owner
Yes? No? Since the Resource Owner is Actively using the web site, the web site is in constant communication with the Client, and the Client gets a new Access Token (Using the Refresh Token) and sends it back to the web site, so the Active user can continue using the site without being kicked out every 5 minutes.
Therefore, if ANY Person gets ahold of that Access Token, and are hitting the Client with it, the Client will continue to send new Access Tokens to whoever has that Access Token. Granted: After a single refresh, one of those two people will have a bad Access Token and be booted, but not necessarily the right person.
Your point seems to be that if an attacker can take over your browser session then they will be able to access the third-party resource for the entire length of the refresh token, as you've described. So what's the point of having a short-lived access token?
There's certainly some truth to that, but there are two general responses:
Using a refresh token makes it practicable to invalidate the user if the third-party figures out that the session has been taken over by an attacker.
The access token / refresh token system is used to prevent or limit other kinds of attacks that you haven't mentioned.
Regarding the first point, remember that the access token is sent to the resource server, not the authorization server. Although there's nothing in the specification that prevents the resource server from checking the validity of the user, in practice that could present performance issues. Access tokens are typically designed to be self-validating, without requiring access to some external resource.
Given that, the only way to invalidate a user is to do it on the authorization server when the refresh token is sent in. The authorization server sees that this user has been marked as compromised, and refuses to send a new access token.
Regarding the second point, there are plenty of other security scenarios that OAuth is designed to protect against other than a user's browser session being taken over by an attacker. What if someone is able to get ahold of the access token in some other way? Since the access token itself isn't generally used to get access to the client (see below), they won't be able to get the client to refresh the token for them, and therefore the fact that the access token is short-lived will be a security advantage.
As a reference, both of these points are made succinctly in this email to the Oauth Working Group mailing list.
Looking specifically at the flow you described in your post, I think your confusion is rooted in the idea that the client (web server) sends the user agent (the browser) the access token (your step 3), and that that token (in the form of a cookie) is what the client uses to authenticate the user agent. Although it's possible for a web framework to do those things, neither one is a part of OAuth (nor generally true of web frameworks, in my experience).
Access tokens are short-lived, refresh tokens are long-lived. Access tokens are presented to the Resource Server (and only the Resource Server) that hosts the protected content to get access. Refresh tokens are presented only to the Authorization Server, never to the Resource Server. So when an attacker obtains an access token, he can use it for the lifetime of the access token to get access to the protected content.
When the access token expires there's no way to get a new one unless he has obtained the refresh token as well. Besides that, when using the refresh token the client typically authenticates itself to the Authorization Server, so even when the attacker got the refresh token, he would also need the Client's credentials to use it to get a new access token.