A JWT authentication package providing both Access Token and Refresh Token mechanisms, featuring fingerprint recognition, Redis storage, and automatic refresh functionality.
version Golang can get here
- Access Token (short-term) + Refresh Token (long-term)
- Automatic token refresh without requiring re-login
- ES256 algorithm (Elliptic Curve Digital Signature)
- Generates unique fingerprints based on User-Agent, Device ID, OS, and Browser
- Prevents token misuse across different devices
- Automatic device type detection (Desktop, Mobile, Tablet)
- Adds Access Token to blacklist upon logout
- Redis TTL automatically cleans expired revocation records
- Prevents reuse of logged-out tokens
- Refresh Token version tracking
- Auto-generates new Refresh ID after 5 refresh attempts
- Prevents replay attacks
- Auto-regenerates when Refresh Token has less than half lifetime remaining
- 5-second grace period for old tokens to reduce concurrency issues
- Minimizes database queries
- Automatic cookie reading
- Authorization Bearer Header
- Custom Headers (X-Device-ID, X-Refresh-ID)
- Supports file paths or direct key content
- Customizable Cookie names
- Production/Development environment auto-switching
npm install @pardnchiu/jwt-auth
import{JWTAuth}from'@pardnchiu/jwt-auth';// initialize the JWT instanceawaitJWTAuth.init({privateKeyPath: "./keys/private.pem",publicKeyPath: "./keys/public.pem",// or paste keys directly:// privateKey: "-----BEGIN EC PRIVATE KEY-----...",// publicKey: "-----BEGIN PUBLIC KEY-----...",accessTokenExpires: 900,// secondsrefreshTokenExpires: 604800,// seconds// true: domain=domain, samesite=none, secure=true// false: domain=localhost, samesite=lax, secure=falseisProd: false,domain: "pardn.io",// cookie key, default access_token/refresh_idAccessTokenCookieKey: "access_token",RefreshTokenCookieKey: "refresh_id",// store with redisredis: {host: "localhost",port: 6379,password: "",// optionaldb: 0// optional},checkUserExists: async(userId: string): Promise<boolean>=>{// return true if user exists, false otherwisereturntrue;}});process.on("SIGINT",async()=>{awaitJWTAuth.close();process.exit(0);});
import{Request,Response}from'express';import{JWTAuth}from'@pardnchiu/jwt-auth';asyncfunctionloginHandler(req: Request,res: Response){// after verifying user login info...constuserData={id: "user123",name: "",email: "john@example.com",thumbnail: "avatar.jpg",role: "user",level: 1,scope: ["read","write"]};try{consttokenResult=awaitJWTAuth.CreateJWT(req,res,userData);// automatically set in cookiesres.json({success: true,token: tokenResult.token,refresh_id: tokenResult.refresh_id});}catch(error){res.status(500).json({error: error.message});}}
import{Request,Response}from'express';import{JWTAuth}from'@pardnchiu/jwt-auth';asyncfunctionprotectedHandler(req: Request,res: Response){try{constresult=awaitJWTAuth.VerifyJWT(req,res);if(!result.isAuth){// Authentication failedreturnres.status(result).json({error: result.isError ? "Bad Request" : "Unauthorized"});}// Authentication success, user result.data to get user datares.json({message: "Protected resource accessed",user: result.data});}catch(error){res.status(500).json({error: error.message});}}
import{Request,Response}from"express";import{JWTAuth}from"@pardnchiu/jwt-auth";asyncfunctionlogoutHandler(req: Request,res: Response){try{awaitJWTAuth.RevokeJWT(req,res);res.json({message: "Successfully logged out"});}catch(error){res.status(500).json({error: error.message});}}
privateKeyPath/privateKey: private key file path or contentpublicKeyPath/publicKey: public key file path or contentaccessTokenExpires: access token expire timerefreshTokenExpires: refresh id expire timeisProd: is production or not (affects cookie setting)domain: cookie domainredis: redis connectionhost: redis hostport: redis portpassword: redis password (optional)db: redis db (optional)
checkUserExists: user existence check functionAccessTokenCookieKey: access token cookie name (default: 'access_token')RefreshTokenCookieKey: refresh id cookie name (default: 'refresh_id')
- Cookie: Automatically reads token from cookie
- Authorization Header:
Authorization: Bearer <token> - Custom Headers:
X-Device-ID: Device IDX-Refresh-ID: Custom Refresh ID
The system automatically generates a new Refresh ID in the following cases:
- Refresh version exceeds 5 times
- Remaining Refresh Token time is less than half
The new tokens are returned via:
- HTTP Header:
X-New-Access-Token - HTTP Header:
X-New-Refresh-ID - Cookie auto-update
- Fingerprint recognition: Generates a unique fingerprint based on User-Agent, Device-ID, OS, Browser, and Device type
- Token revocation: Adds token to a blacklist on logout
- Automatic expiration: Supports TTL to automatically clean up expired tokens
- Version control: Tracks Refresh Token versions to prevent replay attacks
- Fingerprint validation: Ensures tokens are used from the same device/browser
The VerifyJWT method returns:
AuthDataobject on successful authentication- HTTP status code number on failure:
401: Unauthorized (invalid/expired tokens, user doesn't exist)400: Bad Request (invalid fingerprint, malformed tokens)
Common error scenarios:
- Token revoked
- Fingerprint mismatch
- Refresh data not found
- JWT expired or invalid
- User not found
This source code project is licensed under the MIT license.
©️ 2025 邱敬幃 Pardn Chiu