Why this matters
As an API Engineer, you’ll secure endpoints that power apps, partner integrations, and internal services. Real tasks you’ll face:
- Choosing the right auth method for each client (user apps vs. servers).
- Validating JWT access tokens and rejecting invalid ones.
- Implementing OAuth2 flows (Authorization Code with PKCE, Client Credentials).
- Handling OIDC ID tokens for user identity.
- Issuing and rotating API Keys for service-to-service or partner access.
Getting these wrong leads to data exposure, account takeovers, and compliance failures. Getting them right builds trust and reliability.
Concept explained simply
Authentication answers “Who are you?” Authorization answers “What are you allowed to do?”
- OAuth 2.0: A framework for delegated access. Clients obtain access tokens to call APIs.
- OIDC (OpenID Connect): A thin layer on top of OAuth 2.0 that gives you an ID Token (who the user is) and a standard way to get user info.
- API Keys: Simple static secrets that identify a calling system. Best for server-to-server with limited scope and lower risk scenarios. Not tied to a user identity by default.
Mental model
Think of three actors:
- Authorization Server (Auth Server): Issues tokens.
- Client: Wants to call your API.
- Resource Server (Your API): Verifies tokens and enforces scopes.
Your API trusts the Auth Server’s signatures. Access Tokens carry permissions (scopes); ID Tokens carry identity claims. API Keys identify the caller but lack standardized claims unless you add them with metadata and policy.
Core building blocks
- Access Token: Usually a JWT Bearer token or opaque string. Used to call APIs. Validate signature, issuer (iss), audience (aud), expiration (exp), and possibly not-before (nbf).
- ID Token (OIDC): JWT describing the authenticated user (sub). Not for calling your API unless explicitly allowed; mainly for the client app.
- Common flows:
- Authorization Code + PKCE: For web/SPAs/mobile with a user.
- Client Credentials: Machine-to-machine without a user.
- Device Code: For devices without browsers.
- API Keys: Static secrets. Use key IDs, rotate frequently, scope to specific APIs, and rate-limit.
- JWKS and kid: Public keys exposed by the Auth Server. Use the JWT header's kid to find the right key.
Worked examples
Example 1: Verify a JWT access token in your API
- Extract the Authorization header: Bearer <token>.
- Decode header to get alg (e.g., RS256) and kid.
- Fetch JWKS (public keys) from your configured issuer and select key by kid. Cache keys with a TTL.
- Verify signature and standard claims:
- iss matches your expected issuer.
- aud contains your API audience.
- exp and nbf are valid within a small clock skew.
- Authorize based on scopes in the token (e.g., scope: "read:orders").
See sample token claims
{
"iss": "https://auth.example/",
"sub": "user_123",
"aud": "orders-api",
"exp": 1893456000,
"iat": 1734480000,
"scope": "read:orders write:orders"
}Example 2: Machine-to-machine with Client Credentials
- Service A posts client_id and client_secret to the Auth Server’s token endpoint with grant_type=client_credentials and audience=payments-api.
- Auth Server returns access_token with relevant scopes (e.g., "process:payment").
- Service A calls payments API with Authorization: Bearer <token>.
- Payments API validates token as in Example 1 and enforces scope.
Tip: scope design
- Keep scopes action-based and minimal: read:*, write:*, admin:* only if truly needed.
- Prefer multiple small scopes to one overly broad scope.
Example 3: API Key with rotation
- Issue two keys per client: current and next. Include a key ID (kid) or x-api-key-id.
- Accept both keys for a grace period.
- Clients switch to the new key; you revoke the old key after the grace period.
- Log usage per key ID and apply rate limits and scopes.
API Key headers
- Send: x-api-key-id: <id>, x-api-key: <secret>
- Reject requests without both. Do not put keys in URLs.
Who this is for
- API engineers and backend developers implementing or reviewing authentication.
- Engineers moving from monoliths to services that need token-based auth.
- Teams onboarding partners via API keys.
Prerequisites
- HTTP basics (headers, status codes).
- Familiarity with JSON.
- Comfort with environment variables and secret handling.
Learning path
- Start with Authentication vs Authorization and token types (Access vs ID).
- Implement OAuth2 flows: Authorization Code + PKCE, then Client Credentials.
- Add API Key issuance, scoping, and rotation.
- Harden validation: JWT signature, claims, JWKS caching, key rotation.
- Audit and monitoring: per-client logs, token error analytics.
Implementation notes that keep you safe
- Always use HTTPS/TLS. Never transmit tokens or API keys over plain HTTP.
- Validate JWTs locally; cache JWKS for minutes and refresh on kid miss.
- Reject tokens with alg="none". Pin expected algorithms (e.g., RS256).
- Check iss, aud, exp, nbf. Allow small clock skew (e.g., 60s).
- Do not use ID Tokens to call your resource APIs unless explicitly designed for it.
- Prefer short-lived access tokens; use refresh tokens securely on the server side.
- For API Keys: store hashed at rest, show once on creation, and rotate regularly.
Common mistakes and self-check
- Accepting any valid signature but wrong audience: always enforce aud.
- Using ID Token as access token: keep roles separate.
- Ignoring kid and failing during key rotation: select key by kid.
- Long-lived API keys with broad access: scope and rotate.
- Putting API keys in URLs: use headers; URLs end up in logs.
- Storing secrets in client-side code: never embed secrets in public apps.
Self-check checklist
- My API rejects tokens with wrong iss or aud.
- I verify exp/nbf and allow small leeway only.
- I pin accepted algs and ignore "none".
- I cache JWKS and handle key rotation via kid.
- I use Authorization Code + PKCE for public clients.
- Client Credentials is used only for non-user flows.
- API Keys have key IDs, rotation, and logging.
Practical projects
- Project A: Create a small Orders API that accepts OAuth2 access tokens and enforces read:orders and write:orders scopes.
- Project B: Add an internal job runner that calls your API via Client Credentials and logs 401/403 errors for analysis.
- Project C: Add API Key support for a partner endpoint with per-key rate limits and a two-key rotation policy.
Exercises
Do these now. The quick test at the end is available to everyone; log in to save your progress.
- Exercise 1 — Validate a JWT
You receive a JWT access token with:
header: { "alg": "RS256", "kid": "key-2026-01" } payload: { "iss": "https://auth.example/", "sub": "user_123", "aud": "orders-api", "exp": 1893456000, "iat": 1734480000, "scope": "read:orders write:orders" }Assume the RS256 signature verifies with the JWKS key key-2026-01. State whether the token is valid for orders-api and list the effective scopes and subject you will authorize.
- Exercise 2 — Design an API Key rotation plan
Write a rotation plan that avoids downtime for clients and lets you revoke keys quickly. Include: number of simultaneous keys per client, headers to send, logging, and revocation steps.
Need help? Hints
- Ex1: Check iss, aud, exp, and signature before reading scope.
- Ex2: Two active keys (current/next) with key IDs; accept both during a grace period; log usage per key ID.
Mini challenge
Add fine-grained scopes to your API (e.g., read:orders:own vs read:orders:any), update your authorization middleware to enforce them, and confirm with two tokens that have different scopes.
Next steps
- Harden error handling: distinguish 401 (invalid/missing token) from 403 (insufficient scope).
- Add token revocation and introspection for opaque tokens if needed.
- Extend monitoring: track failed validations by reason (iss, aud, exp, sig).