JSON Web Token (JWT) はどう動くのか?
JSON Web Tokens are everywhere in modern web APIs: single sign-on, OAuth flows, OpenID Connect, serverless authentication — almost everything touches this compact token format. Behind the cryptic-looking string made of three base64url-encoded parts sits a remarkably simple, but security-critical, concept. This article covers structure, signatures, standard claims, and the most common mistakes.
Structure: Header.Payload.Signature
A JWT consists of three base64url-encoded parts separated by dots. The header is a small JSON object with type information and the signing algorithm, for example: { "alg": "HS256", "typ": "JWT" }. The payload (or claims set) is also JSON and contains the actual information about the subject — user ID, permissions, expiry. The signature cryptographically protects header and payload.
Important: the payload is only encoded, not encrypted. Anyone seeing the token can read its content. Confidential data does not belong in the payload. For encryption, use JWE (JSON Web Encryption); the JWTs commonly used in practice are JWS — signed, not encrypted.
Signing algorithms
The header carries an alg field. The most common variants:
- HS256 (HMAC-SHA256): symmetric — a shared secret between issuer and verifier. Fast and simple, good when both sides are under your own control.
- RS256 (RSA-SHA256): asymmetric — the issuer signs with a private key, any number of clients verify with the public key. Standard for OAuth/OpenID identity providers where many clients need to validate tokens.
- ES256 (ECDSA on P-256 with SHA-256): elliptic curves with smaller keys and signatures at security comparable to RSA. Popular in mobile and IoT contexts.
- EdDSA (Ed25519): modern Edwards-curve signature, fast, deterministic, free of the classical ECDSA implementation pitfalls. Increasingly preferred in newer stacks.
Standard claims
RFC 7519 defines a few registered claim names with interoperable meaning:
- iss (issuer): who issued the token? Usually a URL or domain identifier.
- sub (subject): who or what is the token about? Usually the user ID, occasionally an application.
- aud (audience): which recipients is the token intended for? A verifier should check that it appears in this list.
- exp (expiration): UNIX timestamp at which the token expires. Verifiers must enforce this.
- iat (issued at): UNIX timestamp of issuance. Useful to flag very old or future-dated tokens as suspicious.
- jti (JWT ID): unique ID of the token. Allows individual tokens to be put on a blocklist — important for revocation strategies.
Where JWTs are used
In OAuth 2.0, access tokens and refresh tokens are often JWTs. OpenID Connect uses JWTs for the ID token, which conveys identity information about the signed-in user to the client. APIs use JWTs as Bearer tokens in the Authorization header (Authorization: Bearer eyJhbGciOi...).
The typical lifecycle: login sends username/password to an auth server, which returns a short-lived access JWT (e.g. 15 minutes) and a longer-lived refresh token. Follow-up API requests carry the access JWT, the server verifies the signature and selected claims. When the access JWT expires, the client uses the refresh token to obtain a new one — until the session ends at the auth server.
Common pitfalls
- The "alg: none" attack: libraries that blindly trust alg can be tricked with the value "none" into accepting unsigned tokens. Algorithms must be pinned on the server side, e.g. via an explicit allowlist — not taken from the token.
- Missing exp checks: without active validation of the exp claim, a once-issued token remains valid forever. Every validation library offers options for expiry and clock-skew checking.
- LocalStorage vs. HttpOnly cookies: a JWT in localStorage can be read via XSS. It's safer to keep the token in an HttpOnly, Secure, SameSite cookie — even though cross-origin setups become slightly more complex.
- Revocation: unlike a classical session ID, a JWT can't simply be invalidated on the server. To revoke a token before expiry, you need a blocklist (jti-based) or short lifetimes plus refresh tokens.
- Weak HS256 secrets: an 8-character "secret" can be brute-forced offline. HS256 keys should be randomly generated with at least 256 bits of entropy — otherwise prefer RS256.
Frequently asked questions
Are JWTs encrypted?
The JWTs that are typically meant in practice (JWS) are signed but not encrypted. If you also need to hide the content, you can additionally wrap them as JWE tokens — but that's rarely necessary if no sensitive data lives in the payload.
What's the difference between access and refresh tokens?
Access tokens are short-lived (minutes) and travel with every API request. Refresh tokens are longer-lived (hours to weeks), kept safely by the client, and only used to obtain new access tokens. This limits the damage from a stolen access token.
Should I use JWT or sessions?
For classic, server-rendered applications, sessions (cookie-based, server holds the state) are often simpler and safer. For API-only backends, mobile apps, or distributed microservices, JWTs play to their strengths: stateless, verifiable by any instance, well interoperable with OAuth standards.