Zero Trust gets thrown around as a marketing term so often that it’s easy to lose sight of what it actually changes architecturally. At its core, it’s a shift in where you place trust: instead of the network edge (is this traffic coming from inside the VPN?), you trust identity (who is making this request, and can they prove it?).

That shift puts three things at the center of your architecture: an Identity Provider (IDP), OAuth2, and JWTs. They are distinct tools that get conflated constantly. Here’s how they actually fit together.

Authentication vs. authorization

Before going further, these two terms appear together constantly and get conflated just as often.

Authentication (AuthN) answers who are you? It’s the process of verifying identity. A password check, an MFA challenge, a passkey assertion, a client certificate — all are authentication mechanisms. The output is a confirmed identity claim.

Authorization (AuthZ) answers what are you allowed to do? It takes a verified identity as input and returns an allow-or-deny decision based on policy. Whether a user can read an S3 bucket, call an API endpoint, or access a specific service — those are authorization decisions.

They’re sequential and distinct: authorization is meaningless without authentication first, and authentication alone grants access to nothing. A user who has completed MFA has authenticated. What they can actually do is entirely a separate question.

In a Zero Trust architecture, both happen continuously and explicitly on every request. Your IDP handles authentication. OAuth2 scopes, role claims in JWTs, and policy engines like OPA or Cedar handle authorization. The rest of this post covers how each piece works.

The IDP is the new perimeter

In a traditional perimeter model, the firewall was the trust anchor. Once traffic was inside the network, it was mostly trusted. That model breaks the moment you have remote workers, SaaS apps, and cloud workloads — which is to say, it broke about a decade ago.

In a Zero Trust model, the IDP takes that role. It’s the authoritative source of identity: it authenticates users and devices, evaluates contextual signals (device posture, location, risk score), and issues credentials that downstream services can verify without calling home on every request. Okta, Entra ID, and Google Cloud Identity are the most common enterprise IDPs, but the role is the same regardless of vendor.

The key change is that the IDP no longer operates as a one-time gate at login. It becomes a continuous checkpoint — tokens expire, policies change, sessions can be revoked. Every access decision is grounded in a fresh, verifiable identity assertion rather than “this client is on the corporate network, so it’s fine.”

OAuth2 is authorization, not authentication

This one trips people up constantly. OAuth2 is a delegation protocol. It answers the question “what can this application do on behalf of this user?” — not “who is this user?”

The flow most people encounter is the Authorization Code flow: you click “Log in with Google”, get redirected to Google, authenticate there, and come back to the application with an authorization code. The app’s backend exchanges that code for tokens via a direct server-to-server call — the access token never touches the browser. The authentication happened at the IDP (Google). OAuth2 is the protocol that formalized the handoff — the application never saw your password, and it received a scoped token that limits what it can do.

For authentication — establishing who the user is — you need OpenID Connect (OIDC), which is a thin layer built on top of OAuth2. OIDC adds an ID token alongside the access token. The ID token contains claims about the user (their identity). The access token is what you use to call APIs.

The practical implication: if you’re building a service that needs to know who a caller is, validate the ID token or use OIDC’s userinfo endpoint. If you’re protecting an API, validate the access token. Don’t use an access token to authenticate a user.

JWTs are self-contained claim bearers

An access token can be opaque (a random string the authorization server looks up in a database) or a JWT (a self-contained document with claims, signed by the IDP). Most modern systems use JWTs for access tokens because the resource server can validate them locally — no round-trip to the IDP on every request.

A JWT has three parts (base64url-encoded, dot-separated): a header identifying the algorithm, a payload containing claims, and a signature. The signature is what makes it verifiable — the resource server fetches the IDP’s public keys from the JWKS endpoint and cryptographically checks that the token wasn’t tampered with and came from the expected issuer.

The claims that matter most in a Zero Trust context:

Claim What it is
iss Issuer — which IDP signed this token
sub Subject — the user or workload identifier
aud Audience — which service(s) this token is valid for
exp Expiration — when the token stops being valid
scope What the token is authorized to do (RFC 9068; Entra historically used scp, an array variant)
groups / roles For attribute-based access decisions

A few things to validate correctly: always check iss and aud together with the signature. sub is unique within a given issuer (or globally, depending on the issuer) — user 12345 at Okta and user 12345 at Entra are different people. Key on iss+sub, not sub alone. And verify the signature against the JWKS endpoint, not a hardcoded public key you copied somewhere.

The downside of JWTs is revocation. Because they’re stateless, a token remains valid until it expires even if the user logs out or their account is disabled. The mitigation is short expiration windows — minutes, not hours — paired with refresh tokens. This is increasingly the default in well-configured Zero Trust deployments.

How they fit together

The flow in practice:

  1. User authenticates to the IDP (password + MFA, passkey, etc.)
  2. IDP issues an access token (JWT) scoped to a specific resource, with claims encoding identity and permissions
  3. Client presents the JWT to the resource server in the Authorization: Bearer header
  4. Resource server validates the JWT signature, checks iss, aud, exp, and evaluates the scopes and role claims
  5. Access granted — or denied — based on policy

The network doesn’t factor into the trust decision. A request from the corporate office and a request from a coffee shop go through the same path: present a valid, unexpired, correctly scoped JWT from a trusted issuer.

What’s evolving

A few things worth knowing as the space matures:

DPoP (RFC 9449) addresses token replay attacks. Normally, if an attacker intercepts your JWT, they can use it until it expires. DPoP binds the token to a client-generated key pair — the client attaches a signed proof with each request, making the token useless without the corresponding private key. Okta and Auth0 both support it natively.

SPIFFE/SPIRE solves the same problem for workloads that OAuth2 solves for users. Containers, microservices, and VMs can’t authenticate with passwords. SPIFFE provides a standard for issuing cryptographically verifiable identities to workloads at runtime, based on attested environmental properties, with automatic rotation. No static API keys buried in config.

Short-lived ephemeral credentials are the broader trend. Static API keys and long-lived tokens are incompatible with Zero Trust — they persist for months and create a large blast radius if compromised. The direction is just-in-time tokens that expire in minutes, issued on demand by an IDP or SPIRE node. Managing the full secret lifecycle — storage, rotation, and revocation — is covered in Understanding Secrets Manager Architecture.

The one-line version

Your IDP is the trust anchor. OAuth2 is the protocol for issuing and delegating access. JWTs are the signed, self-contained tokens that carry the claims your services use to make authorization decisions. Zero Trust doesn’t require magic — it requires that every component in that chain is correctly configured, continuously verified, and short-lived enough that compromise has limited blast radius.