What Is an Access Token?
An access token is the credential a client presents to a resource server to prove it has been authorized to act on a resource owner's behalf, scoped to specific permissions and valid for a limited time. OAuth 2.0 deliberately treats the token as opaque to the client: the client should never need to parse it, only to attach it as a Bearer credential in the Authorization header of API requests. The resource server, in contrast, must be able to validate it, either by checking a cryptographic signature locally or by asking the authorization server whether the token is still active.
Cricket analogy: It works like a player's accreditation pass at the Wankhede Stadium: Virat Kohli doesn't need to know how the pass was printed, he just flashes it at the gate, while security actually checks the barcode against the accreditation database before letting him through.
JWT Structure: Header, Payload, Signature
A JSON Web Token is three Base64URL-encoded segments joined by dots: a header describing the signing algorithm and key identifier, a payload of claims such as sub (subject), aud (audience), exp (expiry), iss (issuer), and scope, and a signature computed over the first two segments using the algorithm named in the header. Because the payload is only encoded, not encrypted, anyone can decode and read a JWT's claims; the signature exists solely to let a verifier detect tampering, not to hide the contents. This is why sensitive personal data should never be stuffed into a JWT payload meant to be logged or passed through browsers.
Cricket analogy: It's like a scorecard printed on the back of a match ticket at the MCG: anyone holding the ticket can read the printed scores (the payload), but the embossed hologram (the signature) is what proves the ticket wasn't forged by a scalper.
// Decoded JWT (header.payload.signature)
// Header
{
"alg": "RS256",
"typ": "JWT",
"kid": "2026-07-key-1"
}
// Payload
{
"iss": "https://auth.example.com",
"sub": "user_8842",
"aud": "https://api.example.com",
"scope": "orders.read orders.write",
"exp": 1752163200,
"iat": 1752159600,
"jti": "c1a9f3e2-91b4-4d7a-9c3e-2f8b5a1e0d77"
}
// Encoded form sent as a Bearer token
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjIwMjYtMDct
LWtleS0xIn0.eyJpc3MiOiJodHRwczovL2F1dGguZXhhbXBsZS5jb20iLC...
.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXkOpaque Tokens vs JWTs
Opaque tokens are random strings with no embedded meaning; the resource server must call the authorization server's introspection endpoint on every request to learn who they belong to and whether they are still valid. JWTs invert that trade-off: the resource server can verify the signature locally using a cached public key and skip the network round trip, which is why JWTs dominate in high-throughput microservice architectures. The cost is that a JWT, once issued, is trusted by any resource server holding the verification key until it expires, since there is no built-in mechanism to look it up and revoke it mid-lifetime the way an opaque token check would catch.
Cricket analogy: It's like the difference between a DRS review that calls the third umpire every time (opaque, always checking centrally) versus a snickometer reading the on-field umpire trusts instantly without a call upstairs (JWT, verified locally).
When validating a JWT access token, always check exp (not expired), nbf (not used before its time), aud (intended for this resource server), and iss (issued by the trusted authorization server) — signature verification alone is not enough.
Validating Access Tokens Correctly
Proper validation of a JWT access token means verifying the signature against the correct public key (fetched from the authorization server's JWKS endpoint and matched by the kid header claim), confirming exp and nbf against the current time with a small clock-skew allowance, and checking that aud matches this specific resource server rather than some other API in the ecosystem. Skipping the audience check is a common vulnerability: a token minted for one API could otherwise be replayed against a different API that shares the same issuer and signing key, letting an attacker escalate access across services that were never meant to trust each other's tokens.
Cricket analogy: It's like a stadium gate that checks not just that a ticket's hologram is genuine but also that it's printed for today's Ashes Test at the Gabba, not last week's ODI, catching a scalper trying to reuse an old, valid-looking ticket.
Never accept a JWT with alg set to none, and never let the resource server trust an algorithm chosen by the token itself without pinning it server-side — attackers have exploited libraries that blindly honor the alg header to bypass signature checks entirely.
- An access token is a scoped, time-limited credential sent as a Bearer token; clients should treat it as opaque and never parse it to make authorization decisions.
- A JWT has three parts — header, payload, signature — and the payload is only encoded, not encrypted, so it must never carry secrets.
- Opaque tokens require an introspection call per request; JWTs are self-contained and verifiable locally via a cached public key.
- Full validation requires checking signature, exp, nbf, aud, and iss together — signature verification alone is insufficient.
- Skipping the audience (aud) check allows tokens minted for one API to be replayed against another API sharing the same issuer.
- Never honor an alg: none header or let the token dictate its own verification algorithm to the verifier.
- JWTs trade revocability for performance: once issued, a JWT remains valid until expiry unless paired with a revocation mechanism like introspection or a deny-list.
Practice what you learned
1. Why should a resource server never trust the alg value inside an incoming JWT's header to decide how to verify it?
2. What is the primary purpose of a JWT's signature?
3. Which validation step specifically prevents a JWT issued for one API from being replayed against a different API sharing the same issuer?
4. What is the main operational trade-off of using JWT access tokens instead of opaque tokens?
5. Where does a resource server typically obtain the public key needed to verify a JWT's RS256 signature?
Was this page helpful?
You May Also Like
Refresh Tokens
Refresh tokens let a client obtain new access tokens without forcing the resource owner to re-authenticate, and how they're issued and rotated is central to OAuth 2.0 security.
Token Introspection and Revocation
Introspection lets a resource server ask the authorization server whether a token is still valid, and revocation lets a client or user proactively kill a token before it expires.
Token Storage Best Practices
Where and how a client stores access and refresh tokens is often the deciding factor in whether an OAuth 2.0 integration is actually secure in practice.
Scopes and Consent
Scopes let a client request narrowly defined permissions, and the consent screen is where the resource owner explicitly approves exactly what's being granted.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics