Skip to content

test(auth): jwt validation edge cases#161

Open
Jayking40 wants to merge 1 commit intoCalloraOrg:mainfrom
Jayking40:#109-Auth--JWT-validation-edge-cases-(expired,-malformed,-wrong-alg)
Open

test(auth): jwt validation edge cases#161
Jayking40 wants to merge 1 commit intoCalloraOrg:mainfrom
Jayking40:#109-Auth--JWT-validation-edge-cases-(expired,-malformed,-wrong-alg)

Conversation

@Jayking40
Copy link
Contributor

test(auth): JWT validation edge cases

Summary

Hardens the requireAuth middleware with proper JWT verification and adds comprehensive tests covering JWT failure modes: expired tokens, malformed payloads, unexpected algorithms, missing claims, and wrong signing secrets.

Previously, requireAuth extracted the Bearer token string and used it directly as the user ID without any cryptographic verification. This PR upgrades it to perform full jwt.verify() validation while maintaining backward compatibility with the x-user-id header path used by existing routes.

Changes

  • Middleware hardening (requireAuth)

    • Added JWT signature verification using JWT_SECRET environment variable
    • Restricted accepted signing algorithms to HS256 only, preventing algorithm-confusion attacks (e.g., alg: none)
    • Added validation of required userId claim in the token payload
    • Distinguished error codes for different failure modes: TOKEN_EXPIRED, INVALID_TOKEN, MISSING_CLAIMS, MISSING_TOKEN
    • Safe logging — failure reasons are logged without ever including token contents
    • Preserved x-user-id header fallback for backward compatibility
  • Extended JWT test helpers

    • signTokenWrongSecret — signs with an incorrect secret
    • signTokenWithAlgorithm — signs with a caller-specified algorithm
    • signTokenMissingClaims — signs a token with arbitrary (incomplete) payload
    • buildNoneAlgorithmToken — crafts a hand-built alg: none token for attack simulation
  • Added 20 integration tests covering:

    • Happy path (valid JWT, x-user-id header)
    • Missing credentials (no header, wrong scheme, empty Bearer)
    • Expired tokens
    • Malformed tokens (garbage strings, corrupted payloads)
    • Algorithm restrictions (HS384, HS512, alg: none)
    • Wrong signing secret
    • Missing/invalid claims (no userId, empty userId, numeric userId, standard-only claims)
    • Server misconfiguration (JWT_SECRET not set)
    • Verification that token contents are never leaked in error responses

Testing

PASS tests/integration/requireAuth.test.ts requireAuth – happy path ✓ passes through with a valid Bearer JWT and sets authenticatedUser ✓ accepts x-user-id header when no Bearer token is present requireAuth – missing credentials ✓ returns 401 when no Authorization or x-user-id header is sent ✓ returns 401 when Authorization header is present but not Bearer scheme ✓ returns 401 when Bearer prefix has no token value ✓ returns 401 with MISSING_TOKEN for Bearer followed by only whitespace requireAuth – expired tokens ✓ returns 401 with TOKEN_EXPIRED code for an expired JWT requireAuth – malformed tokens ✓ rejects a completely invalid string ✓ rejects a token with only two dot-separated segments and garbage ✓ rejects a token with valid base64 header but corrupted payload ✓ does not leak token content in the error response requireAuth – algorithm restrictions ✓ rejects a token signed with HS384 when only HS256 is allowed ✓ rejects a token signed with HS512 when only HS256 is allowed ✓ rejects a crafted "alg: none" token requireAuth – wrong signing secret ✓ rejects a token signed with an incorrect secret requireAuth – missing or invalid claims ✓ rejects a token that has no userId claim ✓ rejects a token where userId is an empty string ✓ rejects a token where userId is a number instead of a string ✓ rejects a token with only standard JWT claims and no userId requireAuth – server misconfiguration ✓ returns 401 when JWT_SECRET env var is not set

Tests: 20 passed, 20 total

Full suite: all 193 tests pass. The 2 pre-existing suite failures (app.test.ts, health.test.ts) are caused by a missing Prisma generated client and are unrelated.

Security notes

  • Algorithm pinning: Only HS256 is accepted, blocking none-algorithm and RSA-confusion attacks
  • Safe logging: Auth failure reasons are logged with error codes only; token contents are never written to logs or error responses
  • Claim validation: Tokens must contain a non-empty string userId claim to be accepted
  • The JWT_SECRET environment variable must be configured for Bearer token auth to work

Closes #109

@drips-wave
Copy link

drips-wave bot commented Mar 24, 2026

@Jayking40 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Auth: JWT validation edge cases (expired, malformed, wrong alg)

1 participant