I am new to JWTs and I have a question about it.
I have a web app with React, Node.js, express, using axios for ajax calls and npm jsonwebtokens for the access tokens.
I read a lot about JWT access tokens and refresh tokens but still one thing is not clear to me.
let's say a user logged in, got his access token and a refresh token, the access token will expire in 15 minutes.
What is the best way to go about it ?
set a timeout that will execute an API call to get a new access token after 15 minutes (let's say 14.5 minutes to be on the safe side)
set an interceptor that will check if the token is still valid and if not first get a new token and then continue with the request
is there another way I didn't considered?
If number 1 is the best way how do I handle a page refresh? the way I have it setup right now is when a user is logging in the login function calls a _refreshCountDown function that:
counts the time until the token expiration - with a setTimeout function
execute the refresh_token API call
call it self back again to start a new countdown based on the new expiration time
now if a user refreshes the page the login function is not being called therefore the _refreshCountDown is never being called.
how would you have handle this scenario?
will appreciate any answer
thanks :)
Related
I have an odd problem. I'm new to JWT authentication so it's probably something I'm doing wrong.
I'm testing out the Refresh Token mechanism and it works sometimes but not others because sometimes the JwtBearerEvents.OnAuthenticationFailed event does not fire.
I'm using C# (.NET 7) to build an ASPNET Core WebAPI.
Essentially:
On log in (via an AJAX call) I create a JWT token (expires after 10 seconds) and a refresh token (expires after 10 days) and send each back to the client in a cookie.
Chrome correctly lists both the JWT token and the Refresh Token cookies.
I make further (valid) GET requests via AJAX to the API methods which process and return successfully.
If I make a request just after (but within a second of) the expiry time of the JWT token then the JWT cookie is sent to the API, fails validation and the OnAuthenticationFailed event fires.
The Refresh Token mechanism does its thing and the JWT token and Refresh Token are successfully refreshed. Chrome shows the updated cookies correctly. All brilliant so far.
I make further (valid) GET requests via AJAX to the API methods which process and return successfully.
But...if I make a request a bit longer after the expiry time of the JWT token (only a second or 2 difference to Step 4.) then the JWT cookie is deleted by Chrome and is not sent, so the token validation never occurs, the OnAuthenticationFailed event DOES NOT fire and the Refresh Token process is never called.
User has to log in again because the Refresh Token mechanism didn't happen.
I guess my question is: Is OnAuthenticationFailed the best way to determine if the JWT token has expired, or is there a more reliable way? I've looked online but can't find any resources to explain this.
Is OnAuthenticationFailed the best way to determine if the JWT token
has expired, or is there a more reliable way?
I think you'd better judge from the expiretime,and there's a claim typed of exp indicates the seconds from 1970-1-1 to your token exp time
after you authoried succeeded,you could try to get the claim type of"exp" from httpcontext
app.Use(async(context,next)=>
{
var claims = context.User?.Claims;
var exp = claims.FirstOrDefault(x => x.Type == "exp");
await next.Invoke();
});
Or you could try to check the claim when you validate the token
I think I've found an alternative way of refreshing the tokens which doesn't require the expired JWT cookie to be sent at all.
I'd followed a tutorial which used the JwtBearerEvents.OnAuthenticationFailed event to capture expiry and, as I'm a bit new to this, had to go through it all with a fine toothcomb to work out why it wasn't working.
The client-side code now responds to the simple 401 NotAuthorized status and that kicks of the process to refresh the token, which only requires the Refresh Token cookie to be sent.
Update: Just in case anyone else is stuck with this, in the case where the JWT cookie is removed by the browser due to expiry and therefore doesn't send it, the OnChallenge JwtBearerEvents event occurs instead of OnAuthenticationFailed.
Stack: React, tRPC, Redux Toolkit
So I'm trying to build out my auth in a way that's somewhat secure and can handle persistent logins. The best approach I've found so far is to have a short-lived JWT that authenticates the user, and then a refresh token with a key saved on the DB that allows new short-lived JWTs to be generated. The short lived token would be stored in my Redux store, while the refresh token would be saved as a cookie so it can be used to log in the user when they refresh the page.
So my first question is, is this in general a good way to approach this problem? I see conflicting answers sometimes.
The second problem I'm facing is that if I want to use a refresh token, I'm going to have to check and see if the JWT is not expired before each API call, and if it is, hit the /refresh endpoint and use the new JWT. However, with my current stack, I'm not sure how to do this in away that doesn't involve a lot of copy and paste code.
The only solutions I've been able to think of so far are:
Just include both JWT and refresh token in every API call. Always send back either the same JWT or a new JWT. If the refresh token is expired, send back a 401.
Do something to so that before every thunk is dispatched, check the JWT/refresh token and hit /refresh if needed before dispatching.
I'm sure there's a better way to handle this though. Any pointers?
Are you sure that you need the short-lived JWT in the first place? Maybe all you need is a good-old cookie-based session. In fact, what you describe with how the refresh token would be used + the first proposed solution, is pretty much how you would use a session. Unless there is a real need for short-lived JWTs as access tokens, I would get rid of them.
If you decide to stick to access and refresh tokens, then what you describe in solution 2 is not enough. You always need a way of intercepting a 401 response from the API, which indicates that the access token is expired. You should then refresh the access token and call the API again. If the refresh fails with 401, then you know that the refresh token is expired. The expiration check needs to be done on the backend because only there you are sure of the clock settings. Clients can have their clocks skewed which makes verifying expiration time on the client side useless.
I'm building a react native app which uses the spotify web api. I'm using the authorization code flow to authorize a user. First I get a authorization code which can be used to obtain an access token and a refresh token. Everything works!
The problem is: an access token is only valid for a limited amount of time. That's where the refresh token comes in. I understand this concept, but I'm breaking my head about how to implement this.
Let's say a users opens the app, requests an access token and uses this for some time. Then, the user closes the app. After 15 minutes, the users opens the app again. The access token has now expired, so I need to request a new access token.
I've come op with several "solutions". Can someone point me to the correct solution?
Solution 1:
Every time the user opens the app, I request a new access token and use this. Problem: when the user uses the app longer than the valid time of the access token, I won't work anymore.
Solution 2:
I use the access token that's stored in the secure storage on every request. When a request comes back with 'access token invalid' (I don't know the exact error code but you guys know what I mean), I request a new access token with the stored refresh token, and then I send the previous command again (with the new access token). But my question here is: can I use some kind of "wrapper function" which checks the response of the request, and if the response is "access token invalid", it automatically requests a new access token and runs the previous request again.
I think certainly correct solution is solution 2,and i think its clear enough.
and for using solution 2 you need somthing like wrapper function,yes its intelligently.
so you should use interceptor:
what is interceptor ?
You can intercept requests or responses before they are handled by then or catch.
in link below there is a good example of implementing refresh token in axios interceptor:
https://gist.github.com/Godofbrowser/bf118322301af3fc334437c683887c5f
I agree that Solution 2 is the best, each time you do a request you can check to see if the Access Token has expired, and if it has then you can request a new Access Token using the Refresh Token as you mentioned and then make your request, in my own project I do this in a FormatRequestHeadersAsync method which calls a CheckAndRenewTokenAsync method where I perform the following check, here shown in C#:
if(AccessToken?.Refresh != null && (AccessToken.Expiration < DateTime.UtcNow))
{
AccessToken = await GetRefreshTokenAsync(
AccessToken.Refresh,
AccessToken.TokenType,
cancellationToken);
}
You can store the Access Token and the Refresh Token and then use something similar to this before you make each request to the API this will refresh your token and then you can store the new Access Token and the existing Refresh Token.
Normally Google Access token is valid for one hour but I want to set it to no expiry. How can I do that, please help
Google access tokens are only good for one hour this is Oauth2 standard and can not be changed. You will need to use a refresh token to request a new access token. No idea if that is possible with dialogflow you will likely have to request your user authenticate again after an hour.
OT: Thats an impressive app you are working on if your users will be using it beyond the access token limit.
According to [1], OAuth token maximum lifetime is 1 hour (3600 seconds) and it cannot be changed.
If your intention is that your application may continue working without having to "manually" recreate a new token, then you could try creating a session client that scopes to multiple requests, as described in the Best Practices Dialogflow reference [2]:
"To improve performance, you can use a single instance of a session client object for multiple requests. The session client reuses the same access token for as long as it is valid (typically one hour). Once it expires, the session client refreshes the access token automatically, so you don't need to recreate the session client to refresh your access token. Your request that also refreshes the access token can take an extra second or two".
Please, try this and let me know the results.
[1] https://cloud.google.com/iam/docs/creating-short-lived-service-account-credentials#sa-credentials-oauth
[2] https://cloud.google.com/dialogflow-enterprise/docs/best-practices
I am a fair way through implementing an actionscript OAuth library which I am initially testing with Google's Drive Api.
I know how you are supposed to refresh an access token using your refresh token but my question is how do I test it?
How do I make my access_token expire so that I test my code that catches the error, attempts a refresh and then re-loads the initial request? If I can only do this once a week (or however often they expire) it's going to take a while to get it right!
Thanks
If you're looking to test your code, you don't actually need to invalidate or expire the access token. Simply make a (say) Drive call with a null access token and you will receive the same 401 response that you would have got with an expired access token.
Well, judging by the lack of responses to this question I am assuming that there is no way to do this.
This page:
https://developers.google.com/youtube/v3/guides/authentication#installed-apps
describes how to revoke an access or refresh token by using this url:
https://accounts.google.com/o/oauth2/revoke?token={token}
but then says:
The specified token can be an access token or a refresh token. If the token is an access token and it has a corresponding refresh token, the refresh token is also revoked.
So if you just want to revoke an access token you aren't able to.
I think the only solution is to wait for the access token to expire (seems to take an hour) then go about testing your app.
I'll be very happy if anyone tells me a faster way to make the token expire.
I handle this testing by simply making note of an expired access_token. Then when I need to test how my app deals with an expired token I simply give the app that expired token to work with. This way, for example, I can test that requests with an expired token will fail as expected.
The easiest way of doing it is using the OAuth Playground 2.0
https://developers.google.com/oauthplayground/
In step 2 especially, you can try refreshing your access token with a refresh token.
Additionally, in the setting (the gear icon), you can set up your own OAuth Credentials to test it out for your own API project.
Im using nodemailer. When setting the options for the transporter object, you can specify an 'expires' time. There isn't any documentation I found on that option but I'm sure you can figure it out. :)
I haven't found a way to shorten the expiration time on an access token either.
In fact you can't even generate another refresh_token unless you revoke access. I don't think you can generate another refresh_token even if you let the access token expire, although I have to wait an hour to test this.
I did find out that if you send the refresh_token and the authorization token is still active, you just get the same live token back although the expiration time is reset.