OAuth2, OIDC, JWTs, mTLS, and Service-to-Service Authentication

Topics Covered

OAuth 2.0 vs OpenID Connect: Authorization and Authentication

Authorization vs Authentication

The Four OAuth 2.0 Roles

Authorization Code Flow with PKCE

What OIDC Adds on Top of OAuth 2.0

Three Token Types

Client Credentials Flow for Machines

JSON Web Tokens (JWTs) in Authorization

JWT Structure

Signing Algorithms

Stateless Validation

The Revocation Problem

Token Bloat and Payload Visibility

Mutual TLS (mTLS) and Service-to-Service Authentication

How mTLS Works

X.509 Certificates and CA Trust Chains

Service Mesh Integration

SPIFFE and SPIRE for Workload Identity

Certificate Rotation Challenges

Service-to-Service Authentication in Practice

Defense in Depth: mTLS + JWT

OAuth 2.0 Client Credentials for Service Tokens

Cloud-Native Workload Identity

Workload Identity Federation

Key Trade-offs and Considerations

Stateless JWT vs Opaque Tokens

Token Lifetime Trade-offs

mTLS Operational Cost

When to Use Which

Summary Cheat Sheet

Protocol and Mechanism Comparison

Decision Tree

Key Principles

Common Interview Mistakes

Why do two standards exist when one seems like it should be enough? Because they solve fundamentally different problems. OAuth 2.0 answers "what is this application allowed to do?" OpenID Connect answers "who is the human using this application?" Confusing the two is one of the most common security mistakes in system design, and interviewers test for it directly.

Authorization vs Authentication

Authorization is about permissions. When you grant a third-party app access to your Google Drive files, OAuth 2.0 handles that. The app receives an access token scoped to specific permissions (read files, list folders) but learns nothing about who you are.

Authentication is about identity. When you click "Sign in with Google," the application needs to know your name, email, and user ID. OAuth 2.0 alone cannot provide this. OIDC extends OAuth 2.0 by adding an ID token — a signed JWT containing identity claims about the user.

The critical distinction: an access token proves what the bearer can do, not who the bearer is. An ID token proves who the user is, but should never be sent to resource servers as an authorization credential.

Key Insight

The most common security mistake in OAuth implementations is using access tokens as proof of identity. An access token says 'the bearer may read files' — it does not say 'the bearer is Alice.' If you need to know who the user is, you need OIDC and its ID token. If you only need to authorize API calls, OAuth 2.0 access tokens are sufficient.

The Four OAuth 2.0 Roles

Every OAuth 2.0 flow involves four actors:

  • Resource Owner — the user who owns the data (you, granting access to your photos)
  • Client — the application requesting access (the third-party photo editor)
  • Authorization Server — the service that authenticates the user and issues tokens (Google's auth server)
  • Resource Server — the API that holds the protected data (Google Photos API)

Understanding these roles matters because each role has different security responsibilities. The client never sees the user's password. The resource server validates tokens but never issues them. The authorization server is the single trust anchor for the entire system.

Authorization Code Flow with PKCE

The authorization code flow is the standard for web and mobile applications. PKCE (Proof Key for Code Exchange) is mandatory for public clients (SPAs, mobile apps) because they cannot securely store a client secret.

OAuth2 Authorization Code Flow with PKCE

The flow works in six steps:

  1. The client generates a random code_verifier and derives a code_challenge (SHA-256 hash)
  2. The client redirects the user to the authorization server with response_type=code, requested scopes, and the code_challenge
  3. The user authenticates and consents to the requested permissions
  4. The authorization server redirects back to the client with a short-lived authorization code
  5. The client exchanges the code plus the original code_verifier at the token endpoint
  6. The authorization server validates the verifier against the stored challenge and returns tokens

PKCE prevents interception attacks. Even if an attacker captures the authorization code (via a malicious redirect or browser history), they cannot exchange it without the code_verifier that only the legitimate client possesses.

What OIDC Adds on Top of OAuth 2.0

OIDC is not a separate protocol — it is a layer on top of OAuth 2.0. When the client includes openid in the requested scopes, the authorization server returns an ID token alongside the access token. The ID token is a JWT containing claims like:

  • sub — a unique, stable identifier for the user
  • email — the user's email address
  • name — the user's display name
  • iss — the issuer (which authorization server created this token)
  • aud — the audience (which client this token was issued for)
  • exp — expiration timestamp

Three Token Types

TokenPurposeAudienceLifetime
Access tokenAuthorize API callsResource serverShort (5-60 min)
ID tokenProve user identityClient applicationShort (5-60 min)
Refresh tokenObtain new access tokensAuthorization serverLong (hours to days)

The refresh token exists because access tokens are intentionally short-lived. When an access token expires, the client uses the refresh token to get a new one without forcing the user to log in again. Refresh tokens are stored securely server-side and can be revoked instantly — unlike access tokens, which remain valid until expiration.

Client Credentials Flow for Machines

When there is no human user — a cron job calling an API, a microservice authenticating to another microservice — the client credentials flow applies. The client sends its own client_id and client_secret directly to the authorization server and receives an access token. No browser redirects, no user consent, no ID token. This flow is the bridge between OAuth 2.0 and service-to-service authentication.

JWTs matter because they solve a specific infrastructure problem: how does a resource server validate an access token without calling the authorization server on every request? In a microservices architecture handling 50,000 requests per second, adding a network round-trip to validate each token doubles latency and turns the authorization server into a bottleneck. JWTs eliminate that round-trip by making tokens self-validating.

JWT Structure

A JWT is three base64url-encoded segments separated by dots: header.payload.signature.

 
1eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.
2eyJzdWIiOiJ1c2VyXzEyMyIsImlzcyI6Imh0dHBzOi8v
3YXV0aC5leGFtcGxlLmNvbSIsImF1ZCI6Im9yZGVycy1h
4cGkiLCJleHAiOjE3MDk0MDAwMDAsInNjb3BlIjoib3Jk
5ZXJzOnJlYWQgb3JkZXJzOndyaXRlIn0.
6dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk

Header specifies the signing algorithm and token type:

json
{"alg": "RS256", "typ": "JWT", "kid": "key-2024-03"}

Payload carries claims — assertions about the subject and their permissions:

json
1{
2  "sub": "user_123",
3  "iss": "https://auth.example.com",
4  "aud": "orders-api",
5  "exp": 1709400000,
6  "nbf": 1709396400,
7  "scope": "orders:read orders:write",
8  "roles": ["admin"]
9}

Key claims: sub (subject — who), iss (issuer — who created this), aud (audience — who should accept this), exp (expiration), nbf (not before), and custom claims like scope or roles for authorization decisions.

Signature is created by signing the header and payload with the issuer's private key. Anyone with the corresponding public key can verify the token was created by the trusted issuer and has not been tampered with.

Signing Algorithms

RS256 (RSA + SHA-256) uses asymmetric cryptography. The authorization server signs with a private key. Resource servers verify with the public key, available at a JWKS (JSON Web Key Set) endpoint. This is the default for production systems because resource servers never need the private key — they only need the public key, which is safe to distribute.

HS256 (HMAC + SHA-256) uses a shared secret. Both the signer and verifier use the same key. This is simpler but dangerous in distributed systems — every service that validates tokens must possess the signing secret, and any compromised service can forge tokens for any other service.

ES256 (ECDSA + SHA-256) uses elliptic curve cryptography. Smaller keys (256-bit vs 2048-bit RSA) with equivalent security, and faster signature verification. Increasingly preferred for mobile and IoT scenarios where bandwidth and computation matter.

Stateless Validation

This is the core advantage of JWTs. When a resource server receives a request with a Bearer token, it validates the JWT entirely locally:

JWT Validation Without Database Lookup
  1. Decode the header and extract the kid (key ID)
  2. Fetch the public key from the JWKS endpoint (cached locally, refreshed periodically)
  3. Verify the signature using the public key
  4. Check exp has not passed (token not expired)
  5. Check nbf has passed (token is active)
  6. Check iss matches the expected authorization server
  7. Check aud includes this service's identifier
  8. Extract scope or roles for authorization decisions

No database query. No network call to the authorization server. Validation takes microseconds. At 50,000 requests per second, this saves 50,000 network round-trips per second compared to opaque token introspection.

Common Pitfall

JWTs cannot be revoked before expiration. Once issued, a JWT is valid until its exp claim passes. If a user's account is compromised, you cannot invalidate their existing JWTs — you can only wait for them to expire. This is why access token lifetimes should be short (5-15 minutes). For immediate revocation, you need either a token blocklist (which sacrifices statelessness) or opaque tokens with server-side lookup.

The Revocation Problem

Stateless validation has a cost: you lose the ability to revoke individual tokens. With opaque tokens stored in a database, revoking access means deleting the token record. With JWTs, the token is self-contained — there is no record to delete.

Production systems mitigate this with a layered approach:

  • Short access token TTL (5-15 minutes) — limits the window of exposure after revocation
  • Refresh token rotation — each refresh returns a new refresh token and invalidates the old one. Revoking the refresh token stops new access tokens from being issued
  • Token blocklist for emergencies — a small Redis set of revoked token JTIs (JWT IDs) checked during validation. This reintroduces a lookup but only for the small set of actively revoked tokens, not all tokens
  • Logout propagation — when a user logs out, revoke their refresh token and optionally add their current access token JTI to the blocklist

Token Bloat and Payload Visibility

JWTs grow with every claim you add. A token with 15 custom claims, nested role hierarchies, and multiple audience values can reach 2-4 KB. Since the token travels in every HTTP request header, this adds bandwidth overhead. Some API gateways reject headers larger than 8 KB, which limits how much data you can embed.

The payload is base64url-encoded, not encrypted. Anyone who intercepts a JWT can decode the payload and read all claims. Never put sensitive data (passwords, credit card numbers, PII beyond what is necessary) in JWT claims. If you need encrypted tokens, use JWE (JSON Web Encryption), but this adds complexity and computational cost.

A common mistake is treating base64url encoding as a form of security. It is not — decoding a JWT payload requires zero keys or secrets. Paste any JWT into jwt.io and every claim is immediately visible. Design your claim set with the assumption that the token will be logged, cached, and inspected by intermediaries.

Standard TLS is one-sided: the client verifies the server's identity, but the server has no idea who the client is. When you visit your bank's website, your browser verifies the bank's TLS certificate, but the bank's server does not verify your browser's certificate. The bank authenticates you later via username and password at the application layer.

This asymmetry is fine for user-facing traffic, but inside a data center it creates a gap. If Service A calls Service B over standard TLS, Service B knows the connection is encrypted but cannot verify that Service A is who it claims to be. Any process on the network that can reach Service B's port can call it. mTLS closes this gap by requiring both sides to present and verify certificates.

How mTLS Works

The mTLS handshake extends the standard TLS handshake with a client certificate exchange:

Mutual TLS Handshake Between Two Services
  1. ClientHello — the client initiates the connection and sends supported cipher suites
  2. ServerHello + Server Certificate — the server responds with its certificate
  3. CertificateRequest — the server requests the client's certificate (this is the mTLS-specific step)
  4. Client Certificate — the client sends its own X.509 certificate
  5. Mutual Verification — both sides verify the other's certificate against their trusted Certificate Authority (CA)
  6. Encrypted Channel — after mutual verification, all traffic is encrypted and both identities are confirmed

After this handshake, Service B knows with cryptographic certainty that the caller is Service A (not an attacker on the same network), and the connection is encrypted end-to-end.

X.509 Certificates and CA Trust Chains

Each certificate is an X.509 document containing the service's identity (Common Name or Subject Alternative Name), the service's public key, the issuer's signature, and a validity period. The trust model works through a chain:

  • Root CA — a self-signed certificate that both services trust. In enterprise environments, this is an internal root CA managed by the security team, not a public CA like Let's Encrypt.
  • Intermediate CA — signs service certificates. Using intermediates means the root CA's private key stays offline in a hardware security module (HSM), reducing the risk of compromise.
  • Leaf certificates — issued to individual services. Each certificate identifies the service by its DNS name or SPIFFE ID.

A service validates an incoming certificate by walking the chain: leaf certificate was signed by the intermediate CA, which was signed by the root CA, which is in the service's trust store. If any link breaks — expired certificate, unknown CA, revoked intermediate — the handshake fails and the connection is refused.

Service Mesh Integration

Manually configuring mTLS on every service is operationally painful. Service meshes like Istio and Linkerd solve this by offloading mTLS to sidecar proxies. Each pod gets a sidecar (Envoy in Istio, Linkerd-proxy in Linkerd) that handles certificate management, TLS termination, and mutual authentication transparently.

The application code makes a plain HTTP call to localhost. The sidecar intercepts the outgoing request, establishes an mTLS connection to the destination's sidecar, and forwards the request. The receiving sidecar terminates TLS and delivers the plain HTTP request to the application. Neither application needs TLS libraries, certificate loading code, or rotation logic.

This separation is powerful because it makes mTLS a platform concern rather than an application concern. A developer writing a Python Flask service does not need to understand X.509 certificates — the mesh handles it.

SPIFFE and SPIRE for Workload Identity

SPIFFE (Secure Production Identity Framework for Everyone) standardizes how workloads identify themselves across heterogeneous environments. Instead of tying identity to an IP address or hostname (which change frequently in container orchestration), SPIFFE assigns each workload a SPIFFE ID in URI format:

 
spiffe://example.com/payments/production
spiffe://example.com/orders/staging

SPIRE (SPIFFE Runtime Environment) is the reference implementation. It runs an agent on each node that attests the identity of workloads (using Kubernetes service account tokens, AWS instance metadata, or other platform-specific attestation), obtains short-lived X.509 certificates from the SPIRE server, and delivers them to workloads via the SPIFFE Workload API. Certificates auto-rotate before expiration.

Certificate Rotation Challenges

Certificates expire. In a cluster with 500 services, each with a certificate that lasts 24 hours, that is 500 certificate renewals per day — roughly one every 3 minutes. Manual rotation is impossible at this scale.

Automated rotation requires:

  • Short certificate lifetimes (1-24 hours) — limits the blast radius of a compromised certificate
  • Automated renewal — SPIRE, cert-manager (Kubernetes), or Vault PKI handle this
  • Graceful handoff — the service must accept both the old and new certificate during the rotation window to avoid dropping in-flight connections
  • Monitoring — alert when certificates are within 10% of their lifetime without renewal. A certificate expiration at 3 AM that takes down mTLS for every service is the kind of incident that ends careers

Real production systems rarely use a single authentication mechanism in isolation. The strongest architectures layer multiple mechanisms because each one solves a different part of the problem. mTLS proves identity at the transport layer (who is this service?), JWTs carry authorization at the application layer (what is this service allowed to do?), and cloud-native identities tie workloads to platform-level permissions.

Defense in Depth: mTLS + JWT

Why use both when mTLS already proves identity? Because mTLS operates at the connection level — it tells you which service opened the connection, but not which user initiated the request or what permissions the request carries. A payment service calling an order service via mTLS proves it is the payment service, but the order service still needs to know: is this a read request or a write request? Which user's order is being accessed? Does the payment service have the "orders:read" scope?

JWTs carry this context. The payment service obtains a JWT from the authorization server (via client credentials flow) with scopes like "orders:read" and forwards it alongside the mTLS-authenticated connection. The order service validates the mTLS certificate at the transport layer and the JWT at the application layer. Two independent checks, two different attack surfaces covered.

Service Mesh Sidecar Handling mTLS and JWT Validation
Interview Tip

In system design interviews, when discussing service-to-service authentication, describe both layers: mTLS for transport-level identity ('who is calling') and JWT for application-level authorization ('what are they allowed to do'). This defense-in-depth answer demonstrates security maturity and distinguishes you from candidates who mention only one mechanism.

OAuth 2.0 Client Credentials for Service Tokens

The client credentials flow is how services obtain JWTs without user involvement. Each service is registered as an OAuth 2.0 client with its own client_id and client_secret (or uses a private key JWT for client authentication, which is more secure). The service authenticates to the authorization server and receives an access token scoped to its specific permissions.

 
1POST /oauth/token
2Content-Type: application/x-www-form-urlencoded
3
4grant_type=client_credentials
5&client_id=payment-service
6&client_secret=s3cr3t
7&scope=orders:read+inventory:write

The authorization server returns a JWT with the requested scopes. The service caches this token and refreshes it before expiration. Each service gets only the scopes it needs — the payment service cannot request "users:admin" scope because its client registration does not permit it.

Cloud-Native Workload Identity

Cloud providers offer identity mechanisms that eliminate the need for manually provisioned secrets:

  • AWS IAM Roles for Service Accounts (IRSA) — Kubernetes pods assume an IAM role via an OIDC token projected into the pod. The pod authenticates to AWS services without any access key or secret stored in environment variables.
  • GCP Workload Identity — maps Kubernetes service accounts to GCP service accounts. Pods call GCP APIs using the mapped service account's permissions with no key file.
  • Azure Managed Identities — Azure assigns an identity to a VM or container instance. The workload requests tokens from the instance metadata service (IMDS) at a well-known local endpoint.

The pattern is the same across all three clouds: the platform attests the workload's identity based on where it runs (which pod, which namespace, which node), and the workload receives short-lived tokens without managing long-lived secrets. No secrets to rotate, no credentials to leak.

Workload Identity Federation

What happens when a service running on AWS needs to call a GCP API? Or when a GitHub Actions workflow needs to deploy to AWS? Workload identity federation bridges trust boundaries by exchanging tokens.

The flow: (1) the workload obtains an OIDC token from its home platform (AWS, GitHub, etc.), (2) the workload presents this token to the target cloud's security token service, (3) the target cloud validates the token's issuer and claims against a pre-configured trust policy, (4) the target cloud issues a short-lived token for its own APIs. No long-lived credentials cross the boundary — only short-lived, scoped tokens that expire in minutes.

This eliminates the most dangerous pattern in multi-cloud architectures: storing AWS access keys in GCP secrets or vice versa. Leaked cross-cloud credentials are among the most common attack vectors in cloud security breaches.

The broader principle behind workload identity federation is the shift from "credentials you store" to "identity you prove." Static credentials (access keys, service account JSON files, client secrets) are liabilities — they can be copied, leaked, and used from anywhere. Platform-attested identities are tied to the workload's runtime environment and cannot be extracted or replayed from a different context. Every major cloud provider is moving in this direction because it fundamentally changes the threat model from "protect the secret" to "verify the caller."

Every authentication and token strategy involves trade-offs. There is no universally correct choice — the right answer depends on your threat model, operational maturity, and system architecture. Understanding these trade-offs is what separates a senior engineer from someone who just implements whatever the tutorial recommends.

Stateless JWT vs Opaque Tokens

This is the most common trade-off question in interviews.

DimensionJWT (stateless)Opaque token (stateful)
ValidationLocal — verify signature, check claimsNetwork — introspect at authorization server or lookup in session store
RevocationHard — valid until exp. Requires blocklist for immediate revocationEasy — delete the token record from the store
ScalabilityExcellent — no shared state, any server validatesRequires shared session store (Redis, database)
Token size500 bytes - 4 KB (carries claims)20-40 bytes (random string, claims stored server-side)
Information leakagePayload is readable (base64url, not encrypted)No information in the token itself
LatencyMicroseconds (local crypto)Milliseconds (network + store lookup)

When to use JWTs: High-throughput APIs where validation speed matters. Architectures with many resource servers that would overload a central token introspection endpoint. Stateless microservices that avoid shared infrastructure.

When to use opaque tokens: Systems requiring instant revocation (financial, healthcare). Environments where token payload confidentiality matters. Simple architectures with a single API server where the overhead of a token store is negligible.

Hybrid approach (most common in production): JWT access tokens (short-lived, stateless validation) paired with opaque refresh tokens (stored server-side, instantly revocable). This combines fast validation for the hot path with instant revocation for the security path.

Token Lifetime Trade-offs

Short-lived tokens (5 minutes) mean a stolen token is useful for only 5 minutes, but the client must refresh frequently. At 10,000 active users with 5-minute tokens, the authorization server handles roughly 33 refresh requests per second — manageable, but not free.

Long-lived tokens (24 hours) reduce refresh overhead to once per day per user, but a stolen token grants access for up to 24 hours. For a compromised admin account, 24 hours of unauthorized access can be catastrophic.

The industry consensus has converged on 5-15 minute access tokens with refresh token rotation. Each refresh returns a new refresh token and invalidates the old one. This provides automatic credential rotation and detects token theft — if an attacker uses a stolen refresh token, the legitimate client's next refresh fails (because the token was already consumed), triggering forced re-authentication and security alerts.

mTLS Operational Cost

mTLS provides the strongest transport-layer authentication, but the operational burden is real:

  • Certificate issuance — every service needs a certificate from a trusted CA. At 500 services, this is a PKI infrastructure problem.
  • Certificate rotation — short-lived certificates (24 hours) require automated renewal. A failure in the renewal pipeline causes service outages.
  • Trust distribution — every service must have the CA's root certificate in its trust store. Adding a new CA or rotating the root requires updating every service.
  • Debugging difficulty — mTLS handshake failures produce cryptic error messages. "TLS handshake failed" could mean expired certificate, wrong CA, revoked cert, or clock skew. Diagnosing requires examining certificates on both sides.
  • Performance overhead — the mTLS handshake adds 1-2 ms of latency per new connection. Connection pooling and persistent connections amortize this cost, but cold starts pay the full price.

For teams without dedicated security infrastructure, the operational cost of mTLS may exceed its security benefit. API keys or JWT-based authentication are simpler alternatives for smaller deployments, with the understanding that they do not provide transport-layer identity verification.

The pragmatic approach is to adopt mTLS incrementally: start with a service mesh on a non-critical namespace, build operational confidence with certificate automation and monitoring, then expand to the full cluster. Trying to deploy mTLS across 500 services in a single rollout is a recipe for a certificate-related outage that undermines trust in the entire initiative.

When to Use Which

ScenarioRecommended approachWhy
User-facing web/mobile appOIDC (authentication) + OAuth 2.0 JWT (authorization)Need user identity + API access. PKCE for public clients.
Service-to-service (internal)mTLS + client credentials JWTmTLS for transport identity. JWT for fine-grained permissions.
External API (third-party)OAuth 2.0 + API keysAPI keys for rate limiting and billing. OAuth for delegated access.
CI/CD pipelinesWorkload identity federationNo long-lived credentials. Platform-attested identity.
Single-page applicationOIDC + BFF patternTokens stay server-side. Browser never holds refresh tokens.
IoT devicesX.509 client certificates + short-lived JWTDevice cert for hardware identity. JWT for cloud API access.

Protocol and Mechanism Comparison

MechanismWhat it doesLayerBest for
OAuth 2.0Delegated authorization (scoped access tokens)ApplicationThird-party API access, user-delegated permissions
OIDCUser authentication (ID tokens with identity claims)ApplicationSSO, user login, identity verification
JWTSelf-contained token format (stateless validation)ApplicationAccess tokens, ID tokens, service tokens
mTLSMutual transport-layer authentication (certificates)TransportService-to-service identity, zero-trust networks
SPIFFE/SPIREPlatform-agnostic workload identityInfrastructureMulti-cloud, Kubernetes, dynamic environments
Workload Identity FederationCross-platform token exchangeInfrastructureMulti-cloud access, CI/CD pipelines

Decision Tree

When designing authentication for a system, start with these questions:

Is there a human user?

  • Yes, and you need identity (name, email, SSO) --> OIDC + OAuth 2.0
  • Yes, but you only need API authorization --> OAuth 2.0 access tokens

Is it service-to-service within your infrastructure?

  • Yes, with a service mesh --> mTLS (handled by sidecar) + JWT for authorization
  • Yes, without a service mesh --> Client credentials JWT + network policies

Is it cross-cloud or CI/CD?

  • Yes --> Workload identity federation (no stored credentials)

Is it an external third-party integration?

  • Yes, calling their API --> OAuth 2.0 client credentials or API key
  • Yes, they are calling yours --> OAuth 2.0 + rate limiting + API key for billing

Key Principles

Defense in depth: Layer authentication mechanisms. mTLS proves transport identity, JWT proves application-level permissions, cloud IAM restricts resource access. No single layer is sufficient alone.

Short-lived credentials: Access tokens should expire in minutes, not hours. Refresh tokens provide continuity without the security risk of long-lived access tokens. Certificates should auto-rotate in hours, not months.

Automate rotation: Manual credential rotation fails at scale. Use SPIRE for certificates, refresh token rotation for user tokens, and workload identity federation for cloud credentials. If a human must remember to rotate a credential, that credential will eventually expire in production.

Least privilege: Every token, certificate, and credential should carry the minimum permissions required. A service that reads orders should not have a token that can delete users. Scoping reduces blast radius when credentials are compromised.

Interview Tip

In system design interviews, show the examiner you understand layered security by mentioning at least two authentication mechanisms for service-to-service calls (mTLS + JWT), explaining why short-lived tokens matter (revocation latency), and noting that cloud-native identities eliminate stored secrets. These three points cover the most common follow-up questions about auth in distributed systems.

Common Interview Mistakes

  • Saying 'exactly-once' token delivery — tokens are issued once and cached; delivery semantics do not apply the same way as message processing.
  • Confusing OAuth 2.0 with authentication — OAuth is authorization. OIDC adds authentication. Interviewers test this distinction explicitly.
  • Forgetting revocation — proposing JWTs without addressing how to handle a compromised token within minutes, not hours.
  • Ignoring operational cost — recommending mTLS without mentioning the PKI infrastructure, certificate automation, and debugging complexity it requires.
  • Treating auth as an afterthought — authentication and authorization should be part of the initial architecture, not bolted on after the system is built.