Entry 1 followed a login request into the kitchen. This page is what happens next in a real app: the user is already logged in, and they want their profile or they want to save a note.
Same restaurant. New orders. The waiter now checks an ID card at the door before taking the order.
The ID card is the token
After login, the app usually gives the browser a JWT or a session cookie. Think of it as a visitor badge.
- The badge is not the user. It only proves “this person already logged in”.
- Every later request must show the badge:
Authorization: Bearer …or an HTTP-only cookie. - If the badge is missing or expired, the door stays closed: 401 Unauthorized.
In Spring Security this door is a filter in front of your controllers. Your @RestController methods should not parse the raw token by hand on every endpoint. The filter does that once, then puts the user on a tray called SecurityContext.
Realtime path: GET /api/me
The logged-in user opens “My profile”. The browser calls GET /api/me.
- Security filter reads the badge. If invalid → 401. Stop.
- If valid, Spring knows the email or user id for this request.
- Controller is thin:
return meService.getProfile(currentUserId). - Service loads the user through the repository.
- You return a DTO (a small JSON shape): name, email, title. Never the password hash.
That DTO is the plate you send back to the customer. The entity in the fridge can have extra columns the customer must never see.
Realtime path: POST /api/notes
Now the user types a note: “Revise @Transactional”. JSON body:
{"title":"Revise transactions","body":"Do not put SQL in the controller"}
- Door check again (filter + badge).
@PostMapping("/api/notes")reads the JSON with@RequestBody.@Validcan reject an empty title with 400 Bad Request before the kitchen runs.- Service creates a note for the logged-in user id from the token, not from a userId field in JSON.
- Repository
save()becomesINSERT INTO notes …. - Response is 201 with the new note id.
If you trust userId from the client body, anyone can save notes as someone else. In production, identity always comes from the badge, never from the plate the customer wrote.
401 vs 403 (two different “no”s)
- 401 = no badge, or badge expired. “Who are you?”
- 403 = we know who you are, but you cannot enter this room. Example: a normal user hitting
/api/admin/users.
Freshers mix these and then frontend teams show the wrong screen (login vs “you don’t have access”).
When something explodes: one error waiter
If the service throws “user not found”, do not leak a Java stack trace to the browser. Add a small @ControllerAdvice (or @RestControllerAdvice) class. It is one extra waiter who turns kitchen accidents into clean JSON:
{"error":"Note not found","status":404}
That is what Postman and React actually need. Stack traces stay in server logs for you.
application.properties is the restaurant address
Local:
server.port=8080
spring.datasource.url=jdbc:postgresql://localhost:5432/notes
spring.jpa.hibernate.ddl-auto=update
Production uses a different file or env vars: real host, no ddl-auto=update on a live database (that can rewrite tables by surprise). Spring profiles (dev, prod) switch the address without changing your Java code.
Practice for this page
On the same tiny Boot app from Entry 1:
- Protect
/api/meand/api/notesso they fail without a token. - Create a note as user A, then try to read it as user B — B should get 404 or 403, not A’s data.
- Send a note with an empty title and confirm you get 400, not a 500.
If you can draw GET /me and POST /notes on paper, with the badge at the door, you already understand more Spring than memorizing twenty annotations.
Next we can open transactions: what happens if saving the note succeeds but saving an audit row fails.
Comments (7)
GET /me after login is how we verify the filter chain in staging. If /me fails, auth never ran.
We also take user id from the token for POST /notes — body userId was our biggest security foot-gun.
@ControllerAdvice for 401/403 messages saved us from five duplicate try/catch blocks per controller.
For profiles dev vs prod, do you use spring.profiles.active in IDE run configs or only on the server?
Mention application.yml overrides — our juniors lost an hour because properties file order was wrong.
We strip stack traces in prod responses but keep them in dev profile. Matches your advice exactly.
Page 2 is what I send after the restaurant analogy. Together this is a full fresher onboarding doc.