Why jwt.verify Doesn’t Work with NextAuth.js Session Tokens

See how NextAuth.js encrypts session tokens, why a signed-token verifier cannot decode them, and how to read them with the library’s helpers.

NextAuth.js · JWT · Authentication

Updated:

Originally published on Medium

In the modern web development landscape, securing user authentication is paramount. Many developers turn to JSON Web Tokens (JWT) for their stateless, compact, and secure nature. When integrating authentication in a Next.js application, next-auth is a popular choice due to its simplicity and rich feature set.

However, a common stumbling block arises when developers try to use jwt.verify directly with tokens issued by next-auth. This article explores why this approach doesn’t work and how to handle JWTs correctly within a next-auth setup.

How NextAuth.js v4 Handles Session Tokens

With the JWT session strategy, NextAuth.js v4 encrypts session tokens by default. The token is a JWE, and v4 derives its encryption key from the configured secret using HKDF. A signed JWT is usually a JWS. jsonwebtoken.verify() verifies a JWS signature, so it cannot decrypt this session token.

Read the Token with the NextAuth.js Helper

For a Next.js Pages Router API route, use the helper from the same NextAuth.js version that issued the token. Set NEXTAUTH_SECRET in the server environment.

import { getToken } from "next-auth/jwt";

export default async function handler(req, res) {
  const token = await getToken({ req, secret: process.env.NEXTAUTH_SECRET });
  if (!token) {
    return res.status(401).json({ error: "Unauthorized" });
  }
  return res.status(200).json({ authenticated: true });
}

When you already have the raw token in a server-side script, use the library’s decoder:

import { decode } from "next-auth/jwt";

const token = process.env.NEXTAUTH_JWT;
const secret = process.env.NEXTAUTH_SECRET;
if (!token || !secret) throw new Error("Missing token or secret");

const payload = await decode({ token, secret });

These examples apply to the default JWT session strategy in v4. Match any custom decoder configured by the app. An OAuth provider’s access token is a separate credential and follows the provider’s validation rules.

Conclusion

Choose the decoder that matches the token’s issuer and format. For a NextAuth.js session token, use the library’s server-side helper so the application handles the token the same way it did when it issued it.

References

  1. NextAuth.js v4 JWT options
  2. NextAuth.js v4 getToken helper

Written by:

Full Stack Developer working with TypeScript, React and Node.js. Web development since 2019, across product interfaces, APIs and analytics.

A bit about me