I have created node.js backend. On Login i am sending a jwt token. For user experience i don't want them to re-login but instead get their tokens refreshed, which i have set to expire in 4 hours.
However i am not getting a good lead on how to do this effectively. My idea is to provide a button in client side, by clicking on which user can get their tokens refreshed. Assuming a rest call that i can make from client side, i need help in its implementation. Appreciate it.
if (response) {
bcrypt.compare(req.body.password, response.password, (error, result) => {
if (result) {
const token = jwt.sign(
{
email: response.email,
userId: response._id
},
process.env.JWT_KEY,
{
expiresIn: '4h'
});
return res.status(200).json({
message: 'Auth Successful! User Found. ',
token
})
} else {
return res.status(404).json({
message: 'Auth Failed! User Not found'
})
}
}
You would need two tokens:
Refresh Token (will be saved in db)
Access Token (your JWT which will expire quickly e.g. 10 mins)
Refresh token typically does not expire quickly. However, there may be a challenge on how to secure the refresh token.
you also need to change the refresh token in the database every time the user refreshed their token / logs in.
You also need to store expiry_date of your access token (you can make it a response from your login api).
Then, in your front-end, you can store those tokens in localStorage / sessionStorage depending on your security requirements.
Then, each API call would check the expiry date that you've set. And if it reaches a certain threshold (e.g. 5 mins before expiry_date), you'd call the refresh token API.
This is a method that I've used. However, it may not considered as a best practice.
Related
I use a backend app server to communicate with firestore, so the ReactJS client sends ID token to server which in turn communicates with firebase using that token. Client does not make any firebase calls directly other than auth calls. Problem I am facing is, the ID token never gets refreshed and after an hour, backend server fails to recognize token and ends up sending 401 to client. My understanding is that the client should always refresh the token and always send a valid token to backend app server.
firebase.auth().onAuthStateChanged(auth, (user) => {
if (user) {
localStorage.setItem("auth.uid", user.uid)
localStorage.setItem("auth.email", user.email)
user.getIdToken(true).then(function(idToken) {
localStorage.setItem("auth.token", idToken)
})
} else {
// User is signed out
localStorage.removeItem("auth.email")
localStorage.removeItem("auth.uid")
localStorage.removeItem("auth.token")
}
})
firebase.auth().onIdTokenChanged((user) => {
// ** NOT GETTING THIS CALLBACK AFTER 1 HR TO REFRESH **
if (user) {
// User is signed in or token was refreshed
user.getIdToken(true).then(function(idToken) {
localStorage.setItem("auth.token", idToken)
})
}
})
Other option, may be, is to use the REST API to manually fetch a new ID token and use that but having passed forceRefresh value true I would expect this is handled automatically.
What am I missing?
I use JsonWebtoken to create an access token for authentication purposes in my web app in node js using express.
I want to define an expiry date for this token but I don't know how It refreshes the "iat" by performing some activities by the user! basically, I want the expiry date starts over again if the user performs some activity within the period of 30 minutes since the last activity!
jwt.sign({ _userName: userName, _name: name + ' ' + sureName, _role: role.name }, config.get('jwtPrivateKey'),);
This is how I create the token.
So the question is how can I refresh the token and send a new one in case of activity from the user within 30 minutes so that we can make sure that the user does not need to login in 30 minutes and the token is going to be valid ?! and then I want the token expires if the user does not perform any tasks for more than 30 minutes!
The standard way to refresh an access token is to create a separate token, a "refresh token" (literally). Here is a blog post to get you started, blog post.
The basic idea is to send both tokens to the client. The access token expires in X time, and the refresh token expires in a much longer amount of time. Once the client gets an error from the server (unauthenticated), it sends another request to the server asking for a new access token. It passes the refresh token when making this request. The server checks if the refresh token is valid, and if so it will return a new refresh/access token pair to the client. It's important that the refresh token can only be used to get new access tokens, and the access token is used for retrieving data from the server.
I fix it using this, so that I can generate a new one in case I need it
app.use(function (message, req, res, next) {
try {
if (typeof message === 'string') {
let userName = req.body._userName;
let name = req.body._name;
let role = req.body._role;
let token = generateToken(userName, name, role);
res.header('z-auth-token', token).status(200).send(message);
} else {
next(message);
}
} catch (e) {
next(e);
}
});
I have the following codes in the backend of my web app made with node.js:
admin.auth().verifyIdToken(req.body.token).then((user) => {
admin.auth().setCustomUserClaims(user.uid, {
identity: "ns",
approved: false,
reviewed: false
}).then(() => {
console.log(user);
})
})
Although, I am logging the user token after the custom user claims have been set. The custom user claims approved and reviewed do not appear in my token. I think the claims are set correctly, but why they are not appearing in my terminal log?
The token that you verifed contains a copy of the claims at the time the token was generated. If you update the claims, that doesn't change what was delivered inside the payload of the token. If you want to see the updated claims inside a token, the client will have to refresh the token and provide a new one to the backend for another verification.
I have a node.js app. I'm using Json Web Token for authorization. When I Login with a user who is in my database, it creates a token for the user. But I can use that token for another user and it works too again. I need to have different tokens for all users and I should not use one user's token for another user. (I dont have internet on my work pc so I cant write my codes on my computer here sorry about that)
Here is my verify-token.js (middleware):
const jwt = require("jsonwebtoken");
module.exports = (req, res, next) => {
try {
const token = req.headers.authorization.split(" ")[1];
const decodedToken = jwt.verify(token, "secret_key");
req.userData = decodedToken;
next();
} catch (error) {
return res.status(401).send({
message: "Auth failed"
});
}
};
And here is my login code (im creating the token here)
if password is true:
const token = jwt.sign(
{
email: user.email,
password: user.password
},
"secret_key",
{
expiresIn: "2h"
}
);
return res.status(200).send({ message: "success", token: token });
And in app.js:
const checkAuth = require('../middleware/checkauth');
router.get('/api/company',checkAuth,companyController.list);
I expect that one token should be for just one user, and for every login it should creates a new token for all users. Any suggestion?
You're including the email in your token body; why not also include the user ID as a claim (field)? When you verify the token, if it's successful, it will return the body to you, so then you'll know which user that token was made for and reject if it's not the one who's making the request.
To ensure two people don't use the same token at the same time, you can keep a list of every valid token when you generate it, and when a token expires or is revoked (for instance, when the user signs out or reports an imposter, if it gets that far) remove it from the list. During verification, if the token is not on the list, don't even bother decoding it, just reject it immediately.
If you give your tokens decently small expiration windows (I believe the recommendation is to make them last no longer than 1 hour), you shouldn't have to worry about such things much.
EDIT To clarify, you'll never have a way to know for sure that the person who gave you the token is who they claim to be. You only know if your server created the token and if the token is currently valid. If you really want to prevent replay attacks (that is, make absolutely sure there's no way for two people to use the same token at once), you'll need to generate a new token every time one is used. If you keep that whitelist that I mentioned above, this regeneration ensures every token becomes invalid as soon as it's used once.
You can also, to be EXTRA confident, include a jti claim in the token body; this is a field intended to be filled with a random unique value every time a token is generated, so that you can keep track of the jti's you've received and not allow the same one to come in more than once. It's about the same as just keeping track of the tokens, though.
In quickblox, the session expires two hours after the last request. So to handle this situation I have used the code
config.on.sessionExpired = function(next,retry){
})
and passed the config in QB.init
config.on.sessionExpired = function(next, retry) {
console.log("============session renewal")
var user = self.get('user')
QB.chat.disconnect()
QB.createSession({ login: user.login, password: user.pass }, function(err, res) {
if (res) {
// save session token
token = res.token;
user.id = res.user_id
self.get('user').token = token
QB.chat.connect({ userId: user.id, password: user.pass }, function(err, roster) {
// Do something
})
}
})
}
QB.init(QBApp.appId, QBApp.authKey, QBApp.authSecret, config);
Is this the right way to renew the session by first disconnecting the chat, then creating a new session first and then connecting the chat back again?
I do not want the client to know that the session has expired in quickblox and they have to refresh the page. The chat is a part of the web portal. It is fine if the quickblox takes 2-3 seconds to create a new session token and then connect to chat. By the time, I can show a loader or some message.
I had tried it without the QB.chat.disconnect() but then it did not work and sent me Unprocessable entity 422 error.
I have same problem, and i found some solution at QuickBlox Docs
https://docs.quickblox.com/docs/js-authentication#session-expiration
QuickBlox JavaScript SDK will automatically renew your current session. There is no need to manually call createSession() method. After login, a session is available for 2 hours. When the session expires, any request method will firstly renew it and then execute itself.
And this example from the official documentation:
var CONFIG = {
on: {
sessionExpired: function(handleResponse, retry) {
// call handleResponse() if you do not want to process a session expiration,
// so an error will be returned to origin request
// handleResponse();
QB.createSession(function(error, session) {
retry(session);
});
}
}
};
QB.init(3477, "ChRnwEJ3WzxH9O4", "AS546kpUQ2tfbvv", config);