Unravel โบ Java concepts โบ Security
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
A festival wristband with a tamper-proof seal.
- 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.
- 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.
- 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.
- 4Libraries: jjwt (Jwts.builder(), Jwts.parser()), Auth0 java-jwt (JWT.create(), JWT.require(alg).build().verify), Nimbus JOSE (SignedJWT), Spring JwtEncoder
- Pin the algorithm on verification
- Tokens cannot be revoked before expiry unless you keep a deny list
- The signature is computed over base64url(header) + "." + base64url(payload)
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();- line 1 uses Jwts, the core of JSON Web Tokens (JWT)
- line 5 uses setExpiration, the core of JSON Web Tokens (JWT)
- line 6 uses signWith, the core of JSON Web Tokens (JWT)
- 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:
- Types:
JwtsClaimsJwtParserJwtBuilderJWTJWTVerifierJWTCreatorJWSObjectSignedJWTJWTClaimsSetJWSVerifierMACSignerRSASSASignerJwtand 12 more - Method calls:
parseClaimsJws()signWith()setExpiration()oauth2ResourceServer()
Part of a learning path
- Security for backend developers ยท previous: Spring Security filter chain and authorization rules ยท next: OAuth 2.0 and OpenID Connect login
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.