JWT verification with explicit algorithm pin — defense against alg-confusion
Verify JWTs with explicit algorithm + issuer + audience. Default verify functions accept multiple algorithms = alg-confusion attack surface.
Default JWT verify accepts multiple algorithms. Attacker substitutes 'none' or HS256 for an RS256-signed token + bypasses verification.
What it is
JWT alg-confusion: if your verify function accepts both RS256 and HS256, an attacker re-signs the token using the public key as an HS256 secret + your verify accepts it.
Vulnerable example
// vulnerable: accepts any algorithm
const payload = jwt.verify(token, publicKey);Fixed example
// pin algorithm + issuer + audience
const payload = jwt.verify(token, publicKey, {
algorithms: ["RS256"], // pin algorithm
issuer: "https://your-issuer.com",
audience: "your-app-id",
clockTolerance: 30,
});How Securie catches it
apps/web/auth.ts:87JWT verification with explicit algorithm pin
Crypto_hygiene + AuthAuthz specialists catch jwt.verify without algorithms[] pin.
// pin algorithm + issuer + audience
const payload = jwt.verify(token, publicKey, {
algorithms: ["RS256"], // pin algorithm
issuer: "https://your-issuer.com",
audience: "your-app-id",
clockTolerance: 30,
});Checklist
- algorithms[] explicitly set
- issuer + audience verified
- clockTolerance set
- Signing key from secure source (not request)
FAQ
Why audience?
Audience identifies which service the token is FOR; pinning prevents tokens for other services being used here.
Related guides
JWTs are only as secure as your verification. Missing issuer check, missing expiration check, `alg: 'none'`, and algorithm confusion all still ship in AI-generated code.
Server Actions execute server-side but default to no auth. Add session-required guard at the top of every protected action.
Stripe webhook handlers must verify the signature before processing. Without verification, attackers spoof events. Plus: idempotency for retry-safety.
anon key is public BY DESIGN — without RLS it's a skeleton key. Lovable Apr 2026 BOLA showed 10.3% of apps got this wrong.