Skip to content

ID Token Audience Validation — Verifying the Recipient of a JWT

DodaTech Updated 2026-06-28 4 min read

In this tutorial, you will learn about ID Token Audience Validation. We cover key concepts, practical examples, and best practices to help you master this topic.

Audience validation verifies that the aud (audience) claim in an ID token matches your application's client_id, ensuring the token was intended for your app and not intercepted from another service.

What You'll Learn

  • What the audience claim is and why it matters for security
  • How to validate the aud claim in an ID token
  • Common audience validation errors and how to fix them

Why It Matters

Without audience validation, a token issued for one app can be used against another. If a malicious app intercepts a token meant for Doda Browser, that token should not grant access to Doda's backend services. The aud claim prevents this by binding the token to a specific recipient.

Real-World Use

Doda Browser uses OIDC to authenticate users. When the browser receives an ID token from the provider, the backend verifies the aud claim equals Doda Browser's client_id. This ensures a token generated for a different application cannot authenticate against Doda's APIs.

flowchart LR
    A["OIDC Provider"] -->|"ID Token with aud=client_id"| B["Your App"]
    B --> C{"Does aud match\nmy client_id?"}
    C -->|Yes| D["Accept Token"]
    C -->|No| E["Reject Token\nInvalid Audience"]
    style D fill:#bbf7d0,stroke:#16a34a
    style E fill:#fecaca,stroke:#dc2626

The Audience Claim Structure

The aud claim in an ID token is a string or array of strings identifying the intended recipients:

{
  "iss": "https://accounts.google.com",
  "sub": "1234567890",
  "aud": "your-client-id-12345.apps.googleusercontent.com",
  "exp": 1719876543,
  "iat": 1719872943
}

Each principal in the aud claim must be a valid OAuth2 client_id registered with the provider.

How Audience Validation Works

When your application receives an ID token, it must verify the aud claim contains its own client_id. If the token has multiple audiences, the server must also check for an azp (authorized party) claim.

import jwt
import requests

# Fetch JWKS from the OIDC provider
jwks_uri = "https://accounts.example.com/.well-known/jwks.json"
jwks = requests.get(jwks_uri).json()

# Decode and verify the ID token
def verify_id_token(token, expected_client_id, jwks):
    try:
        header = jwt.get_unverified_header(token)
        key = next(k for k in jwks["keys"] if k["kid"] == header["kid"])
        payload = jwt.decode(
            token,
            key,
            algorithms=["RS256"],
            audience=expected_client_id,
            issuer="https://accounts.example.com"
        )
        return payload
    except jwt.InvalidAudienceError:
        raise ValueError("Token audience does not match client_id")
    except Exception as e:
        raise ValueError(f"Token verification failed: {e}")

# Usage
token = "eyJhbGciOiJSUzI1NiIsImtpZCI6IjEifQ..."
client_id = "your-client-id-12345.apps.googleusercontent.com"
claims = verify_id_token(token, client_id, jwks)
print(f"Authenticated user: {claims['sub']}")

Expected output:

Authenticated user: 1234567890

Multiple Audiences

Some providers issue tokens with multiple audiences. In this case, your application must check if its client_id appears in the array:

payload = jwt.decode(
    token,
    key,
    algorithms=["RS256"],
    audience=expected_client_id,
    issuer="https://accounts.example.com"
)
# When aud is an array, pyjwt checks membership automatically

If the token has multiple audiences and your client_id is one of them, you must also verify the azp claim if present. The azp identifies the party that requested the token.

Common Mistakes

1. Skipping Audience Validation Entirely

Many developers verify the signature and issuer but forget the audience. This allows token reuse across applications. Always validate aud.

2. Using String Comparison Instead of Array Membership

When aud is an array, comparing it directly to your client_id fails. Use the JWT library's built-in audience validation which handles both string and array formats.

3. Ignoring the azp Claim

For multi-audience tokens, the azp identifies the authorized party. If your app is not the azp, you may need additional validation logic.

4. Hardcoding Audience Values

Audience values change between environments (dev, staging, production). Load the expected client_id from environment configuration, not hardcoded strings.

5. Case-Sensitive Comparison

Audience values are case-sensitive. A mismatch of even one character causes validation failure. Log the received aud value during debugging to spot casing issues.

Practice Questions

  1. What does the aud claim represent in an ID token?
  2. How do you validate the audience using the PyJWT library?
  3. What is the azp claim and when should you check it?
  4. Why is audience validation important for security?
  5. What happens if you skip audience validation?

Answers

  1. The aud claim identifies the intended recipient(s) of the token, typically the application's client_id. 2. Pass the audience=client_id parameter to jwt.decode(). 3. The azp identifies the authorized party when the token has multiple audiences. 4. It prevents token reuse across different applications. 5. A malicious app could use a token meant for another app to gain unauthorized access.

Challenge

Build a token validation function that handles single audience strings, multi-audience arrays, azp verification, and returns a clear error message for each failure case. Test with valid tokens, tokens with wrong audience, and tokens with mismatched azp.

FAQ

What is the audience claim?

The audience (aud) claim identifies who the ID token is intended for. It must match your application's client_id.

Can an ID token have multiple audiences?

Yes. The aud claim can be an array of strings. Your app must verify its client_id is in the array.

What is the azp claim?

The azp (authorized party) claim identifies the party that requested the token, used when the token has multiple audiences.

Does audience validation prevent token replay?

Yes, because a token with aud set to App A will be rejected by App B, preventing replay across applications.

Which libraries support audience validation?

PyJWT, python-jose, jsonwebtoken (Node.js), and most JWT libraries support audience validation via an audience parameter.

Mini Project

Create an audience validation middleware for a Flask application that decodes incoming ID tokens, verifies the audience matches the app's client ID, and returns 401 Unauthorized with a descriptive error message if validation fails.

What's Next

  • Learn how the sub claim provides a unique user identifier
  • Explore the preferred_username claim for display names
  • Continue to ID Token Claims for a complete claim reference

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro