Need help regarding refresh token mechanims - authentication

I have a client facing React native application.
I'm using JWT for authentication with quickly expiring access tokens(10m) & long lasting refresh tokens (7d).
I have two servers, one for auth & one for fetching other things.
ex: server.com/auth, server.com/activities
My question is, how to have a good refresh mechanism here ?
Ex: If a user logs in after 2 days and queries an API through my app, how should I send him the new access token back (using his refresh token) - keeping in mind my auth server is at a separate location ?
The obvious solution I see here is to contact /auth from /activities, get the new tokens and send the new tokens in the header of the response, while on the client side keep checking for new tokens in the header & saving them if present.
Is there a better solution than this ? Is this even a good solution ?

An perhaps better option is to look at using the Backend For Frontend (a.k.a BFF) pattern to secure SPA applications.
See
Backend For Frontend Authentication Pattern with Auth0 and ASP.NET Core
The BFF Pattern (Backend for Frontend): An Introduction
Securing SPAs using the BFF Pattern (once and for all)

What I would do, and as far as I know is what most people do is to have your API (/activities) respond with 403 if the access token is expired. The frontend should catch these responses and then ask the authorization server for a new access token based on the refresh token you have. The AS will respond with a fresh access token, which the frontend can now use to send to the API. Usually this exchange will happen automatically and the frontend will eventually retry calling the API with the new access token.
If the refresh token happens to be expired, then the authorization server will respond with a 403, which is a signal to the frontend app that it should ask the user to log in again.

Related

What are the benefits of implementing OAuth (JWT access tokens with refresh tokens)

Current Setup
I'm currently building an application, and have just finished implementing an OAuth authentication server. This is my first "real" attempt at a project that has a legitimate user authentication and management component, so much of this is new to me.
I've implemented the OAuth specification. This means the following:
The authentication is deployed on a separate webserver with a separate DB than the application server.
The auth server logs in a user, and issues them two tokens. One is a JWT access token that contains information about their user identity. This has a short-lived 15 minutes expiry. The second token is a refresh-token. This is a single-use token with a 7 day expiry. It is used to fetch another access token with the application server returns a 401 (the access token has expired).
The application server shares a secret key with the auth server, and has middleware that verifies the JWT access token.
Concerns
My concern is that I've over-engineered a project that didn't need this much complexity. Since the auth/app are distinct, this means that my client code needs to be aware of, and handle refresh token rotation. It needs to interpret 401s, and fetch another access token.
As far as I can tell from my reading, this wouldn't be necessary with simple session cookies that persist. The cookie is just included in requests to my domain. If I killed this approach, and just had my server do a DB lookup on a signed session cookie - I would avoid a lot of this client complexity.
One consideration is that I’m using a React SPA frontend client. This is also new territory for me, so I’m not sure whether or not this changes the situation.
As I said above, I'm new to a lot of this so could use some advice from people who have worked in this space for longer and have the experience. Is OAuth worth the hassle?
Options
OAuth with access tokens (JWTs) and refresh tokens:
Pros: Provides a secure and scalable way to handle user sessions.
Cons: Client needs to be aware of refresh token rotation procedure and handle 401 responses by using the refresh token to request a new access token, which can add complexity to the client-side code. Also adds complexity (and cost) to the AWS infra stuff. I need to know how to get the auth server and app server on the same base URI. Also makes my local dev environment a little more involved.
Server-side sessions using signed cookies:
Pros: Simpler for the client, as it does not need to handle refresh tokens or 401 responses.
Cons: Server needs to manage session state, which can be more resource-intensive. This means a DB call on every request.

API Authentication for PWA

The Setup
We’re building a PWA (progressive web app). The main components are the app shell (SPA) and the API. The REST API will supply the data needed for the app, while the SPA will handle the rest (as per Google recommendation).
The Problem
Authentication of the end-user seems problematic because the web browser needs to be accounted for. We want the user login to persist through closing down the browser.
We’ve done the research about the possible ways of going about it, however we’d like to ensure that we’re not going in the wrong direction.
Solutions we’ve considered
Session based authentication - the user sends username and password to /accounts/auth and receives a HTTP only cookie with the session ID. The session needs to be stored in a database or Redis. The issue with this option is that cookies are automatically sent by the browser therefore we need a CSRF protection in place. Using the Synchronizer Token Pattern a new token would be generated every time a state changing request has been made e.g. POST. This means that the application needs to supply a CSRF token with every request so that the PWA can send it via AJAX. We determined that it’s not ideal as the user can send multiple post requests in a quick succession making some of them fail and resulting in a bad user experience.
We could also use this method without the CSRF by limiting the CORS policy to same domain and adding a header requirement which technically should stop all CSRF, however we're unsure how secure it would be.
JWT token based authentication - the user sends username and password to /accounts/auth and a new JWT token is issued. The JWT then needs to be stored in localstorage or a cookie. Using localstorage means that JWT is XSS vulnerable and if the token is stolen, an attacker can impersonate the user completely. Using cookies we will still have a CSRF issue to resolve. We considered a double submit cookie method but the CSRF would only refresh every time the JWT is reissued which creates a window for the attacker to find out what the CSRF is. It is not clear which method is best to use.
Session based authentication + JWT token authentication - the user sends username and password to /accounts/auth, a session is created, a HTTP only cookie is set in the browser and a JWT token is sent back to the user. The PWA can authenticate requests with the JWT and whenever the JWT expires the app calls /accounts/auth again to acquire a new one. The /accounts/auth endpoint would still need to be CSRF protected, however the impact of it on usability would be minimised.
There seems to be a large amount of articles claiming that localStorage is insecure and shouldn't be used so why are high profile organisations like Amazon still recommending it? https://github.com/aws/amazon-cognito-auth-js - this SDK uses localStorage to store the token.
You don't need to generate new CSRF token each time a client make a request. It's much easier to use a scheme like token = hash(id + secret + current_day). You only need to update it once a day, or even employ mixed scheme (if the token is invalid today, but is okay for the previous day, the server accepts the operation and returns new token in a predefined header for client to renew it). You may also use the cookie as an id, making the token totally stateless and much easier to check, no need to store them in the database.
Here is how I look at it.
JWT token authentication : with this approach, you can always use a time-bound token with its expiration set to say 2 hours or something?
Or another approach would also be to try and see how you could use some of the approaches the Credentials Management API suggests for example, auto-sign-in of users whenever they come back.
Stuff like 2-step verification with OTPs for instance; for very important features in your web app can be a choice. In this case basic stuff are tied to whichever one time authentication method you have.
Actually, you can also use user-defined pins or short codes (seen a lot in banking apps) to grant access to some features in your web app.
Hope this helps, or sparks some ideation.

Authentication - proper way of handling session with tokens

I have a ReactJS SPA application which connects to the ASP.NET Core WebAPI. The API is also an authorization server thanks to OpenIddict. I am using PasswordFlow and RefreshTokenFlow to handle authentication, which means that the server returns an AccessToken and optionally a RefreshToken. At this moment I struggle with handling Remember me functionality properly. When a user wants to rememebered it is no big deal - the server returns an AccessToken and a RefreshToken which the client stores is LocalStorage, so it can refresh the AccessToken when it's about to expire or is expired by using RefreshToken and it is fine - there is a lot of articles and other helpful resources on the Web. The problem comes when the user does not want to be remembered. How to handle authentication is this scenario? The two solutions I see are:
the server only issues an AccessToken, which the client stores in SessionStorage. If it expires - the client forces the user to re-enter his credentials to get a new AccessToken. AccessTokens should be short-lived (according to what I've learned so far, it can be from one up to several hours, but the more hours it is valid, the less secure it is in a situation when it gets stolen. If it lasts for an hour and after that time the user still uses the application, it seems a bit odd to force him/her to login again.
the server returns an AccessToken and a RefreshToken and the client stores it in SessionStorage. During the session, if the AccessToken is about to expire, the client can get a new one by using the RefreshToken. This is risky as well as the server will never know that the user closed his browser and that his/hers RefreshToken should be revoked. Assuming that RefreshTokens have a way longer lifetime, this seems really risky.
I will be grateful for any thoughts, suggestions and insights on this topic.
Thank you!
If you are new this stuff is tricky to understand, but most implementations work like this:
The SPA uses the Open Id Connect Implicit Flow via a 3rd party library
Users are redirected from the SPA to a 3rd party Authorization Server to login
The Login Process is completely externalized from your app
After login the Authorization Server returns a token to your SPA
The SPA calls the API with an access token
PS: I have a code sample and some written guidance that you might find useful.
Further posts describe how silent token renewal works for an SPA, and as John points out above, an SPA does not use refresh tokens.

Multiple SPA with JWT Authentication with Refresh Tokens

I have a weird scenario. I want to have a single backend API with multiple SPAs as frontend (all under the same domain but different subdomains). Here was the original idea for using JWT and Refresh tokens.
User logs in using USN/PWD.
Server Authenticates the request and sends back a JWT with an expiration and permission in claims.
The server sets a refresh token (that is stored in a data store for sessions) in a cookie for the domain and all subdomains.
Now all request send the JWT and cookie to the server.
If the JWT is expired then check that the refresh cookie is still valid and send a new JWT
Now if the user is in a different SPA under the same domain we can send a request to /token?grant_type=refresh_token which will send a JWT token if refresh token is stored in a cookie.
I would like to know drawbacks to this approach.
Another approach I read (https://stackoverflow.com/a/29088725/4664675) looks interesting as the JTI is basically the sessions ID.
I am not too worried about 15 minutes expiration tokens and a refresh token of about 1-week sliding session. All connection from the SPA to API are over HTTPS as well.
What would someone recommend the best way to handle this situation (One login that is used for many apps like Google does for mail, drive, photos, youtube, etc.)? I like the idea of JWT so that I don't have to hit the datastore on every request.
A little further down the road, I would like to make native apps that consume the same API so an authentication and authorization process that can handle both would be ideal! Seems like I need a Single Sign On approach?
PS. This is all from research and this will be the first authentication/authorization workflow that I will be writing.

Token authentication in SPA app

I started new project. It is small application (playground) to learn couple new concepts. I will create backend API using Ruby on Rails and Single Page Application using React. I stuck in Authentication. I would like to create custom Token-based Authorization/Authorization. I came to following auth flow:
User fill password/login and send to backed using Ajax and through secured HTTPS connection.
Backed checks if user exist in DB. If user exist backend create Token and save to Redis with user id.
Backend response with token to client app.
On client side I will save above token to local storage.
Before every request I will get token from locale storage and pass to request header.
On backend I will take token from header and check if exist in Redis db.
Is this flow correct? Should I decrypt token on client side or It is not necessary? This project is only playground but I would like to do It properly. Please give me some comments if above flow isn't good enough.
I think that you have the right approach. This link could give you more details about token-based authentication:
Implementing authentication with tokens for RESTful applications - https://templth.wordpress.com/2015/01/05/implementing-authentication-with-tokens-for-restful-applications/
Hope it helps you,
Thierry