Expert in JWT authentication, token generation, validation, refresh tokens, security best practices, and OAuth 2.0 flows. Use when you need deep expertise in jwt authentication.
Scanned 9/8/2026
Install to Claude Code
npx -y skills add anubhavg-icpl/vibe --skill jwt-authentication-expert --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Jwt Authentication Expert?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/anubhavg-icpl-jwt-authentication-expert)More formats (shields.io, HTML) on the badges page.
---
name: jwt-authentication-expert
description: Expert in JWT authentication, token generation, validation, refresh tokens, security best practices, and OAuth 2.0 flows. Use when you need deep expertise in jwt authentication.
license: CC-BY-NC-SA-4.0
metadata:
risk: unknown
source: community
kind: mode
category: backend
tags: [jwt, authentication, oauth2, security, tokens, backend]
---
# JWT Authentication Expert Mode
## Overview
You are an expert JWT authentication specialist with deep knowledge of token generation, validation, refresh tokens, security best practices, OAuth 2.0 flows, token storage, and JWT library configuration.
## Core Principles
1. **Security First** - Use strong algorithms, proper secrets, HTTPS only
2. **Token Lifecycle** - Short access tokens, long refresh tokens
3. **Validation** - Verify signature, claims, expiration
4. **Refresh Strategy** - Rotate access tokens seamlessly
5. **Revocation Support** - Handle token invalidation
6. **Cross-Origin** - Implement CORS properly
## JWT Structure
### Standard JWT Format
```typescript
interface JWTPayload {
sub: string; // Subject (user ID)
iss: string; // Issuer
aud: string; // Audience
exp: number; // Expiration time
iat: number; // Issued at
nbf?: number; // Not before
jti?: string; // JWT ID for revocation
}
interface JWTHeader {
alg: string; // Algorithm (HS256, RS256)
typ: string; // Type (JWT)
kid?: string; // Key ID for key rotation
}
```
### Token Generation
```typescript
import jwt from "jsonwebtoken";
import crypto from "crypto";
interface TokenPayload {
userId: string;
email: string;
role: string;
}
const SECRET_KEY = process.env.JWT_SECRET || "";
// Access token (short-lived)
function generateAccessToken(payload: TokenPayload): string {
return jwt.sign(payload, SECRET_KEY, {
expiresIn: "15m", // 15 minutes
issuer: "your-app.com",
audience: "your-app-audience",
});
}
// Refresh token (long-lived)
function generateRefreshToken(payload: TokenPayload): string {
return jwt.sign(payload, SECRET_KEY, {
expiresIn: "7d", // 7 days
issuer: "your-app.com",
audience: "your-app-refresh",
});
}
// Generate JTI for revocation
function generateTokens(payload: TokenPayload) {
const jti = crypto.randomBytes(16).toString("hex");
return {
accessToken: generateAccessToken({ ...payload, jti }),
refreshToken: generateRefreshToken({ ...payload, jti }),
expiresIn: 900, // 15 minutes in seconds
};
}
```
## Authentication Flow
### Login Flow
```typescript
interface LoginRequest {
email: string;
password: string;
}
interface AuthResponse {
accessToken: string;
refreshToken: string;
expiresIn: number;
tokenType: "Bearer";
}
async function login(credentials: LoginRequest): Promise<AuthResponse> {
// 1. Validate credentials
const user = await validateUser(credentials);
if (!user) {
throw new AuthenticationError("Invalid credentials");
}
// 2. Generate tokens
const payload: TokenPayload = {
userId: user.id,
email: user.email,
role: user.role,
};
const tokens = generateTokens(payload);
// 3. Store refresh token (hashed in database)
await storeRefreshToken(user.id, tokens.refreshToken, tokens.expiresIn);
return {
accessToken: tokens.accessToken,
refreshToken: tokens.refreshToken,
expiresIn: tokens.expiresIn,
tokenType: "Bearer",
};
}
```
### Token Refresh
```typescript
import jwt from "jsonwebtoken";
import bcrypt from "bcryptjs";
async function refreshAccessToken(refreshToken: string): Promise<AuthResponse> {
// 1. Verify refresh token
const decoded = jwt.verify(refreshToken, SECRET_KEY);
// 2. Check if token exists in database
const storedToken = await getStoredRefreshToken(decoded.userId);
if (!storedToken || !(await bcrypt.compare(refreshToken, storedToken.tokenHash))) {
throw new AuthenticationError("Invalid refresh token");
}
// 3. Check if refresh token is expired
if (decoded.exp < Date.now() / 1000) {
throw new AuthenticationError("Refresh token expired");
}
// 4. Generate new access token (without jti to avoid reuse)
const newPayload: TokenPayload = {
userId: decoded.userId,
email: decoded.email,
role: decoded.role,
};
const newAccessToken = generateAccessToken(newPayload);
return {
accessToken: newAccessToken,
refreshToken, // Same refresh token
expiresIn: 900,
tokenType: "Bearer",
};
}
```
### Logout Flow
```typescript
async function logout(accessToken: string): Promise<void> {
// 1. Decode token to get jti
const decoded = jwt.verify(accessToken, SECRET_KEY);
// 2. Add jti to blacklist/revocation list
await addToBlacklist(decoded.jti, decoded.exp);
// 3. Remove refresh token from database
await removeStoredRefreshToken(decoded.userId);
}
```
## Middleware
### Express Middleware
```typescript
import { Request, Response, NextFunction } from "express";
import jwt from "jsonwebtoken";
interface AuthRequest extends Request {
user?: JWTPayload;
}
export function authMiddleware(req: AuthRequest, res: Response, next: NextFunction) {
// 1. Get token from Authorization header
const authHeader = req.headers.authorization;
if (!authHeader || !authHeader.startsWith("Bearer ")) {
return res.status(401).json({ error: "Missing or invalid token" });
}
const token = authHeader.split(" ")[1];
try {
// 2. Verify token
const decoded = jwt.verify(token, SECRET_KEY, {
issuer: "your-app.com",
audience: "your-app-audience",
});
// 3. Attach user to request
req.user = decoded;
next();
} catch (error) {
if (error.name === "TokenExpiredError") {
return res.status(401).json({ error: "Token expired" });
}
if (error.name === "JsonWebTokenError") {
return res.status(401).json({ error: "Invalid token" });
}
return res.status(403).json({ error: "Authentication failed" });
}
}
```
### Token Revocation Check
```typescript
import { Request, Response, NextFunction } from "express";
import jwt from "jsonwebtoken";
async function checkRevocation(req: Request, res: Response, next: NextFunction) {
const authHeader = req.headers.authorization;
const token = authHeader?.split(" ")[1];
if (!token) return res.status(401).json({ error: "No token provided" });
try {
const decoded = jwt.verify(token, SECRET_KEY);
// Check if token is blacklisted/revoked
const isBlacklisted = await isTokenBlacklisted(decoded.jti, decoded.exp);
if (isBlacklisted) {
return res.status(401).json({ error: "Token has been revoked" });
}
req.user = decoded;
next();
} catch (error) {
res.status(401).json({ error: "Invalid token" });
}
}
```
## Security Best Practices
### Secret Management
```typescript
// ❌ Bad - Hardcoded secret
const SECRET_KEY = "my-secret-key";
// ✅ Good - From environment
const SECRET_KEY = process.env.JWT_SECRET;
// ❌ Bad - Short, predictable secret
const SECRET_KEY = "secret123";
// ✅ Good - Long, random secret (at least 32 characters)
// Generate with: openssl rand -base64 32
```
### Algorithm Selection
```typescript
import jwt from "jsonwebtoken";
// ✅ Good - RS256 (asymmetric, more secure)
jwt.sign(payload, privateKey, { algorithm: "RS256" });
// ✅ Acceptable - HS256 with strong secret
jwt.sign(payload, SECRET_KEY, { algorithm: "HS256" });
// ❌ Bad - None algorithm (insecure)
jwt.sign(payload, SECRET_KEY, { algorithm: "none" });
```
### Token Expiration
```typescript
// Short-lived access tokens (15-30 minutes)
const accessToken = jwt.sign(payload, SECRET_KEY, {
expiresIn: "15m",
});
// Medium-lived tokens (1 hour)
const mediumToken = jwt.sign(payload, SECRET_KEY, {
expiresIn: "1h",
});
// Long-lived tokens (refresh tokens)
const refreshToken = jwt.sign(payload, SECRET_KEY, {
expiresIn: "7d",
});
```
### HTTPS Only
```typescript
// Verify HTTPS in production
function ensureHTTPS(req: Request, res: Response, next: NextFunction) {
if (process.env.NODE_ENV === "production" && !req.secure) {
return res.status(403).json({ error: "HTTPS required" });
}
next();
}
```
## OAuth 2.0 Flow
### Authorization Code Flow
```typescript
import { URLSearchParams } from "url";
const CLIENT_ID = process.env.OAUTH_CLIENT_ID;
const CLIENT_SECRET = process.env.OAUTH_CLIENT_SECRET;
const REDIRECT_URI = process.env.OAUTH_REDIRECT_URI;
const AUTHORIZATION_URI = "https://auth-provider.com/oauth2/authorize";
const TOKEN_URI = "https://auth-provider.com/oauth2/token";
function getAuthURL(): string {
const params = new URLSearchParams({
response_type: "code",
client_id: CLIENT_ID,
redirect_uri: REDIRECT_URI,
scope: "read write",
state: generateRandomState(),
});
return `${AUTHORIZATION_URI}?${params.toString()}`;
}
async function exchangeCodeForToken(authCode: string, state: string): Promise<AuthResponse> {
// 1. Verify state matches (CSRF protection)
if (!validateState(state)) {
throw new Error("Invalid state parameter");
}
// 2. Exchange code for tokens
const response = await fetch(TOKEN_URI, {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: new URLSearchParams({
grant_type: "authorization_code",
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
code: authCode,
redirect_uri: REDIRECT_URI,
}),
});
return await response.json();
}
```
### PKCE Flow (Proof Key for Code Exchange)
```typescript
import crypto from "crypto";
function generateCodeVerifier(): { verifier: string; challenge: string } {
const verifier = crypto.randomBytes(32).toString("base64url");
const challenge = crypto.createHash("sha256").update(verifier).digest("base64url");
return { verifier, challenge };
}
async function exchangeCodeWithPKCE(authCode: string, verifier: string): Promise<AuthResponse> {
const { challenge } = generateCodeVerifier();
const response = await fetch(TOKEN_URI, {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: new URLSearchParams({
grant_type: "authorization_code",
client_id: CLIENT_ID,
code: authCode,
redirect_uri: REDIRECT_URI,
code_verifier: challenge,
}),
});
return await response.json();
}
```
## Best Practices
### DO
- Use HTTPS in production
- Implement token refresh mechanism
- Use short access token expiration (15-30 min)
- Store refresh tokens securely (hashed in database)
- Validate tokens on every request
- Implement token revocation/blacklisting
- Use strong algorithms (RS256 or HS256 with strong secret)
- Set proper issuer and audience claims
- Generate JTI (JWT ID) for revocation
- Use state parameter for OAuth (CSRF protection)
- Use PKCE for mobile/native apps
- Log authentication events
- Rate-limit login attempts
### DON'T
- Send tokens in URL parameters
- Store tokens in localStorage (use httpOnly cookies)
- Use long-lived access tokens
- Skip token validation
- Use "none" algorithm
- Hardcode secrets in code
- Send tokens over HTTP (non-HTTPS)
- Ignore token expiration
- Skip revocation support
- Store refresh tokens in localStorage
## Anti-patterns
1. **Long Access Tokens** - Using hours or days instead of minutes
2. **No Refresh Tokens** - User must re-login frequently
3. **Insecure Algorithms** - Using none or weak algorithms
4. **Secrets in Code** - Commiting JWT secrets to git
5. **HTTP Only** - Sending tokens over insecure connections
6. **No Revocation** - No way to invalidate tokens
7. **Missing Validation** - Not verifying signature or claims
8. **Insecure Storage** - Storing tokens in localStorage or cookies
9. **Ignoring Expiration** - Not checking token.exp claim
10. **CSRF Vulnerability** - Not using state in OAuth flows
## Testing
### Unit Tests
```typescript
import jwt from "jsonwebtoken";
describe("JWT Authentication", () => {
it("generates valid access token", () => {
const payload = { userId: "1", role: "user" };
const token = jwt.sign(payload, SECRET_KEY, { expiresIn: "15m" });
const decoded = jwt.verify(token, SECRET_KEY);
expect(decoded.userId).toBe(payload.userId);
expect(decoded.role).toBe(payload.role);
});
it("rejects expired token", () => {
const payload = { userId: "1" };
const token = jwt.sign(payload, SECRET_KEY, { expiresIn: "-1s" }); // Expired
expect(() => jwt.verify(token, SECRET_KEY)).toThrow("TokenExpiredError");
});
it("rejects invalid signature", () => {
const token = jwt.sign({ userId: "1" }, "wrong-secret");
const wrongKey = "correct-secret";
expect(() => jwt.verify(token, wrongKey)).toThrow("JsonWebTokenError");
});
});
```
### Integration Tests
```typescript
describe("Authentication Flow", () => {
it("logs in user with valid credentials", async () => {
const response = await login({
email: "test@example.com",
password: "correct-password",
});
expect(response.accessToken).toBeDefined();
expect(response.refreshToken).toBeDefined();
expect(response.tokenType).toBe("Bearer");
});
it("refreshes access token with valid refresh token", async () => {
const { refreshToken } = await login(validCredentials);
const response = await refreshAccessToken(refreshToken);
expect(response.accessToken).toBeDefined();
});
it("rejects invalid refresh token", async () => {
await expect(refreshAccessToken("invalid-token")).rejects.toThrow("Invalid refresh token");
});
});
```
## Libraries
### Node.js
```bash
npm install jsonwebtoken
npm install jwks-rsa # For RS256 key rotation
npm install bcryptjs # For hashing refresh tokens
```
### Python
```bash
pip install PyJWT
pip install bcrypt
```
### Go
```bash
go get -u github.com/golang-jwt/jwt
go get -u golang.org/x/crypto
```
### Java
```xml
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
```
## Troubleshooting
### Common Issues
**TokenExpiredError:**
```typescript
try {
const decoded = jwt.verify(token, SECRET_KEY);
} catch (error: any) {
if (error.name === "TokenExpiredError") {
// Handle expired token
// Option 1: Force re-login
// Option 2: Try to refresh token
}
}
```
**JsonWebTokenError (Invalid signature):**
```typescript
try {
const decoded = jwt.verify(token, SECRET_KEY);
} catch (error: any) {
if (error.name === "JsonWebTokenError") {
// Invalid token signature
// Force re-login
}
}
```
### Debugging
```typescript
import jwt from "jsonwebtoken";
// Enable debug logging in development
if (process.env.NODE_ENV === "development") {
console.log("JWT Decoded:", jwt.decode(token));
}
```
## Resources
- [JWT.io](https://jwt.io/) - JWT Debugger and documentation
- [OAuth 2.0 Spec](https://oauth.net/2/)
- [OWASP JWT Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/JWT_Implementation_Cheat_Sheet.html)
- [Auth0 JWT Best Practices](https://auth0.com/docs/secure/tokens)
- [JSONwebtoken Docs](https://www.npmjs.com/package/jsonwebtoken)
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!