Dealing with expired access tokens in OAuth2 implicit grant - oauth-2.0

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.

Related

What is a good microservice-friendly technique for refresh token security?

I've got an OAuth2-driven authorization system for the applications in my ecosystem using the Auth Code flow. At the moment, it is working extremely well following what I feel are best practices. My current flow can be summed up as this:
User clicks a Login button in application frontend.
Backend for application redirects user to Auth Server login page with redirect URI, client ID, etc, in params.
User logs in, Auth Server redirects to Backend /authcode endpoint with Authorization Code.
Backend authenticates with Authorization Code, receives Access (JWT) & Refresh tokens. It stores Refresh token in its own database, and returns Access token as an HTTP-Only cookie.
When Access token expires, Backend sends Refresh token to Auth Server to refresh.
The problem with this approach is it is heavily dependent on a single-backend/monolith/etc architecture. When the access token expires, the backend app in question needs to be able to get the refresh token and then do the refresh against the Auth Server.
My goals for the future state of this architecture are driven by two main concerns:
Allowing backends to be split into multiple micro-services that are all capable of authenticating the same JWT.
Supporting SSO. Currently, even though all users are managed through the same Auth Server and use the same credentials, they need to enter those credentials separately for each app they log into.
My initial thought was to move the refresh handling to the client-side part of the architecture. Since all the apps are owned by me, I could setup a new flow where a user would login directly with the Auth Server, and then the Access (JWT) and Refresh tokens are set as HTTP Only cookies. This is further supported by the fact that all of my apps are hosted via a single domain name (with different root URI paths for different apps). The new token structure would determine which apps a given user has access to.
My concern there is how to secure the Refresh Token client-side. Most likely I would need to use the Path attribute and depend on the fact that all my apps are on the same hostname, which as I said they are and that will not be changing.
I guess the point of this post is I'm looking for guidance on best practices for handling this kind of scenario.
A few thoughts based on design patterns we recommend at Curity:
BACKENDS AND JWTs
Related APIs should be able to forward JWT access tokens to each other, as detailed in the scopes article. Validating the JWT in each API results in a recommended zero trust setup.
BACK END FOR FRONT END
We recommend a particular way of doing this, focused on separation of web and API concerns - see this code example on the token handler pattern.
Token refresh is handled via HTTP Only cookies and client side retries. This provides a stateless solution that is easy to manage, and where the web back end is static content only, eg a content delivery network. It requires a couple utility API components to be deployed though.
An alternative option, as you say, is to write code within your back end to store tokens, so that cookies only contain a Session ID.
COOKIES AND MULTIPLE WEB APPS
In our resources we use reverse proxies / API gateways as the entry point to APIs, rather than a web back end. Common plumbing such as translating cookies to tokens can then be managed via gateway plugins - as covered in this tutorial.
However, when you have multiple web apps you need to keep cookies isolated during API requests. Each app therefore needs its own API routes. This is awkward but is a consequence of needing to use secure cookies for best browser security. It is best managed in the gateway, and separate domains or subdomains is usually cleanest:
https://api.brand1.com
https://api.brand2.com
Each web team is then responsible for their own API routes and the cookie / CORS / CSRF stuff, rather than the API developers.
SSO
This should be determined solely by the Identity Provider session cookie, which will remain valid as you navigate across apps. If you are presenting a login button when the app does not have a secure cookie yet, then it will not feel like SSO though. One technique for making SSO look seamless is for each app to automatically redirect when it does not have application cookies yet, rather than presenting a login button.
SUMMARY
A long answer, but the best solutions require separation of concerns that is not always obvious. Done well, the end result should be simple code in apps, correct security and an architecture that can be scaled.

Authorization and Authentication in microservices - the good way

I'm considering a microservice architecture and I'm struggle with authorization and authentication. I found a lot of resources about oauth2 and openid connect that claim they solve the issue but it is not clear enough for me.
Let's consider we have a following architecture:
In my system I want to add a feature only for a certain group of users defined by role. I want to also know the name of the user, their email and id.
After my research I find the following solution to be a good start:
SPA application displays login form.
User fills in the form and sends POST request to authN&authZ server.
The server replies with access token (being a JWT) that contains name, email, id and role of the user. The response contains a refresh token as well.
SPA application stores the token and attaches it to every request it makes.
Microservice 1 and Microservice 2 check if the token is valid. If so, they check if the role is correct. If so, they take user info and process the request.
How far away from the good solution I am? The login flow looks like Implicit flow with form post described here but with implicit consents and I'm not sure if it's fine.
Moving forward, I find passing user data in JWT (such as name, email) to be not a good solution as it exposes sensitive data. I found resources that say it is recommended to expose only a reference to a user in token (such as ID) and replace such token with a classic access_token in reverser-proxy/api gateway when sending a request to a microservice. Considering such solution I think that following scenario is a good start:
SPA application displays login form.
User fills in the form and sends POST request to authN&authZ server.
The server replies with access token and refresh token. API gateway (in middle) replaces access token with ID token and stores claims from access token within its cache.
SPA application stores the token and attaches it to every request it makes.
Handling a request, API Gateway takes ID Token and based on the user ID generates a new access token. The access token is send to microservice 1 or microservice 2 that validate it as previous.
How do you find such solutions? Is this a secure approach? What should I improve proposed flow?
Thanks in advance!
You are on the right tracks:
ZERO TRUST
This is an emerging trend, where each microservice validates a JWT using a library - see this article. JWT validation is fast and designed to scale.
CONFIDENTIAL TOKENS FOR CLIENTS
Internet clients should not be able to read claims that APIs use. The swapping tokens in a gateway concept is correct, but the usual approach is to issue opaque access tokens here, rather than using ID tokens. At Curity we call this the Phantom Token Approach.
SECURE COOKIES IN THE BROWSER
One area to be careful about is using tokens in the browser. These days SameSite=strict HTTP Only cookies are preferred. This requires a more complex flow though. See the SPA Best Practices for some recommendations on security.
SPAs should use the code flow by the way - aim to avoid the implicit flow, since it can leak tokens in the browser history or web server logs.
SUMMARY
All of the above are general security design patterns to aim for, regardless of your Authorization Server, though of course it is common to get there one step at a time.
Don't use your own login form. As Garry Archer wrote, use the auth code flow with PKCE which is the recomended flow for applications running in a browser.
If you don't want to get an ID token, don't ask for the openid scope in the initial auth request. The type of issued access tokens (JWT or opaque) can often be configured on your OAuth2 server. So I see no need to issue new tokens at your gateway. Having more token issuers opens more ways of attacking your system.
Your backend modules can use the userinfo endpoint, which will give them info about the user and validate the token. This way, if the token was invalidated (e.g. user logged out), the request processing will not proceed. If you validate just a JWT signature, you will not know about the token being invalidated.
If you plan to make requests between your backend modules as part of of a user request processing, you can use the original access token received from your SPA as long as your modules are in a safe environment (e.g. one Kubernates).

How a mobile app will refresh access_token without refresh_token ? Implicit grant/ OAuth 2

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.

Are refresh tokens necessary for online applications

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.

What is the best way to implement Security in WebApi 2?

Although Web API 2 provides a build-in Authentication implementation using OAuth, but when I read about OAuth Bearer Tokens, I get confused. Using Basic authentication is not a choice for me as we don't want to use SSL.
What do you think is the best security implementation for a publicly accessed API?
What i would do now:
First of, as Badri states, it is important to use SSL, otherwise there is no point in securing the api...
Now you can provide some login action (e.g. a post request to https://my.webapi.com/login) with all the post information.
If the person is authenticated you can respond with a "bearer token" actually it can be any token you want. A token is basically a random string. you can have numbers,letters etc in it.
These tokens are used so the user does not need to send his credentials with every request. It is important to note that this token has to expire of course (e.g. after an hour of inactivity for example).
The user now will have to send this token with every request. This will be used to authenticate the user with every subsequent request. (for as long as the token is valid of course)
To provide a better user experience you could also send a refresh token when the user authenticates. This refresh token is also kept on the users side, and will be used to refresh the token. This way the user does not need to provide it's credentials for as long as this refresh token is valid. This can be much longer than the normal "authentication token" since it is send on very few occasions over a secure connection, thus the chance of it being intercepted is very small.
There is one more thing to take into account: Session hijacking. If someone would be able to get a hold of the token, he can, without the knowledge of the user, impersonate the user. To prevent this (somewhat) you should link these tokens to the users current ip address. If the ip address differs, he would have to login again.
As i mentioned before, you login securely with a post request, and get some tokens back. These tokens have to be send with every request the user makes. With the http protocol you can simply give the token in the the http header. Either in the Authorization part of the header or in some header of your own. (Convention dictates that your own headers start with X-, thus you can use e.g. X-My-Webapi-Auth-token)
What i would do later:
This works perfectly as long as you are in control of all the applications using the api. If you want to open the api up to external developers you will need to put in more security measures since you might want to be able to e.g. block an application, make them pay after x requests, etc...
But when you get to that point, you might want to consider setting up an OAUTH service for authentication, which is a similar story, but a bit more complex. I (or someone else) could elaborate on the measures you could take then, in case you really want it.
If you cannot use SSL, you cannot use bearer tokens, period. It is exactly same as using basic authentication over plain HTTP. The basic premise on which the bearer token is built is that there will be transport security. The post you have quoted, which is by Eran Hammer is about why message based security is better compared to bearer token + SSL. If you have a constraint in using SSL, you must not use bearer token.
Transport security (SSL) is an absolute minimum nowadays. If you cannot use it, because you cannot buy certificates, you will need to reconsider that decision. If there is any other valid reason, take a look at Hawk Authentication by Eran. Thinktecture IdentityModel has Hawk implementation (both as a message handler and OWIN middleware). Take a look at it here.

Resources