I have Native Phone App (in React Native) and Express REST API with auth based on JWT. I have 7 day expiration set.
Am I supposed to refresh (generate new and throw old) token every time user 'cold' open app (for example after 2 days of inactivity)?
Or just use the old one and refresh it like 1 day before or ask for login combo again.
So my questions are: Refresh it? And if yes, when?
you have to use Refresh token and Access token, it's very simple, every Access token (your current JWT) has 7 or 3 days to expiration, and your Refresh token have not expiration time, client will send access token after expiration time and got 401 Unauthorized error, your client have request to refresh token route and get a new access token that has 7 days of expiration time. it's like to user login with another token instead Username and Password.
Access and Refresh tokens in NodeJS
Related
I see in a blog (here) about Authentication in React with JWT, this setup: access token expiry is 15 minutes , refresh token expiry is 1 month; every 10 minutes the client calls the /refreshToken endpoint, to check if refreshToken is still valid (otherwise the user is shown the login screen).
On the server, the /refreshToken endpoint correctly checks that the refreshtoken is not expired, that the user with the id in refreshtoken payload is still existing and valid (i.e.: the passed refreshToken is present in his refreshTokens array). If everything's fine, a new access token is generated, and sent back with the response.
So far so good. But, before returning the response, a new refreshToken is generated, too, and replaced to the old one into users's refreshTokens array... I think this strategy is flawed, since this way the user will never see his login to expire, even after refresh token (one month in this example) will be overdue...
I did make some tests (lowering the 1 month value to 30 minutes), and effectively the user authorization never expires... Forcing a logout of the user deleting his refreshTokens array obviously works fine, but I'd expect a logout when the refresh token expires by age.
I ask if my understanding is correct (the refreshToken endpoint on the server should not refresh the refresh token, but the access token only), or if I miss something.
UPDATE after #Ghero comment:
I see your point... But why to refresh a token if not to update it's expiry?
However, the blog's code used to renew the refresh token:
const jwt = require("jsonwebtoken");
exports.getRefreshToken = (user) => {
const refreshToken = jwt.sign(user, process.env.REFRESH_TOKEN_SECRET, {
expiresIn: eval(process.env.REFRESH_TOKEN_EXPIRY),
});
return refreshToken;
};
// REFRESH_TOKEN_EXPIRY is set to 30 days
It looks like it is always postponing the expiry date 30 days in the future. This way it will never expire...
Having the refresh token being replaced on each use is a current best practice.
Having a one-time use refresh token means that if the refresh token is stolen and used more than once (by you and the hacker), the token service can then detect that and sign-out the user automatically, protecting the user from attacks.
There is a max time that the refresh token is valid, for example 30 days, but that is also often something that you can configure. There are different refresh token lifetime strategies, depending on the service that you use. The picture below shows how IdentityServer deals with refresh tokens:
I have a login page that authenticates users using
signInWithEmailAndPassword() using Javascript client SDK.
If a login is successful, user is redirected (along with the idToken) to the member page.
On the server side (nodejs using firebase admin SDK), the member page checks the validity of idToken and if valid, it gets the user-specific data from Firebase and displays it on the webpage. On the member page, there is lots of data to see/edit/delete etc. So it's not inconceivable that a user might spend more than an hour in this page.
My problem is, I couldn't find a way to detect if the idToken has expired. Ideally I would like to refresh and get a new idToken. Is that possible? If that is not possible, I would like to redirect the user to login page when idToken expires.
But I am not able to figure out how to achieve either one. Looks like onAuthStateChanged and onIdTokenChanged are not triggered when idToken expires. And I am not able to do a forceRefresh of idToken like, firebase.auth().currentUser.getIdToken(true). Because on member page, firebase.auth().currentUser returns null.
Any suggestion on how to handle this scenario?
Thanks.
Using the Firebase Node.js Admin SDK, you can check for a revoked or expired ID token when calling verifyIdToken() by setting the checkRevoked parameter to true.
verifyIdToken(idToken: string, checkRevoked?: boolean): Promise<DecodedIdToken>
checkedRevoked: boolean
Whether to check if the ID token was revoked. This requires an extra request to the Firebase Auth backend to check the tokensValidAfterTime time for the corresponding user. When not specified, this additional check is not applied.
admin.auth().verifyIdToken(idToken, true)
.then(function(decodedToken) {
let uid = decodedToken.uid;
// ...
}).catch(function(error) {
// Handle error for expired ID token
});
Alternatively, the ID token payload claims may be checked on the client. The documentation for how to Verify ID tokens using a third-party JWT library show the payload claims.
exp expiration time: Must be in the future. The time is measured in seconds since the UNIX epoch.
jwt.io references libraries that support client-side token verification.
Also see: How to decode the JWT encoded token payload on client-side in angular 5?
hello everyone ive been working on making a website for a change and when I log into my website with google, I'm also using drive rest api, I get the token
function onSignIn(googleUser) {
var id_token = googleUser.getAuthResponse().id_token;
...
}
but when I stored this token in my database and tried to query the token with a new instance of a token they didn't match, so I'm wondering what this token is for if it isn't a token to tell me that the user is the same as a past user with the same login, thank you for your time
The token is encrypted and you are expected to receive different one every time you request. You can decrypt it using a library of your favorite programming language, verify it then use sub parameter as a user id.
Check out details in this doc.
So I embed a website to have a instagram feed using this website: http://instafeedjs.com/
I got it working and it was up for a week or so and it randomly broke one day with an error "Invalid access Token".
I got a new token and it works again but I'm curious as to why my original Token needed a refresh? They aren't supposed to expire from what I hear. Anyone have any thoughts on this, so I can find out why it broke?
Instagram doesn't provide an expiration time for their tokens, which can expire at any time.
The following text is from Instagram's Developer Authentication page:
Access tokens may expire at any time in the future. [...]
Even though the access token does not specify an expiration time, your app should handle the case that either the user revokes access, or Instagram expires the token after some period of time. In this case, your meta of your responses will contain an “error_type=OAuthAccessTokenError”. In other words: do not assume your access_token is valid forever.
I am using Thinktecture AuthorizationServer (AS) and it is working great.
I would like to write a native javascript single page app which can call a WebAPI directly, however implicit flow does not provide a refresh token.
If an AJAX call is made, if the token has expired the API will send a redirect to the login page, since the data is using dynamic popups it will this will interrupt the user.
How does Facebook or Stackoverflow do this and still allow the javascript running on the page to call the APIs?
Proposed Solution
Does the below scenario sound sensible (assuming this can be done with iframes):
My SPA directs me to the AS and I obtain a token by Implicit Flow. Within AS I click allow Read data scope, and click Remember decision, then Allow button.
Since I have clicked Remember decision button, whenever I hit AS for a token, a new token is passed back automatically without me needing to sign in ( I can see FedAuth cookie which is remembering my decision and believe this is enabling this to just work).
With my SPA (untrusted app), I don't have a refresh-token only an access token. So instead I:
Ensure user has logged in and clicked remember decision (otherwise iframe wont work)
Call WebAPI, if 401 response try and get a new token by the below steps...
Have a hidden iframe on the page, which I will set the URL to get a new access-token from the Authorisation Server.
Get the new token from the iframe's hash-fragment, then store this in the SPA and use for all future WebAPI requests.
I guess I would still be in trouble if the FedAuth cookie is stolen.
Any standard or recommended way for the above scenario?
I understand that your problem is that the user will experience an interruption when the access token has expired, by a redirection to the login page of the authorization server. But I don't think you can and should get around this, at least, when using the implicit grant.
As I'm sure you already know, the implicit grant should be used by consumers that can NOT keep their credentials secret. Because of this, the access token that is issued by an authorization server should have a limited ttl. For instance google invalidates their access token in 3600 sec. Of course you can increase the ttl, but it should never become a long lived token.
Also something to note is that in my opinion the user interruption is very minimal, i.e if implemented correctly, the user will only have to authenticate once with the authorization server. After doing that (for example the first time when also authorizing the application access to whatever resources the user controls) a session will be established (either cookie- or token based) and when the access token of the consumer (web app using implicit grant) expires, the user will be notified that the token has expired and re authentication with the authorization server is required. But because a session already has been established, the user will be immediately redirected back to the web app.
If however this is not what you want, you should, in my opinion, consider using the authorization code grant, instead of doing complicated stuff with iframes.
In that case you need a server side web application because then you can keep your credentials secret and use refresh tokens.
Sounds like you need to queue requests in the event that an access token expires. This is more or less how Facebook and Google do it. A simple way using Angular would be to add a HTTP Interceptor and check for HTTP401 responses. If one is returned, you re-authenticate and queue any requests that come in after until the authentication request has completed (i.e. a promise). Once that's done, you can then process the outstanding queue with the newly returned access token from your authentication request using your refresh token.
Happy Coding.
Not sure if I understand your question but,
I would like to write a native javascript single page app which can call a WebAPI directly, however implicit flow does not provide a refresh token.
Summarize facts,
refresh token is sometimes used to be a part of A: Authorization Grant
https://www.rfc-editor.org/rfc/rfc6749#section-1.5
and as you said in implicit flow you dont get back refresh token, but only in Authorization Grant part
https://www.rfc-editor.org/rfc/rfc6749#section-4.2.2
so you can get back refresh token when issuing access token (refresh tokens are always optional)
https://www.rfc-editor.org/rfc/rfc6749#section-5.1
With my SPA (untrusted app), I don't have a refresh-token only an
access token. So instead I:
Ensure user has logged in and clicked remember decision (otherwise
iframe wont work)
Call WebAPI, if 401 response try and get a new
token by the below steps...
Have a hidden iframe on the page, which
I will set the URL to get a new access-token from the Authorisation
Server.
Get the new token from the iframe's hash-fragment, then
store this in the SPA and use for all future WebAPI requests.
SPA(you) have no idea if user selected remember decision. Its in AS direction and should be complete blackbox. Skip this step.
You can try to use access token and wait for result, always.
If access token has expired and you dont have refresh token, you still can create hidden iframe and and try to get new access token.
Lets assume your AS provide option to remember decision and wont change it in future, then: your iframe will get new access token without user interaction, then you will get result back in some unknown time limit.
Result can be checked by setInterval for read specific cookie or iframe postmessage.
If you dont get back data in time limit, then one from following scenarios occured:
lag, AS is slow, connection is slow or time limit is too tight
user didnt select remember decision
In this case:
show iframe with login
I consider scenario above as good practise if AS doesnt provide refresh tokens, but I also guess every AS like that wont provide remember option as well.
StackOverflow <---> Google scenario (I can only guess)
User login, authorization request occured
User logs in, SO gets access token
SO tries to use access token
SO gets back result + refresh token
SO saves refresh token
SO has permanent access to users Google account
In Google o-Auth , the access token will only be valid for 1 hour, so you need to programmatically update your access token in each one hour, simple you can create web api to do so,you need to have a refresh token, and also that refresh token will not be expired , using c# code, I have done this.
if (dateTimeDiff > 55)
{
var request = (HttpWebRequest)WebRequest.Create("https://www.googleapis.com/oauth2/v3/token");
var postData = "refresh_token=your refresh token";
postData += "&client_id=your client id";
postData += "&client_secret=your client secrent";
postData += "&grant_type=refresh_token";
var data = Encoding.ASCII.GetBytes(postData);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = data.Length;
request.UseDefaultCredentials = true;
using (var stream = request.GetRequestStream())
{
stream.Write(data, 0, data.Length);
}
var response = (HttpWebResponse)request.GetResponse();
string responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
}
you need to save the last updated date time of the access token somewhere(say in database), so that , whenever you have to make a request , so you can subtract that with current date time , if it is more than 60 minutes , you need to call the webapi to get new token .