Free Tool

JWT Secret Generator

Generate a cryptographically secure JWT_SECRET for HS256, HS384 or HS512 signing. The key is created locally in your browser with the Web Crypto API and sized to the RFC 7518 minimum — 32 bytes for HS256, 64 bytes for HS512.

Format
Strength
Your generated secret
 

Generated locally in your browser with the Web Crypto API — nothing is ever sent to a server.

What is a JWT secret?

A JSON Web Token is only trustworthy because of its signature. With the HS256, HS384 and HS512 algorithms that signature is an HMAC computed over the header and payload using one shared secret — the JWT_SECRET. Your server signs tokens with it when a user logs in, and verifies the signature on every later request before trusting the claims inside.

That makes the secret the single thing standing between an attacker and a forged token. Whoever knows it can mint a JWT for any user ID, any role, any expiry. It must therefore be random, long enough for the algorithm you chose, kept only on the server, and never committed to version control.

How long should a JWT secret be?

RFC 7518 (JSON Web Algorithms) §3.2 requires that an HMAC key be at least as long as the hash output. Using a shorter key does not just weaken the signature — it violates the spec, and stricter libraries such as jose will refuse it outright:

AlgorithmHashMinimum key length
HS256SHA-25632 bytes (256 bits)
HS384SHA-38448 bytes (384 bits)
HS512SHA-51264 bytes (512 bits)

This generator defaults to 32 bytes, which is exactly the HS256 floor. If you sign with HS512, switch the strength to 64 bytes (also fine for HS384, which needs 48). A hex secret has two characters per byte, so a 32-byte key is a 64-character string.

Why do short, human-readable secrets fail? Because the security of HS256 is bounded by the secret's entropy, not by SHA-256. A 12-character password drawn from common words has maybe 40 bits of entropy; a GPU rig running hashcat's JWT mode tests billions of candidates per second and recovers it offline from a single captured token. A random 256-bit key is beyond brute force entirely.

Symmetric (HS256) vs asymmetric (RS256 / ES256)

HS256 is symmetric: the same secret both signs and verifies. It is fast, the tokens are small, and the setup is one environment variable — the right choice when a single backend issues and consumes its own tokens, which covers most Next.js apps and monoliths.

RS256 and ES256 are asymmetric: a private key signs, a public key verifies. Use them when other parties must verify tokens without being able to mint them — an API gateway, a mobile app, microservices, or any third party. The public key can be published via JWKS while the private key never leaves the issuer.

Whichever you choose, pin the accepted algorithms on the verification side. Letting the token header decide (the infamous alg: none and RS256 → HS256 confusion attacks) has broken real systems; both jsonwebtoken and jose accept an explicit algorithms list for exactly this reason.

How to use the JWT secret in Node.js / Next.js

1. Add the generated key to your .env file:

.env
# .env
# HS256 → 32 bytes (64 hex chars); HS512 → 64 bytes (128 hex chars)
JWT_SECRET=your-generated-secret

2. With jsonwebtoken — the classic Node.js library — sign and verify with the secret and an explicit algorithm:

lib/jwt.ts
// lib/jwt.ts — jsonwebtoken (Node.js runtime)
import jwt from "jsonwebtoken";

const secret = process.env.JWT_SECRET!;

export function signToken(payload: object) {
  return jwt.sign(payload, secret, { algorithm: "HS256", expiresIn: "1h" });
}

export function verifyToken(token: string) {
  // Always pin the algorithm list — never let the token pick it.
  return jwt.verify(token, secret, { algorithms: ["HS256"] });
}

3. With jose — built on Web Crypto, so it also runs in Edge runtime and Next.js middleware — encode the secret to bytes first:

lib/jwt.ts
// lib/jwt.ts — jose (works in Edge runtime and middleware)
import { SignJWT, jwtVerify } from "jose";

const secret = new TextEncoder().encode(process.env.JWT_SECRET);

export async function signToken(payload: Record<string, unknown>) {
  return new SignJWT(payload)
    .setProtectedHeader({ alg: "HS256" })
    .setIssuedAt()
    .setExpirationTime("1h")
    .sign(secret);
}

export async function verifyToken(token: string) {
  const { payload } = await jwtVerify(token, secret, {
    algorithms: ["HS256"],
  });
  return payload;
}

Generate a JWT secret from the command line

Prefer a terminal? openssl or Node's crypto module produce the same class of key — pick the byte count for your algorithm:

terminal
# HS256 — 32 bytes
openssl rand -hex 32

# HS512 — 64 bytes
openssl rand -hex 64

# Node.js, no openssl needed
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"

Setting up an auth library instead of hand-rolled JWTs? Use the NextAuth secret generator or the Better Auth secret generator — they need the same class of key with a different variable name.

Rotating a JWT secret

Rotating the secret means every token signed with the old value fails verification — with short-lived access tokens that is a minor blip, with long-lived tokens it is a mass logout. Rotate immediately after any suspected leak, and on a fixed schedule (quarterly is common) even without one.

For a zero-downtime rotation, put a key ID (kid) in the token header and let the verifier accept both the current and the previous secret for one token lifetime, then drop the old one. If you cannot change the verifier, rotate during a low-traffic window and keep access-token lifetimes short so the disruption is bounded.

Frequently Asked Questions

How long should a JWT secret be for HS256?

At least 32 bytes (256 bits) of random data, which is the RFC 7518 minimum for HS256 and the default of this generator. As a hex string that is 64 characters. For HS384 use 48 bytes and for HS512 use 64 bytes — select the 64-byte strength above for either.

Should I use hex or Base64 for JWT_SECRET?

Both are fine — libraries treat the secret as bytes, and what matters is how many random bytes went in. Hex is the safest choice for .env files and shell scripts because it contains no special characters, which is why this page defaults to it. Base64 is shorter for the same entropy; just avoid anything with quotes or spaces.

Can I use a password or passphrase as my JWT secret?

No. HMAC's security is capped by the secret's entropy, and anything a human can remember is guessable by a GPU. Tools like hashcat and jwt_tool crack weak HS256 secrets offline from a single captured token. Always use a randomly generated key of the required length.

Is generating the secret in the browser safe?

Yes. This tool uses crypto.getRandomValues from the Web Crypto API — the same cryptographically secure random source openssl and Node's crypto.randomBytes rely on. The key is generated entirely on your device and never sent anywhere. Copy it into your environment variable and close the tab.

This free tool is built and maintained by NEXTY.DEV — the Next.js SaaS boilerplate that ships with authentication, Stripe payments and AI already wired up.