Consider we want to use JWT along with refresh tokens in Spring.
We have to use JWTTokenStore, right?
But if JWTTokenStore isn't a real database and doesn't store anything, where and how should we store refresh tokens?
(We prefer to store refresh tokens in database rather than store them in memory)
Refresh tokens are JWTs by default if the access tokens are. To change that you would have to modify the token services (possibly a custom TokenEnhancer would do it, and maybe also a custom TokenStore). Why not go with the default?
I faced the same problem. The explanation for me is that the tokens was set in the cookies.(No sessions on client side). And I don't want that my refresh token be used like an access token. (Modifying the access token cookie with the value of the refresh token)
Related
I'm implementing security for my React SPA using Spring Security on the backend. After a lot of reading, I opted for the following approach :
HTTPS everywhere
POST /login takes credentials returns JWT_TOKEN & XSRF_TOKEN in cookie form. I build the JWT_TOKEN myself whereas Spring Security handles the XSRF_TOKEN. Both cookies are Secured and SameSite=Strict. The JWT token is HttpOnly.
Subsequent API calls require the X-XSRF-TOKEN header. This is read from the aforementionned cookie. Both are sent and Spring Security compares them. JWT is automatically sent and checked in a Filter.
Every time a XSRF token is used, Spring Security generates a new one to prevent session-fixation attacks
XSS protections are applied by Spring Security
So now I'm wondering about refresh tokens. I'm reading a lot of contradictory info out there. Do I need them with this setup? If so how best to handle this ?
Many Thanks
In general, as its name says, the refresh token changes from one token to another. Typically they are used in OAuth protocol-based authentication. They are useful when an access token has expired, but the user's session is still valid.
First, JWTs are a great choice for access tokens. They have claims that match the access tokens requirements, such as: exp, iat, jti, sub, etc. But, when using a cookie-based authentication there is no need for access tokens and possibly no need for JWT.
As you said, your JWT_TOKEN is being set as an HttpOnly cookie, which means that only the server has access to it. JWT is useful for sharing the initial state between the client and server, and vice-versa. If your server is just taking it to look up the database, you don't need a JWT, you are just using a session concept, and keeping session data on a JWT may not be a good practice.
Second, if your authenticated cookie data will live at /login and die at /logout, there is no need for refresh tokens. Refresh tokens are an exchange key for short-life access tokens. Instead, your cookies keep the session live and don't need to be exchanged by something else.
For example, if the user uses the /login route to exchange your username and password for one short life access_token. He may need the refresh_token to get a new access_token without needing to send his username and password again.
If you are using the OAuth protocol or similar, refresh tokens are essential to provide a more seamless experience for your users and avoid the inconvenience of repeatedly having to re-enter their credentials. But even on OAuth, they are not mandatory.
If I have a single page web application with a Laravel back end, my best option for authentication seems to be Passport with a Password Grant authentication flow. In Passport, this returns an access token and a refresh token.
For security, I would like to issue a short lived access token and refresh it when it expires. However, all the available information about using OAuth with a Javascript application says "don't make your refresh token accessible to the front end" because it's long-lived and can be used by others to generate new access tokens.
For example:
A Single-Page Application (normally implementing Implicit Flow) should
not ever receive a Refresh Token. A Refresh Token is essentially a
user credential that allows a user to remain authenticated
indefinitely. This sensitive information should be stored securely and
not exposed client-side in a browser.
Does this mean that a browser-based SPA cannot use refresh tokens and must, therefore, only issue access tokens that expire after a reasonable "session" length, forcing the user to log in again afterwards?
Otherwise, is there a suitable way to implement short-lifespan access tokens and refresh tokens in a Laravel Passport app with Password Grant authentication, while maintaining good security?
There is no harm in storing refresh token, as they can be used to get another access token after the access token(short lived as you mentioned) expires which create a good user experience.
I'm implementing an Auth server using Spring Security Oauth2. What I noticed is that when spring security saves the access token (using JdbcTokenStore) , the OAuth2AccessToken is serialized as which means the access token is self is saved as plain text. I have a couple questions about this.
1.) The token is never actually retrieved using the access token value. It is retrieved using a token id. Why is that?
2.) Is it Ok to hash this token since it is never retrieved using it's value?
3.) Do we actually need to generate the token id? Can we pass an extra information from the resource server to the authentication server to retrieve the token and validate it against the hash?
By default Spring stores the token in plain text. If you make a request to get a token again in the same browser, you will notice that Spring will return the same token as long as it is still valid.
1) This is not entirely correct. On the resource server, the token is read from the header and a PreAuthenticatedAuthenticationToken is created. Through several steps the token value is used to create the OAuth2Authentication. The key is a intermediate step, but only after you have resolved the token to an OAuth2AccessToken (see TokenStore.readAccessToken())
2) Personally I would hash the token before storing it in the database! This does however require you to implement/extend a TokenStore, since you need to override TokenStore.storeAccessToken() to save the hashed value, and TokenStore.readAccessToken() to hash the incoming token and find the hash in the database.
3) Typically the authentication server and resource server read the same database, and both ends up with a OAuth2Authentication identifying the user. If you want to hash, you just need to implement the store/read methods as described above.
I have implemented a solution like this with Spring Oauth2 1½ ago, so hashing tokens and refresh tokens is diffidently possible. In our case we ended up not using the resource server implementation from Spring Oauth2, because we get 20K requests every minute, and we wanted to delay resolving the token until the request has been validated, and use several layers of caching to avoid hitting the database on every request.
Implemented Django REST and authentication using JWT.
For JWT token we have to refresh it before it expire.
After expired JWT wont give new token.
For my mobile device I need to refresh the token every 10 mins (JWT_EXPIRATION_DELTA).
and if user is not active for more than 10 minutes, then I need to ask to login.
Is there any way that I can refresh the token even after JWT token expired. (we can limit the time to refresh as 2 day)
Whats the best way to handle this behavior in Mobile.
Thanks.
Refreshing tokens in django-rest-framework-jwt
The django-rest-framework-jwt (v. 1.11.0) does not support "Refresh Tokens" as described for example here. It only supports refreshing non-expired tokens; It makes easy to implement a sliding expiration window with width of JWT_EXPIRATION_DELTA. For example, with settings
'JWT_EXPIRATION_DELTA': datetime.timedelta(seconds=300),
'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(days=7),
user cannot be inactive for more than five minutes in order to stay logged in (docs).
Real Refresh Tokens, please?
It is possible to implement the "Refresh Tokens", which are very long lived ("never expiring") tokens, stored in a database, just like in conventional "HTTP Sessions & SessionIDs". This is actually already been implemented for the django-rest-framework-jwt in django-rest-framework-jwt-refresh-token. Another possibility is to use django-rest-framework-simplejwt which also implements the JWT with Access and Refresh Tokens (full example at Medium).
But.. why?
Compared to using only Access Token JWT's, using Refresh Tokens makes possible to revoke access after the Access Token is expired. Refesh Tokens make it possible to have very long ("lifetime of a mobile device") lasting tokens. One may ask why shouldn't you just stick with sessions (sessionid in a Cookie, and session data in database table), if you are creating collection of Refresh Tokens in a database, and accessing that. Using an Access token with expiration time of one hour will mean that database must be accessed once per hour (instead once per PUT/POST request when using "traditional" sessions). In addition, you gain all the usual benefits of JWT tokens (ease of use in microservice network, for example).
You can use refresh tokens, as defined in Oauth2.0
Refresh tokens are credentials used to obtain access tokens. Refresh
tokens are issued to the client by the authorization server and are
used to obtain a new access token when the current access token
becomes invalid or expires,
After a successful login, issue a refresh and an access token. While a access token expires shortly, a refresh token is long lived. Store it securely, and use it to issue new access tokens when the current one expires
I'm getting started with token based authentication using the ASOS (AspNet.Security.OpenIdConnect.Server) framework.
I've got the access token generation and retrieval done and am now moving on to the refresh token bit.
My questions are:
How should I store the refresh token server side?
Should I just store the clientID and the hashed and salted refresh token in a database (Along with utility fields, such as an expiration date)?
What is the expected behaviour if a user of my API has a single clientID and secret, but performs many calls concurrently (Suppose they want to scale out the client on their end across multiple machines to get better throughput for example).
Specifically, I mean what if 1 of the client's access tokens expires, but their refresh token has also expired?
Of course they can go to the token endpoint to get a new access token and refresh token at the same time, but then what about the other instances for that clientID? Assuming that their code is identical (i.e. they don't share knowledge of the refresh token), each instance will also go on to request a new access and refresh token.
If you store a single refresh token for a clientID, you'll end up excessively requesting refresh tokens, potentially every time the access token expires, which would be undesirable.
If you store multiple refresh tokens for a client, how many is a sensible number?
Also, what is the common process of revoking the refresh tokens?
Is it as simple as just deleting it from wherever you're storing it?
Thanks.
Should I just store the clientID and the hashed and salted refresh token in a database (Along with utility fields, such as an expiration date)?
The approach I recommend is to use the ticket identifier attached by ASOS to all the tokens it creates. You can retrieve the refresh token identifier and the expiration date from the SerializeRefreshToken event via context.Ticket.GetTokenId() and context.Ticket.ExpiresUtc.
Note: the default identifier is a GUID but you can replace it using context.Ticket.SetTokenId("token identifier").
Specifically, I mean what if 1 of the client's access tokens expires, but their refresh token has also expired? Of course they can go to the token endpoint to get a new access token and refresh token at the same time, but then what about the other instances for that clientID?
It really depends on your application requirements and how you implement that. You're free to consider refresh tokens as completely independent or, conversely, interdependent. This logic would usually take place into HandleTokenRequest.
Also, what is the common process of revoking the refresh tokens? Is it as simple as just deleting it from wherever you're storing it?
If you use the default token format (more than recommended), refresh tokens will be considered valid until they expire. It's up to you to check whether the token has been revoked from HandleTokenRequest by making a DB lookup (you can get the refresh token identifier using context.Ticket.GetTokenId())