Double JWT certification is a safety mechanism that increases user authentication by employing two types of JSON web tokens (JWTS): an access token and a refresh token. This approach balances users by limiting the access token lifespan by limiting safety and user experience, while users allow them to refresh them originally.
Security: Short-lived access tokens reduce the risk of token misuse if compromised.
User Experience: Long-lived refresh tokens minimize frequent logins.
Scalability: Stateless authentication enables distributed architectures.
Control: Refresh token invalidation allows session revocation without relying on access tokens.
Access Token:
Short lifespan (e.g., 15 minutes).
Used for authenticating API requests.
Typically stored in memory or secure HTTP-only cookies.
Refresh Token:
Long lifespan (e.g., 7 days or more).
Used to obtain new access tokens without requiring user credentials.
Stored securely in HTTP-only cookies or databases.
User Login:
The server validates user credentials and issues an access token and a refresh token.
Accessing Protected Routes:
The user includes the access token in API requests.
The server verifies the token and grants access.
Token Expiry Handling:
If an access token gets expires, the client uses the refresh token to request a fresh new token
The server then verifies the refresh token and issues a new access token.
Logout & Revocation:
Users log out, and refresh tokens are removed from storage.
The server can blacklist refresh tokens if needed.
Token Storage: Securely store access tokens in memory and refresh tokens in HTTP-only cookies or databases.
Blacklist Mechanism: Implement a mechanism to revoke refresh tokens if necessary.
Token Rotation: Issue new refresh tokens with each refresh request to prevent misuse.
Secure Transmission: Always use HTTPS to protect token exchanges.
Access Token Strategy
import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';
@Injectable()
export class JwtAccessStrategy extends PassportStrategy(Strategy, 'jwt') {
constructor() {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: process.env.JWT_ACCESS_SECRET,
});
}
async validate(payload: any) {
return { userId: payload.sub, email: payload.email };
}
}
Refresh Token Strategy
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';
import { Repository } from 'typeorm';
import { InjectRepository } from '@nestjs/typeorm';
import { User } from '../entities/user.entity';
import * as bcrypt from 'bcrypt';
@Injectable()
export class JwtRefreshStrategy extends PassportStrategy(Strategy, 'jwt-refresh') {
constructor(
@InjectRepository(User) private userRepository: Repository<User>
) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: process.env.JWT_REFRESH_SECRET,
passReqToCallback: true,
});
}
async validate(req, payload: any) {
const refreshToken = req.headers.authorization.split(' ')[1];
const user = await this.userRepository.findOne({ where: { id: payload.sub } });
if (!user || !(await bcrypt.compare(refreshToken, user.refreshToken))) {
throw new UnauthorizedException();
}
return user;
}
}
Ready to transform your business with our technology solutions? Contact Us today to Leverage Our NodeJS Expertise.