Generate Production-Ready JWT Secrets in One Click

Create cryptographically secure JWT signing secrets instantly. Get 256-bit, 384-bit, or 512-bit secrets ready for immediate use in your authentication system.

Security:256 bits
Type:HMAC
HMAC with SHA-256 (most common)

๐Ÿ”ง Interactive JWT Decoder & Encoder

Decode existing JWTs to inspect their structure, or build new ones with custom claims.

JWT Decoder

JWT Builder

โฐ JWT Expiration Calculator

Calculate precise expiration times for your JWT tokens with various time formats and validation.

Expiration Settings

Quick Presets

Expiration Preview

Unix Timestamp (exp claim)
1786808382
Human Readable
8/15/2026, 3:39:42 PM
ISO 8601
2026-08-15T15:39:42.491Z
Time Until Expiry
1d 0h 0m
json
{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1786721982,
  "exp": 1786808382
}

โš ๏ธ Expiration Best Practices

  • Short-lived tokens: Use 15-30 minutes for sensitive operations
  • Session tokens: 1-24 hours for user sessions
  • API tokens: Consider 1-7 days for automated systems
  • Refresh strategy: Implement token refresh for better UX
  • Clock skew: Account for time differences between servers

๐Ÿ” JWT Debugger & Validator

Debug JWT tokens, validate structure, and analyze potential security issues.

๐Ÿ“Š JWT Algorithm Comparison

AlgorithmTypeKey LengthSecurityPerformanceUse Cases
HS256HMAC-SHA256256 bits (32 bytes)GoodFastestMost common, good for web apps
HS384HMAC-SHA384384 bits (48 bytes)BetterMediumHigher security requirements
HS512HMAC-SHA512512 bits (64 bytes)BestSlowerMaximum security, critical systems
RS256RSA-SHA2562048+ bitsHighSlowPublic key verification
ES256ECDSA-SHA256256 bitsHighFastModern alternative to RSA

๐Ÿ’ก Current selection: HS256 offers hmac with sha-256 (most common) with 256 bits of security. Perfect for most web applications.

๐Ÿงฉ JWT Claims Builder

Build standard JWT claims with validation and examples.

Standard Claims

Custom Claims

Generated Claims Preview

{
  "iss": "your-app.com",
  "sub": "user-123",
  "aud": "api.example.com",
  "iat": 1786721982,
  "exp": 1786808382,
  "scope": "read:profile write:posts",
  "role": "user",
  "email": "[email protected]"
}

Usage Examples

.env
JWT_SECRET=your-secret-here
Node.js (jsonwebtoken)
const jwt = require('jsonwebtoken');

const token = jwt.sign(
  { userId: '123', role: 'admin' },
  process.env.JWT_SECRET,
  { algorithm: 'HS256', expiresIn: '24h' }
);

JWT Secret Security Best Practices

Secret Length Requirements

Secret length matters

For HMAC-based JWT algorithms, the secret should be at least as long as the hash output:

  • HS256 requires at least 256 bits (32 bytes)
  • HS384 requires at least 384 bits (48 bytes)
  • HS512 requires at least 512 bits (64 bytes)

Using a shorter secret weakens the security of your tokens and makes them vulnerable to brute force attacks.

Secure Secret Storage

  • Environment Variables: Store secrets in environment variables, never in source code
  • Secret Management: Use dedicated services like AWS Secrets Manager, Azure Key Vault, or HashiCorp Vault
  • File Permissions: If storing in files, use strict permissions (600 or 640)
  • Version Control: Never commit secrets to Git repositories
  • Container Security: Use Docker secrets or Kubernetes secrets in containerized environments

Secret Rotation Strategy

โœ“ Do

  • Rotate secrets regularly (every 90 days minimum)
  • Support multiple active secrets during rotation
  • Use automated rotation tools when possible
  • Log secret usage for audit trails
  • Test rotation procedures regularly

โœ— Don't

  • Wait for security incidents to rotate
  • Use the same secret across environments
  • Forget to update all services simultaneously
  • Leave old secrets active indefinitely
  • Skip testing after rotation

Choosing the Right Algorithm

AlgorithmSecurity LevelPerformanceRecommendation
HS256GoodFastDefault choice for most applications
HS384BetterMediumUse for higher security requirements
HS512BestSlowerMaximum security, slight performance cost

Production Deployment Checklist

  • Generate unique secrets for each environment (dev, staging, prod)
  • Implement proper secret storage (environment variables or secret manager)
  • Set up monitoring for failed JWT validation attempts
  • Configure appropriate token expiration times
  • Test secret rotation procedure
  • Audit code for hardcoded secrets

Complete Implementation Examples

Express.js Middleware with Security

middleware/auth.js
const jwt = require('jsonwebtoken');
const rateLimit = require('express-rate-limit');

// Rate limiting for token endpoints
const authLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 5,
  message: 'Too many authentication attempts'
});

class JWTService {
  constructor() {
    this.secret = process.env.JWT_SECRET;
    this.algorithm = 'HS256';
    
    if (!this.secret) {
      throw new Error('JWT_SECRET environment variable is required');
    }
  }

  generateToken(payload) {
    return jwt.sign({
      ...payload,
      iat: Math.floor(Date.now() / 1000),
      jti: require('crypto').randomBytes(16).toString('hex')
    }, this.secret, {
      algorithm: this.algorithm,
      expiresIn: '24h',
      issuer: 'your-app',
      audience: 'your-users'
    });
  }

  verifyToken(token) {
    try {
      return jwt.verify(token, this.secret, {
        algorithms: [this.algorithm],
        issuer: 'your-app',
        audience: 'your-users'
      });
    } catch (error) {
      throw new Error('Invalid token: ' + error.message);
    }
  }
}

// Authentication middleware
const authenticateToken = (req, res, next) => {
  const authHeader = req.headers['authorization'];
  const token = authHeader && authHeader.split(' ')[1];

  if (!token) {
    return res.status(401).json({ error: 'Access token required' });
  }

  try {
    const jwtService = new JWTService();
    req.user = jwtService.verifyToken(token);
    next();
  } catch (error) {
    return res.status(403).json({ error: 'Invalid token' });
  }
};

module.exports = { authenticateToken, authLimiter };

Python Flask with Error Handling

jwt_auth.py
import jwt
import os
from datetime import datetime, timedelta, timezone
from functools import wraps
from flask import request, jsonify

class JWTAuth:
    def __init__(self):
        self.secret = os.getenv('JWT_SECRET')
        self.algorithm = 'HS256'
        
        if not self.secret:
            raise ValueError('JWT_SECRET environment variable required')

    def generate_token(self, user_data):
        payload = {
            'user_id': user_data['id'],
            'email': user_data['email'],
            'role': user_data.get('role', 'user'),
            'exp': datetime.now(timezone.utc) + timedelta(hours=24),
            'iat': datetime.now(timezone.utc),
            'iss': 'your-app',
            'aud': 'your-users'
        }
        return jwt.encode(payload, self.secret, algorithm=self.algorithm)

    def verify_token(self, token):
        try:
            return jwt.decode(
                token, self.secret, 
                algorithms=[self.algorithm],
                options={"verify_aud": True, "verify_iss": True}
            )
        except jwt.ExpiredSignatureError:
            raise ValueError('Token has expired')
        except jwt.InvalidTokenError:
            raise ValueError('Invalid token')

# Decorator for protected routes
def token_required(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        auth_header = request.headers.get('Authorization')
        
        if not auth_header:
            return jsonify({'error': 'Token missing'}), 401
            
        try:
            token = auth_header.split(' ')[1]
            jwt_auth = JWTAuth()
            payload = jwt_auth.verify_token(token)
            request.current_user = payload
        except (IndexError, ValueError) as e:
            return jsonify({'error': str(e)}), 401
            
        return f(*args, **kwargs)
    return decorated

JWT Security Audit Checklist

๐Ÿ” Secret & Configuration

๐Ÿ›ก๏ธ Implementation Security

๐Ÿ” Quick Security Test

Test your JWT implementation:

  • โ€ข Try using 'none' algorithm โ†’ should be rejected
  • โ€ข Send expired token โ†’ should return 401
  • โ€ข Modify token signature โ†’ should be invalid
  • โ€ข Test with wrong audience/issuer โ†’ should be rejected

Bulk Generation

secrets

Implementation Examples

Node.js with Express.js

auth-middleware.js
const jwt = require('jsonwebtoken');

// Generate token (login)
function generateToken(user) {
  const payload = {
    userId: user.id,
    email: user.email,
    role: user.role
  };
  
  return jwt.sign(payload, process.env.JWT_SECRET, {
    algorithm: 'HS256',
    expiresIn: '24h',
    issuer: 'your-app-name',
    audience: 'your-app-users'
  });
}

// Verify token (middleware)
function verifyToken(req, res, next) {
  const token = req.headers.authorization?.split(' ')[1];
  
  if (!token) {
    return res.status(401).json({ error: 'Access token required' });
  }
  
  try {
    const decoded = jwt.verify(token, process.env.JWT_SECRET, {
      algorithms: ['HS256']
    });
    req.user = decoded;
    next();
  } catch (error) {
    return res.status(401).json({ error: 'Invalid token' });
  }
}

Python with Flask

jwt_utils.py
import jwt
import os
from datetime import datetime, timedelta
from functools import wraps
from flask import request, jsonify

JWT_SECRET = os.getenv('JWT_SECRET')
JWT_ALGORITHM = 'HS256'

def generate_token(user_data):
    payload = {
        'user_id': user_data['id'],
        'email': user_data['email'],
        'exp': datetime.utcnow() + timedelta(hours=24),
        'iat': datetime.utcnow(),
        'iss': 'your-app-name'
    }
    
    return jwt.encode(payload, JWT_SECRET, algorithm=JWT_ALGORITHM)

def verify_token(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        token = request.headers.get('Authorization')
        
        if not token:
            return jsonify({'error': 'Token missing'}), 401
            
        try:
            token = token.split(' ')[1]  # Remove 'Bearer '
            decoded = jwt.decode(token, JWT_SECRET, algorithms=[JWT_ALGORITHM])
            request.user = decoded
        except jwt.ExpiredSignatureError:
            return jsonify({'error': 'Token expired'}), 401
        except jwt.InvalidTokenError:
            return jsonify({'error': 'Invalid token'}), 401
            
        return f(*args, **kwargs)
    return decorated

Java with Spring Boot

JwtUtil.java
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class JwtUtil {
    
    @Value("${jwt.secret}")
    private String jwtSecret;
    
    private final int jwtExpirationMs = 86400000; // 24 hours

    public String generateToken(String username, String role) {
        return Jwts.builder()
                .setSubject(username)
                .claim("role", role)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + jwtExpirationMs))
                .signWith(Keys.hmacShaKeyFor(jwtSecret.getBytes()), SignatureAlgorithm.HS256)
                .compact();
    }

    public Claims extractClaims(String token) {
        return Jwts.parserBuilder()
                .setSigningKey(Keys.hmacShaKeyFor(jwtSecret.getBytes()))
                .build()
                .parseClaimsJws(token)
                .getBody();
    }

    public boolean isTokenExpired(String token) {
        return extractClaims(token).getExpiration().before(new Date());
    }

    public boolean validateToken(String token) {
        try {
            extractClaims(token);
            return true;
        } catch (JwtException | IllegalArgumentException e) {
            return false;
        }
    }
}

Go with Gin Framework

jwt_middleware.go
package middleware

import (
    "net/http"
    "strings"
    "time"

    "github.com/gin-gonic/gin"
    "github.com/golang-jwt/jwt/v4"
)

var jwtSecret = []byte("your-secret-here")

type Claims struct {
    UserID string `json:"user_id"`
    Role   string `json:"role"`
    jwt.RegisteredClaims
}

func GenerateToken(userID, role string) (string, error) {
    claims := Claims{
        UserID: userID,
        Role:   role,
        RegisteredClaims: jwt.RegisteredClaims{
            ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)),
            IssuedAt:  jwt.NewNumericDate(time.Now()),
            Issuer:    "your-app",
        },
    }

    token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
    return token.SignedString(jwtSecret)
}

func AuthMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        authHeader := c.GetHeader("Authorization")
        if authHeader == "" {
            c.JSON(http.StatusUnauthorized, gin.H{"error": "Authorization header required"})
            c.Abort()
            return
        }

        tokenString := strings.TrimPrefix(authHeader, "Bearer ")
        
        claims := &Claims{}
        token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) {
            return jwtSecret, nil
        })

        if err != nil || !token.Valid {
            c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"})
            c.Abort()
            return
        }

        c.Set("userID", claims.UserID)
        c.Set("role", claims.Role)
        c.Next()
    }
}

C# with .NET Core

JwtService.cs
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

public class JwtService
{
    private readonly string _secret = "your-secret-here";
    private readonly string _issuer = "your-app";

    public string GenerateToken(string userId, string role)
    {
        var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_secret));
        var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

        var claims = new[]
        {
            new Claim(JwtRegisteredClaimNames.Sub, userId),
            new Claim(ClaimTypes.Role, role),
            new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
            new Claim(JwtRegisteredClaimNames.Iat, 
                DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(), ClaimValueTypes.Integer64)
        };

        var token = new JwtSecurityToken(
            issuer: _issuer,
            audience: _issuer,
            claims: claims,
            expires: DateTime.UtcNow.AddHours(24),
            signingCredentials: credentials
        );

        return new JwtSecurityTokenHandler().WriteToken(token);
    }

    public ClaimsPrincipal ValidateToken(string token)
    {
        var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_secret));
        var tokenHandler = new JwtSecurityTokenHandler();

        var validationParameters = new TokenValidationParameters
        {
            ValidateIssuerSigningKey = true,
            IssuerSigningKey = key,
            ValidateIssuer = true,
            ValidIssuer = _issuer,
            ValidateAudience = true,
            ValidAudience = _issuer,
            ClockSkew = TimeSpan.Zero
        };

        return tokenHandler.ValidateToken(token, validationParameters, out SecurityToken validatedToken);
    }
}

PHP with Laravel

JwtHelper.php
<?php

namespace App\Helpers;

use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use Exception;

class JwtHelper
{
    private static $secret = 'your-secret-here';
    private static $issuer = 'your-app';
    private static $algorithm = 'HS256';

    public static function generateToken($userId, $role)
    {
        $payload = [
            'iss' => self::$issuer,
            'sub' => $userId,
            'role' => $role,
            'iat' => time(),
            'exp' => time() + (24 * 60 * 60) // 24 hours
        ];

        return JWT::encode($payload, self::$secret, self::$algorithm);
    }

    public static function validateToken($token)
    {
        try {
            $decoded = JWT::decode($token, new Key(self::$secret, self::$algorithm));
            return (array) $decoded;
        } catch (Exception $e) {
            throw new Exception('Invalid token: ' . $e->getMessage());
        }
    }

    public static function refreshToken($token)
    {
        try {
            $decoded = self::validateToken($token);
            
            // Check if token expires in next hour
            if ($decoded['exp'] - time() < 3600) {
                return self::generateToken($decoded['sub'], $decoded['role']);
            }
            
            return $token; // No refresh needed
        } catch (Exception $e) {
            throw new Exception('Cannot refresh token: ' . $e->getMessage());
        }
    }
}

// Laravel Middleware
class JwtMiddleware
{
    public function handle($request, Closure $next)
    {
        $token = $request->bearerToken();
        
        if (!$token) {
            return response()->json(['error' => 'Token not provided'], 401);
        }

        try {
            $decoded = JwtHelper::validateToken($token);
            $request->merge(['user' => $decoded]);
            return $next($request);
        } catch (Exception $e) {
            return response()->json(['error' => 'Unauthorized'], 401);
        }
    }
}

๐Ÿ” Implementation Security Tips

  • Always validate the algorithm to prevent algorithm confusion attacks
  • Set appropriate expiration times - shorter is more secure but less convenient
  • Include audience and issuer claims for additional validation
  • Use HTTPS only in production to prevent token interception
  • Implement proper error handling without exposing sensitive information
  • Consider implementing token blacklisting for logout functionality

Generate in Terminal

For production systems, generate secrets locally:

OpenSSL (256-bit, base64)

$openssl rand -base64 32

OpenSSL (256-bit, hex)

$openssl rand -hex 32

Python secrets module

$python3 -c "import secrets; print(secrets.token_urlsafe(32))"

Node.js crypto

$node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"