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.
Related
Yohoho! I am building an application that leverages OAuth to pull user data from provider APIs, and am wondering about the RFC compliance of the flow I have chosen.
Currently, the user signs into the authorization server which sends an auth code to my frontend client. The frontend then passes the auth code to my backend, which exchanges it for an auth token and then makes calls to the provider to pull data.
In this best practices document, it states:
Note: although PKCE so far was recommended as a mechanism to protect
native apps, this advice applies to all kinds of OAuth clients,
including web applications.
To my understanding, PKCE is designed to ensure the token is granted to the same entity that requested the auth code, in order to prevent attackers from using stolen auth codes to execute unwarranted requests.
Now, it makes sense to me why this is important even if the backend keeps the client secret unexposed, since the attacker can make requests to the backend with the intercepted auth code to receive the token. However in my flow, since I am not creating an authentication scheme and rather trying to authorize premeditated requests, the token stays with the backend.
So why is PKCE recommended here? It seems to me the most a stolen auth code can do is initiate an API request from the backend, with no token or data being returned to the attacker. And assuming a PKCE implementation is the way to go, how exactly would it work? The frontend requesting the auth code and the backend trading it for a token aren't exactly the same, so would it be as simple as passing the code_verifier to the backend to make the call?
Some clarification would be greatly appreciated.
PKCE ensures that the party who started the login is also completing it, and there are two main variations that I'll summarise below in terms of Single Page Apps (SPA).
PUBLIC CLIENTS
Consider a Single Page App that runs a code flow implemented only in Javascript. This would store a code verifier in session storage during the OpenID Connect redirect. Upon return to the app after login, this would be sent, along with the authorization code and state to the Authorization Server.
This would return tokens to the browser. If there was a Cross Site Scripting vulnerability, the flow could be abused. In particular the malicious code could spin up a hidden iframe and use prompt=none to get tokens silently.
CONFIDENTIAL CLIENTS
Therefore the current best practice for Single Page Apps is to use a Backend for Frontend (BFF), and never return tokens to the browser. In this model it is more natural for the BFF to operate like a traditional OpenID Connect website, where both the state and code_verifier are stored in a login cookie that lasts for the duration of the sign-in process.
If there was a Cross Site Scripting vulnerability, then session riding is possible by the malicious code, to send the authorization code to the BFF and complete a login. However, this would just result in writing secure cookies that the browser cannot access. Similarly, the hidden iframe hack would also only rewrite cookies.
The code_verifier could alternatively be stored in session storage and sent from the browser to the BFF, but it would be easy enough for malicious code to grab it and also send it to the server. This does not really change the risks, and the key point is that no tokens should be returned to the browser. It is OK to use secondary security values in the browser, as long as you can justify them, eg for security reviewers. Generally though it is easier to explain if secure values are in secure cookies and less visible to Javascript.
FURTHER INFO
Best practices often vary depending on the customer use case, and at Curity we provide resources for customers (and general readers) to explain secure design patterns. These are based on security standards and we translate them to customer use cases. You may
find our recent SPA Security Whitepaper useful.
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.
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.
The specification of OAuth2 states that an authorization server must not issue a refresh token when using implicit grant. In our use case we protect a RESTful API with OAuth2 and use a Single Page Javascript application as a client for this API. As it would be very difficult to redirect to the authorization server after an access token has expired, we are searching for a better way to get a new valid token. I could think about two different approaches and wonder which one could be better:
Use a hidden iframe to Rerequest a valid access token. For this it is necessary to include a parameter like “prompt=none” which tells the OAuth provider neither to challenge authentication, nor to display an authorization page. If the user is authenticated and has authorized the application the server will send back an access token in the urls # parameters. If one of the previous conditions is not fulfilled, it will redirect with an error like #error=authentication%20lost. With this behaviour we can use short lived access tokens also with an implicit flow.
We could use an additional scope (e.g. offline) which tells the server to hand out a refresh token. Even if the original spec says that implicit flow does not issue refresh tokens (which is correct if the client only uses OAuth it for a first authorization) you are free to define your own scopes for your particular application. You should consider to only allow this scope from well-known clients.
Both approaches are very similar to those of OpenID Connect. Unfortunately there are not many implementations of OpenID Connect at the moment. So first step would be to extend the OAuth2 server until OIC will be more popular.
So which approach should be preferred?
EDIT: The token endpoint needs client authentication, which is only possible for confidential clients like server-side applications. With the second approach it would only be possible to let the RESTful API in our case the resource provider to refresh the token and send it back to the client. I think this would be a security risk. So probably we have only one valid approach.
I'm trying to achieve the exact same thing at the moment.
I've actually implemented hidden iframe approach and then realized you have to be very careful with iframes. Any malicious website can contain your iframe and get access token easily if you don't specify X-Frame-Options.
Best approach for refreshing token should be password grant as specified by the spec. (I wanted my users to login with their facebook account & implicit flow was easier to develop this. I have not quite figured out how to do this with password grant.)
2nd approach also came accross my mind and seems much safer than the 1st to me, since you can usually trust the https & browser storage to keep your tokens secret.
Edit
I realized, even with X-Frame-Options most browsers can't prevent redirects, because this header is attached to the response body and redirected URL will be exposed, therefore access tokens exposed.
Update
Looks like hash fragment is protected by the browser when accessed from the parent page within different domain. So I assume #access_token is safe. My bad. Just as a reminder callback page has to store the access token in its own right, instead of (my original intention) delegating it to the parent page like window.parent.storeAccessToken(hash); which obviously is a dumb thing to do.
From the OAuth0 website:
If you need to authenticate your users without a login page (for example, when the user is already logged in via SSO scenario) or get a new access_token (thus simulate refreshing an expired token), you can use Silent Authentication.
As for the Silent Authentication:
However, redirecting users away from your application is usually considered disruptive and should be avoided, from a UX perspective. Silent authentication lets you perform an authentication flow where Auth0 will only reply with redirects, and never with a login page.
This will allow you to log back the user using an SSO token, without having to prompt him for credentials again.
I am just getting started working with Google API and OAuth2. When the client authorizes my app I am given a "refresh token" and a short lived "access token". Now every time the access token expires, I can POST my refresh token to Google and they will give me a new access token.
My question is what is the purpose of the access token expiring? Why can't there just be a long lasting access token instead of the refresh token?
Also, does the refresh token expire?
See Using OAuth 2.0 to Access Google APIs for more info on Google OAuth2 workflow.
This is very much implementation specific, but the general idea is to allow providers to issue short term access tokens with long term refresh tokens. Why?
Many providers support bearer tokens which are very weak security-wise. By making them short-lived and requiring refresh, they limit the time an attacker can abuse a stolen token.
Large scale deployment don't want to perform a database lookup every API call, so instead they issue self-encoded access token which can be verified by decryption. However, this also means there is no way to revoke these tokens so they are issued for a short time and must be refreshed.
The refresh token requires client authentication which makes it stronger. Unlike the above access tokens, it is usually implemented with a database lookup.
A couple of scenarios might help illustrate the purpose of access and refresh tokens and the engineering trade-offs in designing an oauth2 (or any other auth) system:
Web app scenario
In the web app scenario you have a couple of options:
if you have your own session management, store both the access_token and refresh_token against your session id in session state on your session state service. When a page is requested by the user that requires you to access the resource use the access_token and if the access_token has expired use the refresh_token to get the new one.
Let's imagine that someone manages to hijack your session. The only thing that is possible is to request your pages.
if you don't have session management, put the access_token in a cookie and use that as a session. Then, whenever the user requests pages from your web server send up the access_token. Your app server could refresh the access_token if need be.
Comparing 1 and 2:
In 1, access_token and refresh_token only travel over the wire on the way between the authorzation server (google in your case) and your app server. This would be done on a secure channel. A hacker could hijack the session but they would only be able to interact with your web app. In 2, the hacker could take the access_token away and form their own requests to the resources that the user has granted access to. Even if the hacker gets a hold of the access_token they will only have a short window in which they can access the resources.
Either way the refresh_token and clientid/secret are only known to the server making it impossible from the web browser to obtain long term access.
Let's imagine you are implementing oauth2 and set a long timeout on the access token:
In 1) There's not much difference here between a short and long access token since it's hidden in the app server. In 2) someone could get the access_token in the browser and then use it to directly access the user's resources for a long time.
Mobile scenario
On the mobile, there are a couple of scenarios that I know of:
Store clientid/secret on the device and have the device orchestrate obtaining access to the user's resources.
Use a backend app server to hold the clientid/secret and have it do the orchestration. Use the access_token as a kind of session key and pass it between the client and the app server.
Comparing 1 and 2
In 1) Once you have clientid/secret on the device they aren't secret any more. Anyone can decompile and then start acting as though they are you, with the permission of the user of course. The access_token and refresh_token are also in memory and could be accessed on a compromised device which means someone could act as your app without the user giving their credentials. In this scenario the length of the access_token makes no difference to the hackability since refresh_token is in the same place as access_token. In 2) the clientid/secret nor the refresh token are compromised. Here the length of the access_token expiry determines how long a hacker could access the users resources, should they get hold of it.
Expiry lengths
Here it depends upon what you're securing with your auth system as to how long your access_token expiry should be. If it's something particularly valuable to the user it should be short. Something less valuable, it can be longer.
Some people like google don't expire the refresh_token. Some like stackflow do. The decision on the expiry is a trade-off between user ease and security. The length of the refresh token is related to the user return length, i.e. set the refresh to how often the user returns to your app. If the refresh token doesn't expire the only way they are revoked is with an explicit revoke. Normally, a log on wouldn't revoke.
Hope that rather length post is useful.
In addition to the other responses:
Once obtained, Access Tokens are typically sent along with every request from Clients to protected Resource Servers. This induce a risk for access token stealing and replay (assuming of course that access tokens are of type "Bearer" (as defined in the initial RFC6750).
Examples of those risks, in real life:
Resource Servers generally are distributed application servers and typically have lower security levels compared to Authorization Servers (lower SSL/TLS config, less hardening, etc.). Authorization Servers on the other hand are usually considered as critical Security infrastructure and are subject to more severe hardening.
Access Tokens may show up in HTTP traces, logs, etc. that are collected legitimately for diagnostic purposes on the Resource Servers or clients. Those traces can be exchanged over public or semi-public places (bug tracers, service-desk, etc.).
Backend RS applications can be outsourced to more or less trustworthy third-parties.
The Refresh Token, on the other hand, is typically transmitted only twice over the wires, and always between the client and the Authorization Server: once when obtained by client, and once when used by client during refresh (effectively "expiring" the previous refresh token). This is a drastically limited opportunity for interception and replay.
Last thought, Refresh Tokens offer very little protection, if any, against compromised clients.
It is essentially a security measure. If your app is compromised, the attacker will only have access to the short-lived access token and no way to generate a new one.
Refresh tokens also expire but they are supposed to live much longer than the access token.
I've written a little about this because I was pondering the reasoning myself today.
https://blog.mukunda.com/cat/2023/refreshing-access-tokens.txt
Essentially, I think the main security boost is only there if the refresh token does not remain the same over its lifetime.
Let's say someone steals your tokens from your browser cookies because they had access to your device temporarily.
If they use the refresh token, and the refresh token changes, then you have feedback – you are logged out. That can seem rightfully suspicious to careful users who can then take action and revoke all tokens.
If the refresh token doesn't update upon each use, then it is harder to notice that someone has access in tandem. (Chances are, if does update, then it might update from your device automatically before the attacker can even get to use it.)
If the refresh token does not get updated each time you use it, then I don't see any boost in security from the strategy, since it will be right next to the access token and client secrets.
So, why access tokens? It is so you can check that your credentials are valid regularly.
Do refresh tokens expire? Yes, but usually after a few months if you have "remember me" ticked. There's no expiration time in the spec, so you just go until it fails. Services that require longer unmonitored sessions might have secret credentials so they can refresh their refresh token.
Update:
I also glossed through the OAuth 2.0 specification and see the same reasoning, though it emphasizes that the invalid authentication feedback can be caught on the server side. That is a great point – the server can automate revoking the token if it is compromised.
If a refresh token is compromised and subsequently used by both the attacker and the legitimate client, one of them will present an invalidated refresh token, which will inform the authorization server of the breach.