I'm using Node.js and Express to deal with JWT Auth. First of all, every time a user is created and verified, I'm storing a refresh token
inside User
collection:
const refreshToken = await jwt.sign({ userId: decoded.user }, process.env.JWT_Refresh_Key);
const user = await User.updateOne({ _id: mongoose.Types.ObjectId(decoded.user) }, { refresh_token: refreshToken, status: true });
A JWT Access Token is generated after a successful Login (expires after 15min):
const token = await jwt.sign(
{ email: user.email, userId: user._id, role: user.role },
process.env.JWT_Key,
{ expiresIn: '15m' });
res.status(200).json({success: true, token: token});
Then access token
is stored in localStorage
to be handled by Angular Http Interceptor and auth methods. After 15min, the token
will be invalid for handling requests, so I need to use the refresh token
stored on the database.
Refresh method is being called on AuthService.ts
:
export class AuthService {
constructor(private http: HttpClient){}
refreshToken(token: string) {
this.http.post<{token: string, expiresIn: number, name: string}>(`${BACKEND_URL}/refreshtoken`, {token: token})
.subscribe((data) => {
const expiresAt = moment().add(data.expiresIn, 'second');
localStorage.setItem('token', data.token);
localStorage.setItem('expiration', JSON.stringify(expiresAt.valueOf()));
});
}
}
//route
router.post('/refreshtoken', user.refreshToken);
//controller user.js
exports.refreshToken = async(req, res, next) => {
// I need to store and call 'old_refreshtoken' where??
const user = await User.findOne({ refresh_token: old_refreshtoken });
if (user) {
const newToken = await jwt.sign(
{ email: user.email, userId: user._id, role: user.role },
process.env.JWT_Key,
{ expiresIn: '15m' });
res.status(200).json({success: true, token: newToken, expiresIn: 900, name: user.name});
} else {
res.status(401).json({success: false, message: 'Autenticação falhou.'});
}
};
How can I use my refresh token
(database) to generate a new access token
?
I'm not sure how to store a refresh token
on client-side (Angular) to compare to refresh token
stored on the database.
I'm assuming that you have your own back-end to handle the refresh token process. Please tell me if this is not the case
What I did to this process is to move all decoding and encoding to the back-end. But you have to make sure that you store the latest active refresh token in the back-end. Otherwise, someone could reuse old token to create access token.
back-end
and send both access-token
and refresh-token
to itaccess-token
and get your necessary data. Ignore expiry date in this decode function.refresh-token
with the latest refresh-token
in the db. If it doesn't match, the user is not authorized. Otherwise, continue.access-token
content to a new token. Otherwise, do your query and rebuild the access-token
.Hope this helps
Firstly, the user controller where you have a refresh token method doesn't need the next parameter, because you aren't utilizing it. The next
parameter work closely like a promise, It shines when it comes to middleware handler.
The middleware flow should be separated from the controller, depends on your application folder structure.
You can create a refresh token end-point same way you did before a successful login.
refreshToken = (payload, secret) => {
const token = jwt.sign(payload, secret, {
expiresIn: '15m',
});
return token
}
then validate the token by using jwt verify method jwt.verify(token, secret, handler)
.
exports.refreshToken = (req, res, next) => {
const token = req.headers['x-access-token'] || req.headers.token;
/* if token was not provided */
if (!token) {
return res.status(403).send({
success: false,
message: 'Not Authorized',
});
}
/* verify token*/
jwt.verify(token, secret, (error, decoded) => {
if (error) {
return res.status(401).send({
success: false,
message: 'Invalid token',
});
}
req.decoded = decoded;
next();
});
}
In the front-end store the expiry date (token). Then, every time you make a request to the back-end, check if the token is still valid(expired) by using the jwt verify method. If it's expired, fire the refresh-token method.
req.decoded
.localStorage.setItem(userToken, token)
and get token by localStorage.getItem(userToken)
.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With