how to refresh token when expired in jwt - angularjs

I am implementing JWT in my project. I implemented jwt and gave it an expiration time of 1 minute. The jwt that is generated from the api side is during login and the token and expiration details are sent in the result and are stored in local storage. How can I refresh the expired token from API side and send it back again to the client so that it can be stored in local storage and sent for every call using interceptor?
this is how I created jwt and gave expiration time
// let us suppose this is my input
tokenObject = { User: { username: name, pwd: pwd } };
//creating a jwt here
jwt.sign({ tokenObject }, "secretkey", { expiresIn: "60s" }, (err, token) => {
res.json({
token
});
});
After this, I'm verifying the token in the result and sending it in result to the client.
After a minute how do I regenerate the token?
Please help and let me know the way and tell me if I am doing something wrong . Thanks!!

You need to add a function or middleware that will check that the JWT is valid or not. You can use the verify method of JWT library:
jwt.verify(token, 'secretKey', function (err, decoded) {
if (err) {
if (err.name === 'TokenExpiredError') {
//create a new token and send the same way you created initially
}
}
});

You can create an API that accepts a JWT token, validates it and then issues a new token for the same user.
Take a look at the verify method of jsonwebtoken.
While verifying the token you can use ignoreExpiration: true option to verify the expired token as well. Then then generate the new one using sign method.
So while making the request from the frontend, if you get a token expired error, then you issue a new token using that API and save that token.
With that said, I do recommend you to take a look at the note about refreshing the JWT token from the docs:
First of all, we recommend to think carefully if auto-refreshing a JWT
will not introduce any vulnerability in your system.
We are not comfortable including this as part of the library, however,
you can take a look to this example to show how this could be
accomplished. Apart from that example there are an issue and a pull
request to get more knowledge about this topic.
Here is the link of the gist that has the code.

Related

How to validate AzureAD accessToken in the backend API

I just wanted to know how can we validate the azure ad access token in a backend API in my case i.e. Django rest framework.
Consider that I have a single page app or a native app and a backend API (django rest framework) completely independen of each other. In my case if my single page app/native app wants to access certain data from the backend API, and inorder to access the API, user should be logged in the backend API.
So what my approch is to make use of MSAL library to get the access token from the SPA/native app and then once token is acquired, pass that token to backend API, validate it, get the user info from graph api. If user exists in the DB then login the user and pass the required info. If user info doesn't exist then create the user, login and pass the info from the API.
So my question is when I pass the access token to my backend api, how can I validate that the token that a user/SPA/native app has passed to backend API is valid token or not?
Is it just we need to make an API call to graph API endpoint with accessToken that user/SPA/native passed and if it is able to get the user data with the accessToken then then token is valid or if it fails then the accessToken is invalid.
Is it the general way to validate the token or some better approach is there? Please help
Good day sir, I wanna share some of my ideas here and I know it's not a solution but it's too long for a comment.
I created a SPA before which used msal.js to make users sign in and generate access token to call graph api, you must know here that when you generate the access token you need to set the scope of the target api, for example, you wanna call 'graph.microsoft.com/v1.0/me', you need a token with the scope 'User.Read, User.ReadWrite' and you also need to add delegated api permission to the azure app.
So as the custom api of your own backend program. I created a springboot api which will return 'hello world' if I call 'localhost:8080/hello', if I wanna my api protected by azure ad, I need to add a filter to validate all the request if has a valid access token. So I need to find a jwt library to decode the token in request head and check if it has a token, if the token has expired and whether the token has the correct scope. So here, which scope is the correct scope? It's decided by the api you exposed in azure ad. You can set the scope named like 'AA_Custom_Impression', and then you can add this delegate api permission to the client azure ad app, then you that app to generate an access token with the scope of 'AA_Custom_Impression'. After appending the Bearer token in calling request, it will be filtered by backend code.
I don't know about python, so I can just recommend you this sample, you may try it, it's provided by microsoft.
I've solved the similar issue. I don't found how to directly validate access token, but you can just call graph API on backend with token you've got on client side with MSAL.
Node.js example:
class Microsoft {
get baseUrl() {
return 'https://graph.microsoft.com/v1.0'
}
async getUserProfile(accessToken) {
const response = await got(`${this.baseUrl}/me`, {
headers: {
'x-li-format': 'json',
Authorization: `Bearer ${accessToken}`,
},
json: true,
})
return response.body
}
// `acessToken` - passed from client
async authorize(accessToken) {
try {
const userProfile = await this.getUserProfile(accessToken)
const email = userProfile.userPrincipalName
// Note: not every MS account has email, so additional validation may be required
const user = await db.users.findOne({ email })
if (user) {
// login logic
} else {
// create user logic
}
} catch (error) {
// If request to graph API fails we know that token wrong or not enough permissions. `error` object may be additionally parsed to get relevant error message. See https://learn.microsoft.com/en-us/graph/errors
throw new Error('401 (Unauthorized)')
}
}
}
Yes we can validate the Azure AD Bearer token.
You can fellow up below link,
https://github.com/odwyersoftware/azure-ad-verify-token
https://pypi.org/project/azure-ad-verify-token/
We can use this for both Django and flask.
You can directly install using pip
but I'm not sure in Django. If Django install working failed then try to copy paste the code from GitHub
Validation steps this library makes:
1. Accepts an Azure AD B2C JWT.
Bearer token
2. Extracts `kid` from unverified headers.
kid from **Bearer token**
3. Finds `kid` within Azure JWKS.
KID from list of kid from this link `https://login.microsoftonline.com/{tenantid}/discovery/v2.0/keys`
4. Obtains RSA key from JWK.
5. Calls `jwt.decode` with necessary parameters, which inturn validates:
- Signature
- Expiration
- Audience
- Issuer
- Key
- Algorithm

Misunderstanding the process of JWT authentication

I create project using React + Redux + Apollo Client + Graphql
When we need to log in in our app we need to use token (saved in localStorage for example) which is put in the headers parameter like in the code below:
const client = new ApolloClient ({
uri: 'http://localhost:4000/api',
headers: {
authorization: `Bearer ${localStorage.token}`,
},
});
After request server verifies token and becomes aware who is the user.
My question: from where do we need to get token and put it to the headers parameter for log on (sign up) process? A new customer comes to our log on page, he has no token (in localStorage or somewhere else) at the beginning but server requires it in the requests. And if we remove headers parameter from our client, the log on process will proceed but server won't understand who is the current user.
Typically the server would be the one issuing the JWT token, and this would happen during user login or maybe during account creation. For these particular calls, you should not be expecting the JWT in the header. Instead, the user would be passing credentials, such as username and password. For most other calls, it is appropriate to pass the JWT in the header of the request.
Keep in mind that the main purpose of the JWT is free the user from having to provide personal credentials during most requests. Instead, the user can just present a JWT, much as one would present a passport, to get access to your web services.
In response to your comments below, I would suggest that you keep the signup/registration process separate from the user-only area of your application. Here is a typical workflow:
Prospective user visits your site, and creates an account, by choosing a username and password, and possibly by providing certain other personal information
Your application creates an account, and then sends an email verification link to the user's email address. The server lands the user on a page which mentions all of this
The user opens the email, which contains a verification link, which when clicked will activate the account. Your application returns a web page which then asks the user to login.
Finally, the user logs in from the normal login page.
Note carefully here, that JWT were not at all involved in the signup process, nor do they need to be. The user JWT only needs to come into existence after the user actually logs in for the first time.
Decision:
you need to check for token in localStorage and update the request if token exists
const client = new ApolloClient({
uri: 'http://localhost:4000/api',
request (operation) {
const headers = {};
const token = localStorage.getItem('token');
if (token) headers.authorization = 'Bearer ' + token;
operation.setContext({ headers });
}
})

JWT destroy token on logout

I'm developing a MEAN App, the problem that I have is that I want to destroy the token generated by JWT. Initially I thought that the logout function would the job:
router.get('/logout', function(req, res) {
req.logOut();
res.status(200).json({
status: 'Bye!'
});
});
But now I realized that "req.logOut()" is just a passport function that doesn't do anything to the token.
I send the token from client in the header of the request, so in case the user saved the token somewhere else, when logout, the user can still have access to the app if the token is included in the request. So my questions are the following, how do I destroy the token ?, is it "stored" somewhere ? is it ever auto-destroyed ?
I did not find any method to destroy simple JWT token. But I have a suggestion to solve your issue.
You can keep the token in DB for each session. So you can validate the client request by comparing 'token from DB' with the token in 'client request header'. While logout you can remove the token form DB. So user can't access the app after logout.

How to store a JWT token inside an HTTP only cookie?

I have created an app that simply uses a JWT sent by the server upon correct login credentials, and authorizes against any /api route on my backend Express.js server.
AngularJS, on the other hand, took this token, stored it in session storage, and used an auth interceptor every go around to send the token back to the server.
I've more recently come to understand how dangerous this practice is.
I understand the transfer method of tokens back and forth, in this scenario. However, would someone be so kind as to explain, at a high level, the method that takes place when you want to store that JWT inside a secure, HTTP only cookie that the client side Javascript cannot read?
For example: upon credential success
cookie is created on server,
create a JWT at the same time as the cookie
store the JWT in a cookie property called token etc..
I'm trying to gain a mental model here of how it works. If my understanding is correct, doing it this way wouldn't require an auth interceptor anymore because upon correct credential login, the server would do all of the transferring of the token inside the cookie.
Dealing with cookies has their fair share of subtleties, but at a high level a cookie is a piece of data that your web server can set, that will be then stored by the user's web browser and sent back to the server on any future requests that browser makes to the same server as long as the cookie is valid and applicable to the request being made.
(this is why you'll no longer need to use the Angular interceptors, because it's the browser itself that ensures the cookie is sent)
Besides some specials flag options, like the HTTP only, at a higher level you can set cookies to be associated with a given domain and path. For example, your server could set a cookie in such way that it would only be later sent by the browser to requests made under the /api path.
To sum it up, cookies are a state management mechanism for HTTP, see the associated RFC 2617 for more details.
In contrast, a JWT is just some data that has a well-know representation and follows some conventions. More specifically, a JWT is composed of a header, payload and signature sections and is generally advised to keep the size of the payload small for most of the JWT use cases. See Get Started with JSON Web Tokens for more details.
If you go through the previous article you'll notice that the final representation of a JWT is three Base64url encoded strings separated by dots. This is specially of interest because it means a JWT is well-suited to be used within HTTP, including as the value of a cookie.
One thing to have in mind is that by the specification you are only guaranteed that a browser will support a cookie up to 4096 bytes per cookie (as measured by the sum of the length of the cookie's name, value, and attributes). Unless you're storing way to much data in the token you should not have an issue, but it's always something to consider. Yes, you can also break a JWT token into multiple cookies, but things start to get more complex.
Additionally, cookies have their notion of expiration, so have that in mind also because the JWT itself, when used within the scope of authentication will also have thei own notion of expiration.
Finally, I just want to address some of your concerns about storing the JWT in localStorage/sessionStorage. You're correct that if you do it you have to understand its implication, for example, any Javascript code within the domain for which the storage is associated will be able to read the token. However, HTTP only cookies are also not a silver-bullet. I would give the following article a read: Cookies vs Tokens: The Definitive Guide.
It focuses on the differences between the traditional session identifier cookies vs the token-based (JWT) authentication systems, the section named Where to Store Tokens? warrants a read as it tackles the security related aspects of storage.
A summary for the TL:DR folks:
Two of the most common attack vectors facing websites are Cross Site
Scripting (XSS) and Cross Site Request Forgery (XSRF or CSRF). Cross Site Scripting) attacks occur when an outside entity is able to execute code within your website or app. (...)
If an attacker can execute code on your domain, your JWT tokens (in local storage) are vulnerable. (...)
Cross Site Request Forgery attacks are not an issue if you are using JWT with local storage. On the other hand, if your use case requires you to store the JWT in a cookie, you will need to protect against XSRF.
(emphasis is mine)
Basically, I save access_token(jwt) in a refresh token object stored in the database when the user logs in. see an example of the saved object below;
const newToken = new RefreshToken({
issuedUtc: moment().unix(), /* Current unix date & time */
expiresUtc: moment().add(4, "days").unix(), /* Current unix date&time + 4 days */
token: refreshToken, /* Generate random token */
user: data.id, /* user id */
/* Signing the access Token */
access_token: jwt.sign(
{ sub: data.id, user: userWithoutHash },
Config.secret,
{
issuer: "http://localhost:3000",
expiresIn: "30m", // Expires in 30 minutes
}
),
});
The generated and saved rand token is then sent as httpOnly cookie to the browser;
res.cookie("refreshToken", newToken.token, {
httpOnly: true,
sameSite: "strict",
});
Since the browser sends the cookie for every request all that is left is to use middleware on protected routes, retrieve the token from the cookie, verify if it is exists by looking for it in the database, check if it has not expired, try to verify the access token saved in the database for that refresh token, if it is expired then sign new jwt and update the refresh token in the database then allow the user to proceed to protected route, if it is valid simply allow the user to proceed to protected route. If the refresh token has expired, redirect the user to the login page, and lastly if no refresh token is received also redirect the user to the login page.
var cookie = await getcookie(req); // get the cookie as js object using my custom helper function
/* Check if refresh token was received */
if (cookie.refreshToken) {
/* Check find the refresh token object in the database */
var refreshToken = await RefreshToken.findOne({
token: cookie.refreshToken,
});
/* Check if the refresh token is still valid using expiry date */
if (moment.unix(refreshToken.expiresIn) > moment.now()) {
/* If the condition is fulfilled try to verify the access token using jwt */
jwt.verify(refreshToken.access_token, Config.secret, async (err, result) => {
/* in callback check for error */
if (err) {
/* If error this means the access_token is expired, so find and update the user's refresh token with a newly signed access token */
await RefreshToken.findByIdAndUpdate(refreshToken.id, {
access_token: jwt.sign(
{ sub: result.id, user: result.user },
Config.secret,
{
issuer: "http://localhost:3000",
expiresIn: "30m", // Expires in 30 minutes
}
),
});
/* Proceed to save the user in a local variable then call next */
res.locals.user = result.user;
return next();
}
/* If no error proceed by saving the user in a local variable then call next */
res.locals.user = result.user;
return next();
});
} else {
/* If the refresh token is expired, then redirect to log in */
return res.status(401).redirect('/login');
}
} else {
/* If no refresh token is provided, then redirect to log in */
return res.status(401).redirect('/login');
}
This is something I came up with myself so I can't say it is full proof but since httpOnly cookie cannot be accessed in the DOM, running malicious script in the DOM can't access the refresh token, and even if the refresh token somehow falls in the hand of bad guys then it will be useless because it does not hold any information at all until it gets to the server. So as long the right cors header is set on the server it is highly unlikely that any information can be leaked using the refresh token.

Using OAuth2 refresh token in React Redux app

I have an app that has OAuth2 implemented. It works fine, but I'm confused with refresh_tokens here. My app is using React + Redux combination.
I know I need to check if my access_token expired and then ask for new one using refresh_token. Okay... But when should I refresh it? After the 401 happened or in time when some API request that needs authorization is ready (just before send)?
I also know how to use HTTP interceptors to get all API requests before send or detect the 401 responses.
The problem is I'm confused how to solve the problem in Redux flow. How to "freeze" a request for the time the token is being refreshed? Or how to repeat the request when I solve the problem on 401 response?
When first authenticating with server successfully, we will have {access_token, expires_in, refresh_token}. We will store access_token and expires_in in session storage and refresh_token in local storage.
Whenever getting access_token for fetching data (you should enhance/wrap the fetch with filling access_token), you'll check if the expires_in is due soon (less than 1 minute, or what you feel comfortable), then we use the refresh_token to request new access_token. And of course, we have to update new result to the storage as well.
Pseudo code:
function getToken() {
const expiresIn = storage.getItem(KEY_EXPIRES_IN);
const accessToken = storage.getItem(KEY_ACCESS_TOKEN);
if (accessToken
&& (!expiresIn || moment.unix(Number(expiresIn)).diff(moment(), 'minute') > 1)) {
return accessToken;
}
return refreshToken();
}
Above function will be called every time you make a request to server.
P/S: you may want to make it as promise to use with isomorphic-fetch

Resources