BlogHow to Generate a JWT Secret Key (Step-by-Step)
·Updated September 22, 2026·11 min read·JWTSecrets Team

How to Generate a JWT Secret Key (Step-by-Step)

Generate cryptographically secure JWT secrets in Node.js, Python, Go, and Java for CI/CD — with a free browser tool when you need a key instantly.

How to Generate a JWT Secret Key (Step-by-Step)

Every JWT signed with HMAC algorithms (HS256, HS384, HS512) depends on a secret key. If that secret is weak, predictable, or leaked, your entire authentication system is compromised. This guide focuses on programmatic generation — the approach you want in CI/CD, Docker entrypoints, and secrets-manager bootstrap scripts.

> Prefer not to write the code? Generate a secure secret instantly with our free browser tool → — all randomness stays on your device.

Why Secret Quality Matters

A JWT secret is not a password you invent — it is raw cryptographic entropy. Attackers who capture any valid token can attempt offline brute-force attacks against weak secrets at millions of guesses per second. A 256-bit randomly generated secret makes this attack computationally infeasible. For depth on entropy, see JWT secret entropy.

Step 1: Choose the Right Key Length

AlgorithmMinimum Key SizeRecommended
HS256256 bits (32 bytes)256 bits
HS384384 bits (48 bytes)384 bits
HS512512 bits (64 bytes)512 bits

For most applications, 256 bits for HS256 is the correct default. See what size JWT secret you need.

Step 2: Generate Programmatically

Always use a CSPRNG (crypto.randomBytes, secrets, crypto/rand, SecureRandom). Never Math.random(), random.random(), or a human-typed passphrase.

Node.js

const crypto = require('crypto');

// 32 bytes = 256 bits → 64 hex characters
const secret = crypto.randomBytes(32).toString('hex');
console.log(secret);

// Or base64 if your stack expects it
const secretB64 = crypto.randomBytes(32).toString('base64');

Python

import secrets

secret = secrets.token_hex(32)  # 256-bit hex
print(secret)

# Or URL-safe base64
secret_b64 = secrets.token_urlsafe(32)

Go

package main

import (
	"crypto/rand"
	"encoding/hex"
	"fmt"
)

func main() {
	b := make([]byte, 32) // 256-bit
	if _, err := rand.Read(b); err != nil {
		panic(err)
	}
	fmt.Println(hex.EncodeToString(b))
}

Java

import java.security.SecureRandom;
import java.util.HexFormat;

public class JwtSecret {
  public static void main(String[] args) {
    byte[] bytes = new byte[32]; // 256-bit
    new SecureRandom().nextBytes(bytes);
    System.out.println(HexFormat.of().formatHex(bytes));
  }
}

OpenSSL (CLI / scripts)

openssl rand -hex 32

Wire any of these into your deploy pipeline: generate once, store in your secrets backend, inject as JWT_SECRET at runtime.

Step 3: Store It Securely

Never hardcode the secret in source code:

JWT_SECRET=your-generated-hex-key-here

For production, use a secrets manager. Read how to store JWT secrets securely.

Step 4: Sign and Verify a Test Token

const jwt = require('jsonwebtoken');
const token = jwt.sign({ userId: 1 }, process.env.JWT_SECRET, {
  algorithm: 'HS256',
  expiresIn: '1h',
});

Paste the token and secret into the JWT Validator to confirm the signature is valid. You can also build a token visually with the JWT Encoder.

Understanding HMAC Signing

JWT secrets used with HS256 are inputs to HMAC-SHA256. The algorithm combines your secret with the base64url-encoded header and payload to produce a signature. Verification repeats the same computation — if the result matches the token's third segment, the token is authentic.

  • Same secret everywhere: Every service that verifies HS256 tokens must possess the signing secret
  • No encryption: The payload is only base64-encoded — never store passwords or PII in claims
  • Algorithm matters: Always specify algorithms: ['HS256'] to prevent algorithm confusion attacks

For microservices where many teams verify tokens, see HS256 vs RS256. For monoliths and small APIs, HS256 with a strong secret is the right default.

Separate Secrets Per Environment

# .env.development
JWT_SECRET=dev-only-secret-never-use-in-prod

# Production (hosting platform or secrets manager)
JWT_SECRET=production-256-bit-random-secret

Generate a fresh secret for each environment — with code in CI, or via the JWT Secret Generator.

When to Rotate Your Secret

Rotate immediately if you suspect the secret was committed to git, logged, or breached. For routine hygiene, rotate on a schedule using the kid header — see how to rotate JWT secrets.

Common Mistakes to Avoid

  • Using a human-readable passphrase instead of random bytes
  • Reusing the same secret across development and production
  • Committing secrets to git (even in private repos)
  • Using keys shorter than 256 bits for HS256
  • Using Math.random() / non-crypto RNGs

Frequently Asked Questions

Can I use a UUID as my JWT secret? A UUID v4 has 122 bits of randomness — below the 256-bit minimum for HS256. Generate 32 random bytes instead.

Should I base64-encode my secret? Hex is common for HS256. If your library expects base64, encode 32 random bytes — do not base64-encode a short passphrase.

How do I know my secret is working? Sign a test token and verify it with the JWT Validator.

Need a secret right now without writing code? Use the JWT Secret Generator.

Advertisement

Written by

JWTSecrets Team

Editorial Team

The JWTSecrets editorial team writes practical guides on JWT authentication, cryptographic key management, and browser-based security tooling. Our content is reviewed against IETF RFCs and current library documentation.