We just shipped add-mcp: think npx skills but for MCPs. One command to install MCPs across all your editors and agents

JWT

Authenticate using JSON Web Tokens (JWT) for external services

Beta

The Neon Auth with Better Auth is in Beta. Share your feedback on Discord or via the Neon Console.

Neon Auth is built on Better Auth and provides support for JWT plugin APIs through the Neon SDK. You do not need to manually install or configure the Better Auth JWT plugin.

While Neon Auth primarily relies on secure, HTTP‑only cookies (sessions) for browser‑based authentication, certain scenarios require a raw token. In these cases, the JWT plugin is especially useful:

  • Microservices: Sharing identity between backend services.
  • Separate frontend and backend domains: Authenticating API requests from a domain different than your main application.
  • CLI tools: Enabling authentication from the command‑line interface.

Sessions vs. JWTs

This plugin is not a replacement for session management in web applications. For standard browser-based apps (Next.js, React, Vue, etc.), rely on the default session cookie mechanism provided by authClient.signIn and authClient.getSession.

Only use JWTs when you specifically need to authorize requests to services that cannot access the browser's cookie jar.

Prerequisites

  • A Neon project with Auth enabled.

Retrieve a Token

You can retrieve a JWT for the currently signed-in user using the Neon SDK.

Using the SDK method

To fetch a raw token string, use the authClient.token() method. This is the recommended approach for client applications that need to attach a token to an API request header manually.

src/get-token.ts
import { authClient } from './auth';

export async function getJwtToken() {
  const { data, error } = await authClient.token();

  if (error) throw error;

  // The token string (e.g., "eyJhbGciOiJFZ...")
  return data.token;
}

Using the session header

When you call authClient.getSession(), Neon Auth automatically includes a JWT in the response headers. If you are using a custom fetcher or need to intercept the token immediately after a session check:

await authClient.getSession({
  fetchOptions: {
    onSuccess: (ctx) => {
      const jwt = ctx.response.headers.get('set-auth-jwt');
      console.log('JWT:', jwt);
    },
  },
});

Example decoded JWT payload

A typical decoded JWT payload looks like this:

{
  "iat": 1766320685,
  "name": "User Name",
  "email": "user@email.com",
  "emailVerified": false,
  "image": null,
  "createdAt": "2025-12-20T11:04:41.437Z",
  "updatedAt": "2025-12-20T11:04:41.437Z",
  "role": "authenticated",
  "banned": false,
  "banReason": null,
  "banExpires": null,
  "id": "860dc360-609f-4b7d-9e70-ec93fe6414d3",
  "sub": "860dc360-609f-4b7d-9e70-ec93fe6414d3",
  "exp": 1766321585,
  "iss": "<YOUR_NEON_AUTH_URL_ORIGIN>",
  "aud": "<YOUR_NEON_AUTH_URL_ORIGIN>"
}

Verify a token

To verify the authenticity of a JWT, you need to validate its signature using the public keys provided by JWKS (JSON Web Key Set).

Neon Auth exposes a public JWKS endpoint that contains the public keys necessary to verify the signature of your JWTs.

The JWKS endpoint

Your Neon Auth JWKS endpoint is located at:

<YOUR_NEON_AUTH_URL>/.well-known/jwks.json

Verification example

The following examples demonstrate how to verify a Neon Auth JWT in several programming languages. No matter which language you use, the process is the same: fetch the JWKS from the provided endpoint and use it to validate the token’s signature and claims. If your preferred language isn’t included here, you can apply these same principles in your own environment.

Production Readiness

The following examples are provided for reference only and are not guaranteed to be production‑ready. Be sure to implement proper caching, error handling, and security best practices as required for your application.

  1. Install the library:

    npm install jose
  2. Use the following example code as a reference to verify a JWT:

    import { jwtVerify, createRemoteJWKSet } from 'jose';
    
    const NEON_JWKS_URL = `${process.env.NEON_AUTH_BASE_URL}/.well-known/jwks.json`;
    const JWKS = createRemoteJWKSet(new URL(NEON_JWKS_URL));
    
    export async function validateNeonToken(token: string) {
        try {
            const { payload } = await jwtVerify(token, JWKS, {
                issuer: new URL(process.env.NEON_AUTH_BASE_URL!).origin
            });
    
            return payload;
        } catch (error) {
            console.error('Token validation failed:', error);
            return null;
        }
    }
    
    validateNeonToken(<YOUR_JWT_TOKEN>).then((payload) => {
        console.log('Token is valid. Payload:', payload);
    }).catch(() => {
        console.log('Token is invalid.');
    });

    Replace <YOUR_JWT_TOKEN> with the actual JWT token you want to verify.

Limitations

Because Neon Auth is a managed service, certain server-side configurations available in the standalone Better Auth library are pre-configured by Neon and cannot be changed:

  • Signing algorithm: Neon Auth uses EdDSA (Ed25519) by default for high security and performance. Ensure your verification libraries support this algorithm.
  • Expiration: Tokens expire in 15 minutes (access tokens). You should implement logic to refresh the token using authClient.token() when it expires.
  • Custom claims: Currently, the JWT payload contains the default user information. Custom claims are not supported at this time.

Troubleshooting

Token rejection

If a token is rejected during verification, check the following:

  1. Verify that you are using the correct JWKS endpoint for your Neon Auth instance. The issuer of the token must match the origin of your Neon Auth URL. (e.g., if your Neon Auth URL is https://ep-xx.aws.neon.tech/neondb/auth, the issuer should be https://ep-xx.aws.neon.tech).
  2. Confirm that your verification library supports EdDSA (Ed25519).
  3. Make sure the token has not expired.
  4. Check that the kid in the JWT header matches one of the keys in the JWKS response. If not, fetch the latest keys from the JWKS endpoint.

Need help?

Join our Discord Server to ask questions or see what others are doing with Neon. For paid plan support options, see Support.

Last updated on

Was this page helpful?