BackendBench
Coffee

Unravel โ€บ Java concepts โ€บ Security

Spring

JSON Web Tokens (JWT)

A JWT is a signed token that carries claims (who the user is, when it expires, what roles they have).

Learn these first

At a glance

Mental model

A festival wristband with a tamper-proof seal.

What happens, in order
  1. 1A JWT has three base64url parts: header (algorithm), payload (claims such as sub, exp, iss, roles) and signatureIt is signed, not encrypted: anyone can read the payload.
  2. 2Issuing: build claims, set an expiry, sign with a secret (HS256) or a private key (RS256, ES256)Verifying: check the signature, the expiry (exp), the issuer and the audience before trusting any claim.
  3. 3In Spring Security, a resource server is one line: http.oauth2ResourceServer(o -> o.jwt(...)) with a JwtDecoder that fetches the public keys from the issuer JWKS endpointA JwtAuthenticationConverter maps claims to authorities.
  4. 4Libraries: jjwt (Jwts.builder(), Jwts.parser()), Auth0 java-jwt (JWT.create(), JWT.require(alg).build().verify), Nimbus JOSE (SignedJWT), Spring JwtEncoder
Remember
Watch out
Not verifying signature, expiry, issuer and audienceAccepting any algorithmSensitive data in the payloadLong-lived tokens with no revocation plan
Example (highlighted lines explain it)
String token = Jwts.builder()    .setSubject(user.getId().toString())    .claim("roles", user.getRoles())    .setIssuedAt(new Date())    .setExpiration(Date.from(Instant.now().plus(Duration.ofMinutes(15))))    .signWith(key, SignatureAlgorithm.HS256)    .compact();Claims claims = Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token).getBody();
  1. line 1 uses Jwts, the core of JSON Web Tokens (JWT)
  2. line 5 uses setExpiration, the core of JSON Web Tokens (JWT)
  3. line 6 uses signWith, the core of JSON Web Tokens (JWT)
  4. line 9 uses Claims, the core of JSON Web Tokens (JWT)
Read the full explanation (about 2 min)

A JWT is a signed token that carries claims (who the user is, when it expires, what roles they have). A server can verify it without a database lookup, so APIs use it as proof of login in the Authorization: Bearer header.

A mental model

A festival wristband with a tamper-proof seal. Staff read it at a glance (claims) and know it is genuine because of the seal (signature), without phoning the ticket office each time.

How it works

A JWT has three base64url parts: header (algorithm), payload (claims such as sub, exp, iss, roles) and signature. It is signed, not encrypted: anyone can read the payload.

Issuing: build claims, set an expiry, sign with a secret (HS256) or a private key (RS256, ES256). Verifying: check the signature, the expiry (exp), the issuer and the audience before trusting any claim.

In Spring Security, a resource server is one line: http.oauth2ResourceServer(o -> o.jwt(...)) with a JwtDecoder that fetches the public keys from the issuer JWKS endpoint. A JwtAuthenticationConverter maps claims to authorities.

Libraries: jjwt (Jwts.builder(), Jwts.parser()), Auth0 java-jwt (JWT.create(), JWT.require(alg).build().verify), Nimbus JOSE (SignedJWT), Spring JwtEncoder.

Going deeper

Pin the algorithm on verification. Accepting alg: none or letting the token pick between HMAC and RSA enables classic forgery attacks (using the public key as an HMAC secret). Good libraries make you specify the key and algorithm; never skip it.

Tokens cannot be revoked before expiry unless you keep a deny list. Use short lifetimes (5 to 15 minutes) with refresh tokens stored and rotated server-side, and do not put sensitive data in the payload.

Keep HMAC secrets long and random (at least 256 bits) and out of source code. Store tokens in browsers in HttpOnly cookies where possible, because JavaScript-readable storage is exposed to XSS.

Under the hood

The signature is computed over base64url(header) + "." + base64url(payload). HMAC uses one shared secret for both signing and verifying; RSA and ECDSA sign with the private key and verify with the public key, which lets many services verify tokens issued by one identity provider without holding any secret.

Common mistakes

  • Not verifying signature, expiry, issuer and audience.
  • Accepting any algorithm.
  • Sensitive data in the payload.
  • Long-lived tokens with no revocation plan.

How Unravel recognises it

When you paste code, Unravel looks for these signs of json web tokens (jwt). Spotting them yourself is a good habit when you read unfamiliar code:

Part of a learning path

Related concepts

Frequently asked questions

What is JSON Web Tokens (JWT)?

A JWT is a signed token that carries claims (who the user is, when it expires, what roles they have). A server can verify it without a database lookup, so APIs use it as proof of login in the Authorization: Bearer header.

What are the most common mistakes with JSON Web Tokens (JWT)?

Not verifying signature, expiry, issuer and audience. Accepting any algorithm. Sensitive data in the payload. Long-lived tokens with no revocation plan.

How can I see JSON Web Tokens (JWT) in real code?

Paste your own Java into Unravel and it will point out where json web tokens (jwt) appears, explain how it works at the detail level you choose, and draw the flow of the code around it.