CI/CD 2026-03-10

Automate JWT Token Validation in CI/CD Testing Pipelines

Automate JWT token validation in GitHub Actions integration tests. Verify claims, check expiry, and assert token structure without a running auth server.

⚙️ Uses: JWT Decoder — Free

The Problem

Your integration tests call an auth endpoint, receive a JWT token, and need to verify it contains the right claims (user ID, role, expiry) before calling downstream APIs. Writing JWT parsing code in every test suite is tedious and error-prone.

Why This Matters

Testing JWT claims in CI catches auth bugs before they reach production. A missing <code>role</code> claim or wrong <code>aud</code> audience value causes authorization failures that are hard to debug in staging. Automating this check in your pipeline gives you confidence that every merge passes auth contract tests.

Step-by-Step Instructions

1

Decode a sample token using the tool below

Paste a JWT from your auth endpoint into the decoder. Inspect the payload structure to identify which claims your tests should assert: sub, role, aud, exp.

2

Add a JWT claim assertion step using Node.js

In your workflow, use node -e with a one-liner that base64-decodes the payload and checks fields. No JWT library required — just JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString()).

3

Assert required claims are present and correct

Check payload.role === 'admin', payload.exp > Date.now()/1000, and any custom claims your API depends on. Fail the job with process.exit(1) if assertions fail.

4

Use the token for downstream API calls

After validation, pass the token to subsequent steps as a step output. Use it in curl commands or API test frameworks as Authorization: Bearer $TOKEN.

Try It Now — JWT Decoder

Open full page →
JWT Decoder — Live Demo

All processing happens in your browser — no data is sent to any server.

Before & After Example

Problem: JWT returned from auth endpoint — claims not verified
- name: Get auth token
  run: |
    TOKEN=$(curl -s -X POST https://auth.example.com/token \
      -d '{"client_id":"ci-bot","client_secret":"${{ secrets.CLIENT_SECRET }}"}' \
      | jq -r '.access_token')
    echo "token=$TOKEN" >> $GITHUB_OUTPUT
    # ⚠️ Token stored but claims never verified
    # Will downstream tests fail with 403 due to wrong role?
Solution: decode and assert JWT claims before using the token
- name: Get and validate auth token
  id: auth
  run: |
    RESPONSE=$(curl -s -X POST https://auth.example.com/token \
      -H 'Content-Type: application/json' \
      -d '{"client_id":"ci-bot","client_secret":"${{ secrets.CLIENT_SECRET }}"}')

    TOKEN=$(echo "$RESPONSE" | jq -r '.access_token')

    if [ "$TOKEN" = "null" ] || [ -z "$TOKEN" ]; then
      echo "Failed to obtain token"
      echo "$RESPONSE" | jq .
      exit 1
    fi

    # Decode and validate JWT claims (no library needed)
    node -e "
      const token = '$TOKEN';
      const payload = JSON.parse(Buffer.from(token.split('.')[1], 'base64url').toString());

      console.log('Token claims:', JSON.stringify(payload, null, 2));

      // Assert required claims
      if (!payload.sub) { console.error('Missing sub claim'); process.exit(1); }
      if (payload.exp < Date.now() / 1000) { console.error('Token already expired'); process.exit(1); }
      if (!['admin', 'ci-bot'].includes(payload.role)) {
        console.error('Wrong role: ' + payload.role); process.exit(1);
      }
      console.log('✓ JWT claims valid');
    "

    echo "token=$TOKEN" >> $GITHUB_OUTPUT

- name: Call protected API
  run: |
    curl -s -H "Authorization: Bearer ${{ steps.auth.outputs.token }}" \
      https://api.example.com/protected | jq .

Frequently Asked Questions

How do I decode a JWT without installing any npm packages?

JWT payloads are base64url-encoded JSON. In Node.js: JSON.parse(Buffer.from(token.split('.')[1], 'base64url').toString()). In Python: import base64, json; json.loads(base64.b64decode(token.split('.')[1] + '==')).

Should I verify the JWT signature in CI?

For testing your own auth service, verifying the signature proves the token was issued by your server. Use jsonwebtoken (Node) or PyJWT (Python) with your public key. For third-party tokens (Auth0, Cognito), use their provided JWKS endpoint.

How do I handle JWT rotation in long CI runs?

Tokens expire. For workflows longer than the token TTL, re-fetch the token before each API call, or use a refresh token flow. Store the expiry from the exp claim and conditionally refresh.

Related Workflows

Want the full JWT Decoder experience?

Open the standalone tool for more space, keyboard shortcuts, and additional features.

Open JWT Decoder →

Related Workflow Guides