Docs

Warning

This is a lower-level method intended for more advanced use-cases. It's recommended to use authenticateRequest(), which fully authenticates a token passed from the request object.

verifyToken()

Verifies a Clerk-generated token signature.

function verifyToken: (token: string, options: VerifyTokenOptions) => Promise<JwtReturnType<JwtPayload, TokenVerificationError>>;
  • Name
    token
    Type
    string
    Description

    The token to verify.

  • Name
    options
    Type
    VerifyTokenOptions
    Description

    Options for verifying the token.

Warning

You must provide either jwtKey or secretKey.

  • Name
    audience?
    Type
    string | string[]
    Description

    A string or list of audiences.

  • Name
    clockSkewInMs?
    Type
    number
    Description

    Specifies the allowed time difference (in milliseconds) between the Clerk server (which generates the token) and the clock of the user's application server when validating a token. Defaults to 5000 ms (5 seconds).

  • Name
    jwtKey?
    Type
    string
    Description

    The PEM Public Key from the API Keys page -> Show JWT public key -> PEM Public Key section of the Clerk Dashboard. It's recommended to use the environment variable instead.

  • Name
    secretKey?
    Type
    string
    Description

    The Clerk secret key from the API Keys page in the Clerk Dashboard.

  • Name
    skipJwksCache?
    Type
    boolean
    Description

    A flag to ignore the JWKS cache and always fetch JWKS before each JWT verification.

  • Name
    apiUrl?
    Type
    string
    Description

    The Clerk Backend API endpoint. Defaults to 'https://api.clerk.com'.

  • Name
    apiVersion?
    Type
    string
    Description

    The version passed to the Clerk API. Defaults to 'v1'.

Example

The following example demonstrates how to use the JavaScript Backend SDK to verify the token signature. Although this example uses Next.js Route Handlers, you can use verifyToken() with any JS framework or no framework at all.

In the following example:

  1. The JWT Public Key is set in the environment variable CLERK_JWT_KEY.
  2. The session token is retrieved from the __session cookie or the Authorization header.
  3. The token is verified using the verifyToken() method.
  4. The token's exp and nbf claims are checked.
  5. The token's azp claim is checked against the permitted origins. Verifying the azp claim on the server side ensures that the session token is generated from the expected frontend application. For example, if you are permitting tokens retrieved from http://localhost:3000, then the azp claim should equal http://localhost:3000.
  6. If the token is valid, the response contains the verified token.
import { verifyToken } from '@clerk/backend';
import { cookies } from 'next/headers';

export async function GET(request: Request) {
  const cookieStore = cookies()
  const sessToken = cookieStore.get('__session')?.value
  const bearerToken = request.headers.get('Authorization')?.replace('Bearer ', '');
  const token = sessToken || bearerToken;

  if (!token) {
    return Response.json({ error: 'Token not found. User must sign in.' }, { status: 401 });
  }

  try {
    const verifiedToken = await verifyToken(token, {
      jwtKey: process.env.CLERK_JWT_KEY,
    });

    // Check if the token is expired or not yet valid
    const currentTime = Math.floor(Date.now() / 1000);
    if (verifiedToken.exp < currentTime || verifiedToken.nbf > currentTime) {
      throw new Error("Token is expired or not yet valid");
    }

    // Check if the token is issued by a permitted origin
    const permittedOrigins = ["http://localhost:3000", "https://example.com"]; // Replace with your permitted origins
    if (verifiedToken.azp && !permittedOrigins.includes(verifiedToken.azp)) {
      throw new Error("Invalid 'azp' claim");
    }

    return Response.json({ verifiedToken });
  } catch (error) {
    return Response.json({ error: 'Token not verified.' }, { status: 401 });
  }
}

If the token is valid, the response will contain a JSON object that looks something like this:

{
  "verifiedToken": {
    "azp": "http://localhost:3000",
    "exp": 1687906422,
    "iat": 1687906362,
    "iss": "https://magical-marmoset-51.clerk.accounts.dev",
    "nbf": 1687906352,
    "sid": "sess_2Ro7e2IxrffdqBboq8KfB6eGbIy",
    "sub": "user_2RfWKJREkjKbHZy0Wqa5qrHeAnb"
  }
}

Feedback

What did you think of this content?