I'm using two JWT tokens - Refresh Token(expires after 7 days) and Access Token (expires after 15 min). They are stored on httpOnly cookies and can be accessed via server. Refresh methods signs new token and store it on a cookie. I need to check if these tokens are expired after every request like this:
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
constructor(private authService: AuthService, private cookieService: CookieService) { }
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const expirationToken = this.cookieService.get('tokenexp'); // access token expiration
const expirationTokenRefresh = this.cookieService.get('tokenrefexp'); // refresh expiration
// Refresh Token needs to be checked first
if (Number(expirationTokenRefresh) < Date.now()) {
// new refresh token is stored on cookie
this.authService.refreshTokenRefresh();
// this.authService.refreshToken().subscribe(() => { ... });
}
// next we check Access Token
if (Number(expirationToken) < Date.now()) {
// new access token is stored on cookie
this.authService.refreshToken();
// this.authService.refreshTokenRefresh().subscribe(() => { ... });
}
return next.handle(req.clone({
withCredentials: true
}));
}
}
// auth service
refreshToken() {
return this.http.get(`${BACKEND_URL}/refreshtoken`);
}
refreshTokenRefresh() {
return this.http.get(`${BACKEND_URL}/refreshtokenref`);
}
Here is Express back-end methods:
//routes
const express = require('express');
const router = express.Router();
router.get('/refreshtoken', user.refreshToken);
router.get('/refreshtokenref', user.refreshTokenRefresh);
// refresh access token method
const jwt = require('jsonwebtoken');
const moment = require('moment');
const User = require('../models/user');
exports.refreshToken = wrap(async(req, res, next) => {
const user = await User.findOne({ refresh_token: req.cookies['tokenref'] });
if (user) {
const newToken = await jwt.sign(
{ email: user.email, userId: user._id, role: user.role },
process.env.JWT_Key,
{ expiresIn: '15m' });
const expiresAt = moment().add(900, 'second');
res.cookie('tokenexp', JSON.stringify(expiresAt.valueOf()), { maxAge: 3000000000, secure: true});
res.cookie('token', newToken, { maxAge: 3000000000, secure: true, httpOnly: true });
res.status(200).json({success: true});
} else {
res.status(401).json({success: false, message: 'Sessão expirou.'});
}
});
How can I make it work using RxJS Observables? I may send one request to refresh a token, and then another request to refresh second token, and finally the original request with updated cookies. In summary, I may need to send requests before my original request.
Also there is problem: AuthInterceptor shouldn't be called after request one or two (tokens).