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.
Contact Us