I have a SPA that I've built with a rest API on the backend. All routes besides login require a JWT.
When the user logs in successfully, the rest API returns an access token, and refresh token.
I'm wondering what the proper strategy is to store these tokens on the client. I was testing Vuex with Vuex-persist. But I wanted to know what the proper pattern-like way is of storing the access and refreshing JWT tokens.
I was thinking of using the front-end to store both tokens in 2 separate cookies, with expiration times. This way, the front-end can check if the cookie exists. If it does, then use the value (access token) to make the rest API call to whatever resource the user is requesting. If it doesn't exist (expires) use the refresh cookie (if it exists) to retrieve a new set of access/refresh tokens.
Would this be considered a good approach or an anti-pattern?
Related
Yet another OAuth2 question that isn't quite covered elsewhere.
I'm using NestJS backend, React frontend, Passport and my own DB for authentication. Trying to add an
OAuth2 identity provider (Google).
I configured my NestJS app as an OAuth Client. After logging in I'm receiving the callback at which point I have an access_token and the requested user details extracted from the payload of the id_token. This is encapsulated in a class extending PassportStrategy(Strategy, 'google') and an AuthGuard('google') and much of it is handled automatically. Code here.
At this point however, I need to maintain an authenticated session between backend (NestJS) and frontend (React). I suppose I need a JWT, but I'm wondering about the best approach:
Can I use a token provided by the IdP (e.g. id_token or access_token)? So that I don't have to worry about issuing tokens myself. I.e. the frontend receives the token (either from backend, or the IdP directly), sends it on every request, backend verifies it with the IdP on every request (verifyIdToken or getTokenInfo of google-auth-library).
One drawback here is the extra network request every time. I'm not sure if there's a need for that because the IdP is only used to identify the user, not for access to other resources. Another drawback is that I need to store a refresh token and handle when the token expires (get new one, update it on the frontend).
So alternatively, could I just issue a JWT myself and not worry about checking in with the IdP? Once the JWT expires I'd need to prompt the user to log in again. In this case, I wouldn't need to store the IdP tokens. But is this good practice? One issue I can think of is that I won't detect if the user revokes access in the IdP (until the JWT expires).
I ended up issuing my own JWT tokens and managing User sessions in my app, as described in this article: OAuth2 in NestJS for Social Login (Google, Facebook, Twitter, etc)
probably my solution would be helpful.
you could access complete source code of my app that implemented with react typescript (redux toolkit rtk Query) and nestjs included of google oauth2 flow with passport.js. resource
I wrote an API that uses JWT to authenticate the incoming requests.
I connected an ASP.NET Core application to this API. When the users login to the application, it asks the api if the credentials are goods, and if they are the api sends back a JWT token to the application.
This application finally stores the JWT to an httpOnly cookie on the client.
Now, I want to use the "User.IsAuthenticated" feature to displays the name of the actual user if he possesses a JWT cookie.
To do so, I wrote a JWTManager which analyze each requests of the application and if the user possesses a JWT cookie, the Manager will authenticates the user with HttpContext.SignInAsync by decoding the JWT, verifying his authenticity from the api then reading all the claims it contains before adding it to the User Session.
Tldr, I discuss to the api with jwt but I use cookie sessions on the application, sessions that I ironically create from jwt too.
My question is, do I need to keep sessions ?
Basically, I implemented the cookie session to use the [Authorize] annotation. But because the api already uses it, I can simply verify if the api returns unauthorized to stop the user from accessing the content he isn't authorized to use.
To display the name, I can avoid the User.Identity.IsAuthenticated and simply look for his JWT, verify if its authentic from the api then displays his name from the JWT. If he hasn't a JWT, I can display "Sign in" instead of his name.
What is the optimal way to use JWT ?
I choose it to reduce the calls to database from the api and to make the cross applications easier to use. And avoiding session will also reduce the memory used by the server to store them.
But is it worth it ? I'll ask the api if the JWT is authentic at each request from the client, then decode the JWT to at least write the username on the navigation bar to each requests (yes I can use cache and ajax to avoid reloading the navbar at each request, but I still need to verify if the user has access to the content).
Is it more efficient than just use a session with several roles and [Authorize] my content ?
Or finally my mixed use of both feature is efficient ? (Authenticate and discuss with the api from jwt will using session on the application)
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.
Background
I'm implementing an authentication system based on JWT and Refresh tokens but I had an hard time searching for serious documentation about the refresh token generation and handling.
The common scenarios I've found expect:
A short-live token JWT that is stateless and not stored on the server-side
A long-live refresh token that is stored somewhere on the client side and on the server-side and that allows to get new authorized JWTs.
Refresh token generation
My first question is about the refresh token generation. I've seen two main scenarios:
The refresh token is a simple random string or a uuid that it is stored (with its expiring time) on the server side and represent a long user session
The refresh token is itself a JWT containing the not-sensitive data of the user that has logged in and has itself an expiration
The first case is the simplest but allows to encapsulate session data only manually, the second case is more complex but allows to encapsulate the session data, the expiration and it is generated only by a secret held in the server (it means more security). In this last case, however, making the JWT persistent is against the JWT phylosophy and more effort is required for validating also this JWT and comparing the data.
Refresh token workflow
Prerequisites
Storing the refresh token on the client side is the only way to persist the session on something like a browser. However it has to been stored securely so there are two scenarios even here:
The refresh token get stored in the browser in something like the localStorage or the sessionStorage (less secure)
The refresh token is passed to the client using a HttpOnly cookie that are less reachable with Javascript.
Question
Assuming that we store the refresh token in an HttpOnly cookie I was wondering: does the endpoint /refresh_token, that returns a new JWT and a new refresh token, need to be authorized?
If the endpoint has to be authorized, I should have a valid JWT for validating my user without requesting username and password again. In a scenario where the user uses the web application in a browser, then he closes it, then after a while he returns to the web application (and the JWT has expired) this is not possible and requires the user to authenticate again.
If the endpoint is not authorized I cannot have, while validating the refresh token, a valid user instance to check the refresh token data against. So, the only thing that I can check is the validity of the refresh token with the store (or with JWT strategies). This solves the above-mentioned scenario but, is this safe enough?
Another scenario is that the endpoint accepts also expired JWTs, validates them and then it checks the refresh token.
How should the refresh token be validated for a secure implementation? What are the best practices about this?
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.