Keep refreshing JsonWebToken by any action form user - javascript

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);
}
});

Related

How can access google calendar of user and edit it without asking for user permisssion again and again

On my website, I am asking for google calendar access. I can edit the user calendar but, I don't want to ask for user permission, again and again, so once the user authorized and give access to google calendar, I can edit it anytime until the user revokes the access. Should I implement it on the frontend or the backend and how? I checked few answers where they mention we can use a service account but, it is not clear how can I edit or read the individual user's calendar events and how can I remove it once the user revokes access. This question was deleted because code was missing so adding code below.
I tried this so once user login I get access token and I am using it
window.gapi.load("client:auth2", () => {
window.gapi.client.setApiKey("api_key");
window.gapi.client.load("https://content.googleapis.com/discovery/v1/apis/calendar/v3/rest")
.then(() => {
window.gapi.auth.setToken({ access_token: access_token })
window.gapi.client.calendar.events.insert({
"calendarId": "id",
'resource': event
}).then((res) => {
console.log("calendar data res "+JSON.stringify(res))
}).catch(err => console.log("error getting calendar data "+JSON.stringify(err)))
}).catch(err => console.error("Error loading GAPI client for API", err) )
})
but once access token expires how can I get a new access token( I don't want to show login popup to the user again and again. I want to know how can I do it using refresh token on client-side).
You can't get a refresh token on the client-side without exposing your secret key to the public.
You can create an endpoint that accepts oAuth code and return the token, save the refresh token for later. You set up a corn job that checks for expired token and refreshes them.
Every time the user accesses your app, you grab a fresh token from the server and proceed to work normally.
As per Google guidelines. You do POST to https://oauth2.googleapis.com/token. Assuming your server-side stack is in Node.js, you do something like this using an HTTP client like Axios:
const Axios = require('axios');
const Qs = require('querystring');
const GOOGLE_CLIENT_ID = 'abc';
const GOOGLE_CLIENT_SECRET = '123';
let refreshToken = getFromDataBase(); // should be stored in database
Axios.post('https://oauth2.googleapis.com/token', Qs.stringify({
client_id: GOOGLE_CLIENT_ID,
client_secret: GOOGLE_CLIENT_SECRET,
refresh_token: refreshToken,
grant_type: 'refresh_token'
}), {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
}
})
.then(({ data }) => console.log(data.access_token)) // new token that expires in ~1 hour
.catch(console.log)
Firstly, do you (a) want to update the calendar when the user is not logged in, for example in response to an external event? ... OR ... do you (b) only want to update the calendar from within a browser session?
If (a), then you need to ask the user for offline access which will give you a Refresh Token , which you can securely store on a server and use whenever you need to. (Forget all about Service Accounts).
If (b), then you need the following pieces of information :-
When the access token expires, request access again, but add the flag prompt=none. This will give you a fresh Access Token without the user seeing any UX.
Do this in a hidden iframe so that it is happening in the background and is invisible to the user. Your iframe will therefore always have an up to date Access Token which it can share with your app via localStorage or postMessage.

Validating JWT Token in vue.js Router

I am using the following code to generate a JWT token:
jwt.sign(id, TOKEN_SECRET, { expiresIn: '24h' });
Once generated, I send the token to the client, which stores it within a cookie:
document.cookie = `session=${token}` + ';' + expires + ';path=/'
Furthermore, I am using vue.js Router for my navigation. From my understanding, if one adds the following code in the router file, one can insert middle-ware in order to protect some routes.
router.beforeEach((to, from, next) => {
if (to.meta.requiresAuth) {
let token = Vue.cookie.get('session')
if (token == null) {
next({
path: '/',
params: { nextUrl: to.fullPath }
})
}
} else {
next()
}
})
However, I am having difficulty understanding how can one verify the validity of the JWT token using this approach, which needs to be done on the server, where the TOKEN_SECRET is stored, and not on the client side.
Let me start with this: your goal in guarding routes is to prevent the user from having a bad experience by proceeding to a page that will attempt to retrieve information that they are not authorized to view.
So, you don't need to validate the token on the client side. Since a token will only be in hand if the server validated the user and returned a token, you - the author of the client code - can use the presence of the token as a means to inform what route to take the user through.
In other words, the client having a token is all the validation you need to allow the user through to protected routes.
Remember, it is not as though a protected page has private data in and of itself. A protected page will always retrieve that protected data from the server, which means that the server has the chance to authenticate the token after all.

How to authorize all users with different tokens using jwt in Node JS

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.

Best way to refresh JWT token using Node.js

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.

Google Client Refresh Token only works once

I am using the Google API Client to access the Directory API. My code is as follows:
function getClient()
{
$client = new Google_Client();
$client->setApplicationName('G Suite Directory API');
$client->setScopes(Google_Service_Directory::ADMIN_DIRECTORY_USER);
$client->setAuthConfig('credentials.json');
$client->setAccessType('offline');
$client->setApprovalPrompt('force');
// Load previously authorized token from a file, if it exists.
// The file token.json stores the user's access and refresh tokens, and is
// created automatically when the authorization flow completes for the first
// time.
$tokenPath = 'token.json';
if (file_exists($tokenPath)) {
$accessToken = json_decode(file_get_contents($tokenPath), true);
$client->setAccessToken($accessToken);
}
// If there is no previous token or it's expired.
if ($client->isAccessTokenExpired()) {
// Refresh the token if possible, else fetch a new one.
if ($client->getRefreshToken()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
} else {
.....
//this is where google creates the initial token
}
}
}
My problem revolves around this line:
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
When I initially authorise the client, I get a token.json that contains a refresh token. After an hour, the token expires and it creates a new token. This new token however does not include a refresh token. So it will only ever refresh once and then stop working after 2 hours.
Is there a setting I'm missing?
I had to add $client->setApprovalPrompt('force'); in order for the initial token to include a refresh token.
You should keep reusing the refresh token you got initially to get new access token every hour (which you'd then use in each API request). Refresh tokens generally don't expire.

Categories

Resources