Die API absichern
Ergänze Authentifizierung und Autorisierung: BCrypt-Passwörter, ein JWT-Login-Endpunkt und die Rollen MEMBER und LIBRARIAN, über die Endpunkte hinweg durchgesetzt.
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
BookVault works, but right now anyone can delete any book. This lesson adds the layer that makes it safe to expose: authentication (who are you?) and authorization (what may you do?), using JWT tokens, BCrypt-hashed passwords, and two roles - MEMBER and LIBRARIAN.
Passwords, hashed
Never store a password. Store a BCrypt hash - a one-way, salted, deliberately slow function - and verify by hashing the attempt and comparing:
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(); // salted, slow-by-design; never reversible
}A member's stored passwordHash is what login checks against. Even if the database leaks, the
plaintext passwords don't.
Logging in returns a JWT
BookVault is a stateless API - no server-side sessions. On successful login it issues a JWT: a signed token carrying the user's identity and roles, which the client sends on every subsequent request:
// AuthController: verify credentials, then mint a signed token
public TokenResponse login(LoginRequest request) {
authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(request.email(), request.password()));
return new TokenResponse(tokenService.issue(request.email())); // signed JWT
}The token is signed with an HMAC secret (HS256). Because the signature is verifiable, the server
trusts a token's claims without looking anything up - that's what makes it stateless and scalable. The
secret comes from the environment (JWT_SECRET), never the source.
Roles decide what you can do
The security filter chain validates the JWT on each request and then applies authorization rules - reading is open, but changing the catalog requires the LIBRARIAN role:
http
.csrf(csrf -> csrf.disable()) // safe: stateless token API
.sessionManagement(s -> s.sessionCreationPolicy(STATELESS))
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/auth/**").permitAll() // login is open
.requestMatchers(GET, "/api/books/**").permitAll() // anyone may browse
.requestMatchers(POST, "/api/books/**").hasRole("LIBRARIAN") // only librarians edit
.anyRequest().authenticated())
.oauth2ResourceServer(o -> o.jwt(...)); // validate the JWTNow GET /api/books is public, a MEMBER can borrow, and a DELETE /api/books/... without a LIBRARIAN
token is rejected with 401 (not authenticated) or 403 (authenticated but not allowed).
Logging in is passport control: you prove who you are once, and receive a boarding pass (the JWT) stamped with where you're allowed to go. At each gate (endpoint) staff check the pass's signature and your class (role) - no need to re-verify your passport every time. A forged or expired pass is refused at the gate. That's stateless, token-based security: authenticate once, carry a verifiable pass, and each endpoint checks it.
401 vs 403 - a precise distinction
401 Unauthorized means 'I don't know who you are' - no or invalid token; authenticate first. 403 Forbidden means 'I know who you are, but you may not do this' - a valid token without the required role. BookVault returns 401 for a missing/bad token and 403 for a MEMBER attempting a LIBRARIAN action. Getting these right makes your API honest about why a request failed.
A MEMBER (logged in, holding a valid JWT) sends DELETE /api/books/978-.... Walk through what the
security layer does, which status code comes back and why, and contrast it with the same request sent
with no token at all.
How does BookVault secure its API?
Key takeaways
- Store passwords only as BCrypt hashes (salted, slow, one-way) and verify by hashing the attempt.
- BookVault is stateless: login issues a signed JWT carrying identity and roles, sent on each request instead of a session.
- The JWT is signed with an HMAC secret from the environment, so the server trusts its claims without a lookup.
- The security filter chain validates the token then applies authorization rules - reads open, catalog edits require LIBRARIAN.
- 401 means unauthenticated (no/bad token); 403 means authenticated but lacking the required role.
- Security is a distinct layer added over a working app - authentication first, then fine-grained authorization.