Common Backend Vulnerabilities
Authentication & Authorization
Spring Security JWT authentication
In the last chapter, we learned how to securely verify a user's password using bcrypt. That process—verifying a user is who they claim to be—is the first crucial step. But what happens after they log in? How do we remember them on their next request? And how do we control what they are allowed to do?
This is where we move from a single check to a continuous process of managing a user's session and permissions. These two concepts, Authentication and Authorization, are the pillars of application access control.
While often used together, these terms represent distinct stages in the access control process. A secure system must implement both correctly.
Authentication is the process of confirming that a user is who they claim to be. It answers the question, "Who are you?".
Mechanism: It involves the user presenting one or more credentials (factors of authentication) that are validated by the system.
User Authentication Example: When a user submits a username and password via a login form, the backend authenticates them. It does this by hashing the provided password and comparing it to the securely stored hash in the database for that username. A match confirms the user's identity.
Service Authentication Example: Your backend service needs to fetch data from an external payment gateway API. To do so, your service includes a secret API key in its request header (e.g., Authorization: Bearer <secret_api_key>). The payment gateway authenticates the request by validating this key, confirming that the request is from a trusted and legitimate application.
Outcome: A successful authentication process establishes a trusted identity for the requesting entity. This is often represented by creating a session (for a user) or by simply granting access for that single API call (for a service).
There are many ways of implementing authentication:
Authorization is the process of determining if an authenticated user has the necessary permissions to perform a specific action or access a particular resource. It answers the question, "What are you allowed to do?".
Mechanism: This process happens after successful authentication. For every incoming request to a protected endpoint, the system checks the authenticated user's identity and associated permissions (e.g., roles, ownership) against an access control policy.
Web Application Example: An authenticated user with userId: 50 makes a GET request to /api/orders/123. The authorization logic on the backend must verify: "Does the user with ID 50 have permission to view order 123?" This could be based on a role (e.g., an ADMIN can view any order) or ownership (the user can only view their own orders). If they lack permission, the server must respond with an error, typically 403 Forbidden.
Outcome: A "Permit" or "Deny" decision for a specific request.
| Feature | Authentication | Authorization |
|---|---|---|
| Question | "Who are you?" | "What are you allowed to do?" |
| Process | Verifying credentials against a trusted source. | Enforcing access policies against an authenticated identity. |
| Output | A verified identity, often represented by a session or token. | A Permit / Deny decision (e.g., 200 OK vs. 403 Forbidden). |
| Timing | Typically happens once at the beginning of a session (login). | Happens on every request to a protected resource. |
HTTP is a stateless protocol. This means the server treats every request as a new, independent event, with no memory of past requests. Therefore, after a user authenticates, we need a mechanism to persist their identity across subsequent API calls. This is known as session management.
There are two primary architectural patterns for session management: stateful sessions and stateless tokens.
In this model, the server maintains the state of the user's session after login.
<aside> 💭
The session's state and data live on the server. The client only holds a random text as the session ID (also called opaque identifier).
</aside>
In this model, the server offloads the session state to the client in the form of a secure, self-contained token. The most common implementation is the JSON Web Token (JWT).
<aside> 💭
Stateless tokens can be a bit confusing to understand at first glance. It will be more clear soon with more info and example.
</aside>
https://www.youtube.com/watch?v=UBUNrFtufWo
The following video explains everything you need to know about JWT
https://www.youtube.com/watch?v=7Q17ubqLfaM
A JWT consists of three Base64Url-encoded parts, separated by dots:
<aside> ⌨️
Hands on:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiQXdlc29tZSBUcmFpbmVlIiwiY29ob3J0Ijo1NSwiZW1haWwiOiJ0cmFpbmVlQGhhY2t5b3VyZnV0dXJlLm5sIiwibGFuYXVnZXMiOlsiSmF2YSIsIkphdmFTY3JpcHQiLCJTUUwiXX0.HE8qR4355aY4Mfy0-r8hsIN9LQcbF2oZUlkZPkqyIMw
What is the trainee’s email?
hackyourfuture-hackyourfuture-hyf
</aside>
| --- | --- | --- |
<aside> 💭
</aside>
<aside> 💭
</aside>
The major drawback of JWTs is their difficult revocation. A stolen token is valid until it expires. A long expiration time is a security risk, while a short one degrades user experience. The Access Token / Refresh Token pattern solves this.
This pattern uses two different tokens:
The Authentication Flow:
This hybrid approach provides the stateless scalability of JWTs for most API calls while retaining the critical ability to revoke sessions by invalidating the refresh token in the database, offering a robust balance of security and user experience.