Streamline authorization by leveraging JWT claims in Cerbos

Published by Alex Olivier on October 29, 2025
Streamline authorization by leveraging JWT claims in Cerbos

Cerbos has native JWT support. It can ingest a bearer token from the authorization request, verify it against your keysets if you provide them, and expose the verified claims under request.auxData.jwt for use in policy conditions. This removes the need to parse tokens in each caller and copy claims into the request payload.

Cutting JWT parsing from app code reduces boilerplate and avoids subtle bugs around time skew, algorithm selection, and issuer confusion.

 

How JWT verification works in Cerbos

Cerbos checks the token signature using a configured key set, validates the expiry and not-before times, and rejects tokens that fail verification. You can load keys from a remote JWKS URL or from local files. The engine exposes claims to policies through request.auxData.jwt.

Using the standard JWT and JWK specifications ensures compatibility with common identity providers.

Why this matters: Credentials remain a leading initial action in breaches. The 2024 Verizon DBIR shows use of stolen credentials as the top initial action at 24 percent. Tight verification of issuer, audience, and signature helps reduce risk.

 

How to configure JWKS and caching

Add an auxData.jwt block to your Cerbos configuration. You can mix remote and local keysets. Cerbos respects HTTP cache headers from your JWKS endpoint, or you can set a refresh interval. (AuxData block documentation.)

# cerbos.yaml
auxData:
  jwt:
    cacheSize: 256
    keySets:
      - id: default
        remote:
          url: https://idp.example.com/.well-known/keys.jwks
          refreshInterval: 1h
      - id: backup
        local:
          file: /etc/cerbos/keys/backup.jwks

When multiple keysets are configured, you can indicate the keyset to use in your request. With only one key set, the id is optional.

 

How to use JWT claims in policy conditions

Once enabled, claims are available through request.auxData.jwt in CEL expressions as long as the provided token is valid. You can combine them with principal and resource attributes.

# resource policy snippet
rules:
  - actions: ["read"]
    effect: EFFECT_ALLOW
    condition:
      match:
        all:
          of:
            - expr: request.auxData.jwt.iss == "https://idp.example.com"
            - expr: "payments-api" in request.auxData.jwt.aud
            - expr: P.id == request.auxData.jwt.sub

This pattern enforces issuer, audience, and subject consistency without custom code in the application.

The application layer, which calls the Cerbos PDP provides the token in the request:

{
 "principal": {
   "id": "alice",
   "roles": [
     "employee"
   ],
   "attr": {
     "department": "accounting"
  
   }
 },
 "resources": [
   {
     "resource": {
       "id": "XX125",
       "kind": "leave_request",
       "attr": {
         "department": "accounting",
       }
     },
     "actions": [
       "approve"
     ]
   }
 ],
 "auxData": {
   "jwt": {
       "token": "xxx.yyy.zzz",
       "keySetId": "ks1"
   }
 }
}

 

How to handle multiple issuers and key rotation

Define several keysets and select the correct one per request. For providers that rotate signing keys, rely on the JWKS endpoint and either set a refresh interval or let Cerbos honor HTTP cache headers. This keeps keys fresh without restarts.

If you are migrating from legacy tokens with odd header fields, keep strict verification in production and only relax checks during controlled tests.

 

How this fits with gateways

At the edge, your gateway can pass the original Authorization header through to downstream services. A sidecar or nearby Cerbos PDP reads the token, verifies it, and enforces route or resource rules consistently.

What we have seen: Teams standardize on OIDC, yet still duplicate JWT parsing in each service. Centralizing verification and using claims in policies reduces drift and simplifies audits.

 

What are typical mistakes, and how do we avoid them

  • Skipping audience checks. Always check aud or a custom claim in addition to the signature and expiry.
  • Forgetting clock skew. Configure a small acceptable skew if your IdP and PDP clocks differ.
  • Hard-coding keys. Prefer JWKS with rotation and cache controls.

 

When to disable verification

Cerbos allows disabling signature verification for migration or testing. Even then, expiry and not before are still evaluated. Keep verification enabled in production.

 

Cerbos native JWT vs app side extraction vs a bespoke PIP

  • Cerbos' native JWT is a built-in verifier and claims bridge. It gives consistent verification, less boilerplate, and policy-level access to claims.
  • App side extraction copies claims from decoded tokens into the request. It works, but duplicates logic and risks inconsistent checks across services.
  • A bespoke PIP (Policy Information Point) is a separate service that transforms tokens into attributes. It is flexible, but it adds another hop and extra moving parts.

Verdict: Start with Cerbos native JWT for most cases. Add a PIP only when you need additional enrichment that cannot come from the token.

 


Key takeaways

  • Cerbos verifies JWTs using your JWKS and exposes claims directly to policy conditions.
  • You can configure multiple keysets, cache verified tokens, and handle rotation without restarts.
  • Claims like iss, aud, and sub can be enforced centrally in CEL expressions.
  • Gateways can pass tokens through; one policy set covers edge and service.
  • Stolen credentials remain a top initial action in breaches at 24 percent in 2024. Strong token verification helps reduce risk.
  • Disable verification only for controlled testing, not for production.

FAQ

Can Cerbos verify JWTs natively?

How do I point Cerbos at my JWKS?

Book a free Policy Workshop to discuss your requirements and get your first policy written by the Cerbos team