Istio’s JWT and OIDC authentication is less about proving who a user is and more about verifying that a trusted third party has already proven it.

Let’s see what this looks like in practice. Imagine a user trying to access your frontend service, which is protected by Istio.

apiVersion: security.istio.io/v1beta1
kind: RequestAuthentication
metadata:
  name: frontend-jwt
  namespace: default
spec:
  selector:
    matchLabels:
      app: frontend
  jwtRules:
  - issuer: "https://accounts.google.com"
    jwksUri: "https://www.googleapis.com/oauth2/v3/certs"

This RequestAuthentication policy tells Istio to expect a JWT in the Authorization: Bearer <token> header for requests targeting the frontend service. It also specifies that this JWT should be issued by https://accounts.google.com and that Istio can fetch the public keys (JWKS) needed to verify the token’s signature from https://www.googleapis.com/oauth2/v3/certs.

When a request comes in, Istio’s Envoy proxy intercepts it. It looks for the Authorization header. If present, it extracts the JWT and does a few things:

  1. Verifies the signature: It fetches the public keys from the jwksUri and uses them to confirm the JWT hasn’t been tampered with.
  2. Checks the issuer (iss claim): It ensures the token was actually issued by the expected identity provider (https://accounts.google.com in this case).
  3. Checks the audience (aud claim, optional): If configured, it verifies that the token was intended for your application.
  4. Checks expiration (exp claim): It makes sure the token hasn’t expired.
  5. Checks not-before (nbf claim, optional): If present, it ensures the token is valid now.

If all these checks pass, Istio trusts the claims within the JWT, such as the user’s ID (sub claim) and any roles or scopes, and allows the request to proceed to the frontend service. If any check fails, Istio returns a 401 Unauthorized response.

The "OIDC" part comes into play because JWTs are often issued as part of the OpenID Connect flow. When a user logs into an OIDC provider (like Google, Auth0, Keycloak), the provider authenticates them and then issues a JWT. This JWT is what the user’s client application includes in requests to your services. Your Istio mesh, by validating this JWT, effectively trusts the OIDC provider’s authentication.

The AuthorizationPolicy is where you actually enforce access based on the validated JWT claims.

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: frontend-authz
  namespace: default
spec:
  selector:
    matchLabels:
      app: frontend
  action: ALLOW
  rules:
  - from:
    - source:
        principals: ["https://accounts.google.com/"] # Matches the issuer
    when:
    - key: request.auth.claims[email]
      values: ["user@example.com"]

This policy says: "For the frontend service, allow requests (action: ALLOW) only if the request is authenticated with a JWT whose issuer principal is https://accounts.google.com/ AND the email claim within that JWT is exactly user@example.com."

The principals field in AuthorizationPolicy is a bit of a misnomer; it’s matching the iss (issuer) claim from the validated JWT, not a subject principal. This is a common point of confusion.

The real power is in combining RequestAuthentication and AuthorizationPolicy. RequestAuthentication handles the verification of the token’s integrity and origin, populating request.auth.claims for downstream policies. AuthorizationPolicy then uses these claims to make granular access control decisions.

One of the most subtle aspects is how Istio constructs the request.auth.claims object. It’s not just the standard JWT claims (iss, sub, aud, exp, iat). Any custom claims present in the JWT payload are also directly accessible via request.auth.claims[claim_name]. This means your OIDC provider can inject custom attributes like groups, roles, or user-specific IDs, and you can use them directly in your AuthorizationPolicy rules without needing a separate service to inspect the token.

This mechanism allows you to offload complex authentication logic to specialized identity providers and focus your mesh on secure, policy-driven authorization.

The next logical step is often to implement more sophisticated authorization rules, perhaps allowing access based on JWT claims that indicate membership in specific groups.

Want structured learning?

Take the full Istio course →