Zustandslose Auth mit JWT
Beim Login ein signiertes Token ausstellen und jede weitere Anfrage daraus authentifizieren - ohne Server-Session.
Deutsche Übersetzung in Arbeit
Diese Lektion ist noch nicht ins Deutsche übersetzt und wird daher auf Englisch angezeigt. Der Rest der Seite ist vollständig lokalisiert.
Auf dieser Seite
A traditional web app keeps a session: after login, the server stores who you are and hands you a cookie pointing at that session. For an API serving many clients and scaling across servers, that server-side state is a burden. JWT (JSON Web Token) offers a stateless alternative: the proof of identity travels with each request.
What a JWT is
A JWT is a signed, self-contained token with three dot-separated parts:
header.payload.signature- header — the algorithm (e.g. HS256).
- payload — the claims: who the user is (
sub), their roles, an expiry (exp). - signature — a cryptographic signature over the first two parts, made with a secret only the server knows.
Because it's signed, the server can trust a token it receives without looking anything up: if the signature verifies, the claims are authentic and untampered.
At a festival, you show ID once at the entrance and get a wristband. For the rest of the weekend, staff just glance at the wristband - they don't phone the box office to re-check your ticket each time. The wristband is hard to forge and encodes your access level. A JWT is that wristband: you authenticate once, receive a signed token, and every later request simply presents it. The server checks the "seal" (signature) rather than looking you up in a session store.
The flow
- Login: the client POSTs credentials; the server authenticates them and, on success, issues a signed JWT containing the user id and roles.
- Each request: the client sends the token in an
Authorization: Bearer <token>header. - Validation: a filter verifies the signature and expiry, reads the claims, and
builds the
Authentication- no database, no session.
// issuing a token on login (using Spring Security's JwtEncoder)
JwtClaimsSet claims = JwtClaimsSet.builder()
.subject(user.getEmail())
.claim("roles", user.getAuthorities())
.issuedAt(now).expiresAt(now.plus(1, ChronoUnit.HOURS))
.build();
String token = jwtEncoder.encode(JwtEncoderParameters.from(claims)).getTokenValue();On the validating side, Spring Security's resource server support does the checking for you - point it at the signing key and it authenticates every Bearer token:
http.oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()));The trade-offs
Statelessness is powerful but has consequences:
- Can't be revoked instantly — a valid token works until it expires. Keep lifetimes short (minutes to an hour) and use refresh tokens for longer sessions.
- Claims can be read by anyone — a JWT is signed, not encrypted. Never put secrets in the payload; assume the client can read it.
- Always use HTTPS — a stolen token is a valid credential until it expires.
Signed, not secret
The signature guarantees integrity (nobody altered the claims), not confidentiality. Anyone can decode a JWT's payload and read the roles and expiry. Put identity and permissions there - never passwords or sensitive data.
A client logs into BookVault, receives a JWT, and later calls
DELETE /api/books/{isbn}. Describe what the client sends on that call, and the two
things the server checks about the token before allowing the deletion - without ever
touching a session store or the database for the token itself.
What makes JWT-based authentication 'stateless'?
Key takeaways
- JWT enables stateless auth: a signed token carries the user's identity and roles, so no server-side session is needed.
- Flow: authenticate once at login -> receive a signed JWT -> send it as 'Authorization: Bearer <token>' on each request.
- Spring Security's resource-server support validates the signature and expiry and builds the Authentication automatically.
- A JWT is signed, not encrypted - anyone can read its claims, so never put secrets in the payload.
- Tokens can't be instantly revoked, so keep lifetimes short, use refresh tokens, and always require HTTPS.