---
title: Validate JSON web tokens (JWT)
description: Extract a JWT from the Authorization header, verify its HMAC-SHA256 signature using the WebCrypto API, and validate its claims.
image: https://developers.cloudflare.com/core-services-preview.png
---

> Documentation Index  
> Fetch the complete documentation index at: https://developers.cloudflare.com/rules/llms.txt  
> Use this file to discover all available pages before exploring further. 

[Skip to content](#%5Ftop) 

# Validate JSON web tokens (JWT)

Extract a JWT from the Authorization header, verify its HMAC-SHA256 signature using the WebCrypto API, and validate its claims.

Caution when using in production

The example code contains a placeholder HMAC secret of `"mysecretsymmetrickey"`. To best protect your resources, change the secret to a strong, unique value in the Snippets editor before saving your code.

JavaScript

```
export default {  async fetch(request) {    const HMAC_SECRET = "mysecretsymmetrickey"; // Change this to your secret key    const CLOCK_TOLERANCE = 30; // Tolerance for clock skew in seconds
    // Extract JWT token from "Authorization: Bearer" header    function getJWTToken(request) {      const authorizationHeader = request.headers.get("Authorization");      if (authorizationHeader && authorizationHeader.startsWith("Bearer ")) {        return authorizationHeader.substring(7, authorizationHeader.length);      }      return null;    }
    // Convert a base64url string to a Uint8Array    function base64urlToUint8Array(base64url) {      const base64 = base64url        .replace(/-/g, "+")        .replace(/_/g, "/")        .padEnd(base64url.length + ((4 - (base64url.length % 4)) % 4), "=");      const binary = atob(base64);      return Uint8Array.from(binary, (c) => c.charCodeAt(0));    }
    // Decode a base64url-encoded JWT segment to a JSON object    function decodeSegment(s) {      const bytes = base64urlToUint8Array(s);      return JSON.parse(new TextDecoder().decode(bytes));    }
    // Validate JWT token structure, cryptographic signature, and claims.    async function validateJWT(token) {      const parts = token.split(".");      if (parts.length !== 3) {        throw new Error("Invalid JWT format");      }
      const [headerB64, payloadB64, signatureB64] = parts;      const decodedHeader = decodeSegment(headerB64);      const decodedPayload = decodeSegment(payloadB64);
      // Verify the algorithm.      // This prevents algorithm-confusion attacks where an attacker changes the "alg" header to bypass signature verification.      // Never branch on the token's alg header to decide how to verify.      // Always enforce the algorithm you expect.      if (decodedHeader.alg !== "HS256") {        throw new Error("Unsupported algorithm");      }
      // Verify the cryptographic signature.      // Import the shared secret as an HMAC-SHA256 key, then verify that the signature matches "header.payload".      // If this fails, the token was tampered with or signed with a different key.      const signature = base64urlToUint8Array(signatureB64);      const data = new TextEncoder().encode(`${headerB64}.${payloadB64}`);      const key = await crypto.subtle.importKey(        "raw",        new TextEncoder().encode(HMAC_SECRET),        { name: "HMAC", hash: "SHA-256" },        false,        ["verify"],      );      const valid = await crypto.subtle.verify(        { name: "HMAC" },        key,        signature,        data,      );
      if (!valid) {        throw new Error("Invalid signature");      }
      // Validate standard claims.      // The claims a JWT must contain depends on your use case.      const now = Math.floor(Date.now() / 1000);
      // exp (expiration): Reject tokens that have expired.      // A small clock tolerance accounts for clock skew between servers.      if (typeof decodedPayload.exp !== "number") {        throw new Error("Missing exp claim");      }      if (decodedPayload.exp < now - CLOCK_TOLERANCE) {        throw new Error("JWT has expired");      }
      // iat (issued at): Ensure the token declares when it was created.      if (typeof decodedPayload.iat !== "number") {        throw new Error("Missing iat claim");      }
      // Additional claims per RFC 7519 (https://www.rfc-editor.org/rfc/rfc7519.html):      // - nbf (not before): Reject tokens used before their valid start time.      //     if (decodedPayload.nbf > now + CLOCK_TOLERANCE) throw new Error("JWT is not yet valid");      // - iss (issuer): Ensure the token was issued by a trusted authority.      //     if (decodedPayload.iss !== "https://auth.example.com") throw new Error("Invalid issuer");      // - aud (audience): Ensure the token is intended for your service.      //     if (decodedPayload.aud !== "my-api") throw new Error("Invalid audience");      // - sub (subject): Identify the principal the token refers to.      // - jti (JWT ID): Unique token identifier, useful for preventing replay attacks.
      return true;    }
    // Execute the function to extract JWT token    const jwtToken = getJWTToken(request);
    // If the token is not provided, serve 401 Forbidden    if (!jwtToken) {      return new Response("Missing JWT token", { status: 401 });    }
    try {      // If the token is valid, the validateJWT function will not error and serve the actual response      // An example of a valid token that will expire in 2033 is "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNjI0OTkyMDAwLCJleHAiOjIwMDExMjAwMDB9._qgQ_TMrGfYgOoA8HtTZwEGoj8zAPWxsz8CT1jEAGzo"      await validateJWT(jwtToken);      return fetch(request);    } catch {      return new Response("Invalid JWT token", { status: 401 });    }  },};
```

```json
{"@context":"https://schema.org","@type":"TechArticle","@id":"https://developers.cloudflare.com/rules/snippets/examples/jwt-validation/#page","headline":"Validate JSON web tokens (JWT) · Cloudflare Rules docs","description":"Extract a JWT from the Authorization header, verify its HMAC-SHA256 signature using the WebCrypto API, and validate its claims.","url":"https://developers.cloudflare.com/rules/snippets/examples/jwt-validation/","inLanguage":"en","image":"https://developers.cloudflare.com/core-services-preview.png","dateModified":"2026-04-20","publisher":{"@type":"Organization","name":"Cloudflare","url":"https://www.cloudflare.com/"},"isPartOf":{"@type":"WebSite","@id":"https://developers.cloudflare.com/#website","name":"Cloudflare Docs","url":"https://developers.cloudflare.com/"},"keywords":["Authentication","Request modification"]}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/rules/","name":"Rules"}},{"@type":"ListItem","position":3,"item":{"@id":"/rules/snippets/","name":"Cloudflare Snippets"}},{"@type":"ListItem","position":4,"item":{"@id":"/rules/snippets/examples/","name":"Snippets examples"}},{"@type":"ListItem","position":5,"item":{"@id":"/rules/snippets/examples/jwt-validation/","name":"Validate JSON web tokens (JWT)"}}]}
```
