JWT Auth (Node.js)
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

Feature
-
Dual Token System
- Access Token (short-term) + Refresh Token (long-term)
- Automatic token refresh without requiring re-login
- ES256 algorithm (Elliptic Curve Digital Signature)
-
Device Fingerprinting
- 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)
-
Token Revocation
- Adds Access Token to blacklist upon logout
- Redis TTL automatically cleans expired revocation records
- Prevents reuse of logged-out tokens
-
Version Control Protection
- Refresh Token version tracking
- Auto-generates new Refresh ID after 5 refresh attempts
- Prevents replay attacks
-
Smart Refresh Strategy
- 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
-
Multiple Authentication Methods
- Automatic cookie reading
- Authorization Bearer Header
- Custom Headers (X-Device-ID, X-Refresh-ID)
-
Flexible Configuration
- Supports file paths or direct key content
- Customizable Cookie names
- Production/Development environment auto-switching
How to use
-
Installation
npm install @pardnchiu/jwt-auth
-
Initialize
import { JWTAuth } from '@pardnchiu/jwt-auth';
await JWTAuth.init({
privateKeyPath: "./keys/private.pem",
publicKeyPath: "./keys/public.pem",
accessTokenExpires: 900,
refreshTokenExpires: 604800,
isProd: false,
domain: "pardn.io",
AccessTokenCookieKey: "access_token",
RefreshTokenCookieKey: "refresh_id",
redis: {
host: "localhost",
port: 6379,
password: "",
db: 0
},
checkUserExists: async (userId: string): Promise<boolean> => {
return true;
}
});
process.on("SIGINT", async () => {
await JWTAuth.close();
process.exit(0);
});
-
CreateJWT
import { Request, Response } from 'express';
import { JWTAuth } from '@pardnchiu/jwt-auth';
async function loginHandler(req: Request, res: Response) {
const userData = {
id: "user123",
name: "",
email: "john@example.com",
thumbnail: "avatar.jpg",
role: "user",
level: 1,
scope: ["read", "write"]
};
try {
const tokenResult = await JWTAuth.CreateJWT(req, res, userData);
res.json({
success: true,
token: tokenResult.token,
refresh_id: tokenResult.refresh_id
});
} catch (error) {
res.status(500).json({ error: error.message });
}
}
-
VerifyJWT
import { Request, Response } from 'express';
import { JWTAuth } from '@pardnchiu/jwt-auth';
async function protectedHandler(req: Request, res: Response) {
try {
const result = await JWTAuth.VerifyJWT(req, res);
if (typeof result === "number") {
return res.status(result).json({
error: result === 401 ? "Unauthorized" : "Bad Request"
});
}
res.json({
message: "Protected resource accessed",
user: result
});
} catch (error) {
res.status(500).json({ error: error.message });
}
}
-
RevokeJWT
import { Request, Response } from "express";
import { JWTAuth } from "@pardnchiu/jwt-auth";
async function logoutHandler(req: Request, res: Response) {
try {
await JWTAuth.RevokeJWT(req, res);
res.json({
message: "Successfully logged out"
});
} catch (error) {
res.status(500).json({ error: error.message });
}
}
Configuration
Config
privateKeyPath
/ privateKey
: private key file path or content
publicKeyPath
/ publicKey
: public key file path or content
accessTokenExpires
: access token expire time
refreshTokenExpires
: refresh id expire time
isProd
: is production or not (affects cookie setting)
domain
: cookie domain
redis
: redis connection
host
: redis host
port
: redis port
password
: redis password (optional)
db
: redis db (optional)
checkUserExists
: user existence check function
AccessTokenCookieKey
: access token cookie name (default: 'access_token')
RefreshTokenCookieKey
: refresh id cookie name (default: 'refresh_id')
Supported methods
- Cookie: Automatically reads token from cookie
- Authorization Header:
Authorization: Bearer <token>
- Custom Headers:
X-Device-ID
: Device ID
X-Refresh-ID
: Custom Refresh ID
Token refresh
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
Security features
- 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
Error handling
The VerifyJWT
method returns:
AuthData
object 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
License
This source code project is licensed under the MIT license.
Creator
邱敬幃 Pardn Chiu
©️ 2025 邱敬幃 Pardn Chiu