1. Introduction

When you develop a REST API, you will face one of the most important security questions:

Who is asking, and what can they access?

This is where authentication and authorization come in.

Authentication

Authentication answers:

Who are you?

For example, when a user logs in using an email and password, the backend verifies the provided credentials.

Email + Password
       |
       v
Authentication
       |
       v
User Identity

If the credentials are valid, the user is authenticated.

Authorization

Authorization happens after authentication. It answers:

What can you access?

For example, an application can have two roles:

An ADMIN may be allowed to create, update, and delete products, while a USER may only be allowed to view products.

The difference can be summarized as:

Authentication → Who are you?
Authorization  → What can you access?

Why JWT?

For REST APIs, we may want authentication to be stateless.

Instead of keeping a traditional server-side session, the server can issue a token after successful login. The client then includes that token with subsequent requests.

The overall flow is:

Login
  |
  v
Validate Credentials
  |
  v
Generate JWT
  |
  v
Client Receives JWT
  |
  v
Client Sends JWT
  |
  v
Server Validates JWT
  |
  v
Access Allowed / Denied

In this article, we will explore the JWT authentication flow implemented with Spring Boot and Spring Security.

2. What Is JWT?

JWT stands for JSON Web Token.

It is a compact token format commonly used to pass information between a client and a server.

A JWT consists of three parts:

Header.Payload.Signature

A JWT has a structure similar to:

xxxxx.yyyyy.zzzzz

Header

The header contains information about the token, including the signing algorithm and token type.

For example:

{
  "alg": "HS256",
  "typ": "JWT"
}

The alg property identifies the algorithm used to sign the token, while typ identifies the token type.

Payload

The payload contains claims. Claims are pieces of information about the user or token.

For example:

{
  "sub": "[email protected]",
  "role": "USER",
  "iat": 1724500000,
  "exp": 1724503600
}

Common claims include:

The JWT payload is encoded, not encrypted by default. Therefore, sensitive information such as passwords should not be stored inside the payload.

Signature

The signature helps ensure that the token has not been altered.

Conceptually:

Signature = HMAC(Header + "." + Payload, Secret Key)

When the server receives the token, it can verify the signature. If the token has been modified, the signature verification will fail.

Stateless Authentication

Traditional session-based authentication can be represented as:

Client
  |
  v
Session
  |
  v
Server
  |
  v
Session Data

With JWT-based authentication:

Client
  |
  v
JWT
  |
  v
Server Validates JWT

JWT can be used in distributed applications and REST APIs because the server does not need to maintain a traditional session for every client.

3. Why Spring Security?

Sending a username and password is not enough to implement authentication in a real application.

An application also needs to handle:

Spring Security provides the security infrastructure for Spring applications.

Security rules can be defined centrally instead of implementing them separately in every controller.

A simplified request flow is:

HTTP Request
     |
     v
Spring Security
     |
     v
Authentication
     |
     v
Authorization
     |
     v
Controller

In Spring Security, authentication and authorization are separate concepts.

Authentication determines whether the user is authenticated.

Email + Password
       |
       v
AuthenticationManager
       |
       v
Credentials Valid
       |
       v
Authenticated

Authorization determines whether the authenticated user has permission to access a resource.

Authenticated User
       |
       v
Role
       |
       +----> USER
       |
       +----> ADMIN
       |
       v
Limited Access / Full Access

In simple terms:

Authentication → Who is the user?
Authorization  → What can the user access?

4. JWT Authentication Flow

Let's look at what happens when a user logs in and accesses a protected API.

The overall flow is:

Login Request
      |
      v
AuthenticationManager
      |
      v
UserDetailsService
      |
      v
Password Validation
      |
      v
Generate JWT
      |
      v
Return Token
      |
      v
Client
      |
      v
JWT Filter
      |
      v
Validate JWT
      |
      v
SecurityContext
      |
      v
Authorization
      |
      v
Protected API

Step 1: Login Request

The user provides credentials to the login endpoint.

POST /api/auth/login

For example:

{
  "email": "[email protected]",
  "password": "password123"
}

These credentials need to be verified by the backend.

Step 2: AuthenticationManager

Spring Security's AuthenticationManager handles the authentication request.

Login Request
      |
      v
AuthenticationManager

It attempts to authenticate the user using the configured authentication mechanism.

If the credentials are incorrect, authentication fails.

Step 3: UserDetailsService

Spring Security needs to retrieve the user's information from the database.

This is typically handled using UserDetailsService.

AuthenticationManager
       |
       v
UserDetailsService
       |
       v
Database
       |
       v
User

The user information can include:

The database should not store passwords as plain text. Passwords should be stored using a secure password-hashing mechanism, such as BCrypt.

Step 4: Generate JWT

After successful authentication, a JWT is generated with relevant claims such as the username, role, and expiration time.

Authenticated User
       |
       v
JWT Generator
       |
       v
Signed JWT

The token is then returned to the client.

Step 5: Client Sends the JWT

For subsequent requests, the client includes the JWT in the Authorization header.

For example:

GET /api/products
Authorization: Bearer <JWT>

The Bearer prefix indicates that the following value is a bearer token.

Step 6: JWT Filter

Before the request reaches the controller, the JWT authentication filter can inspect the request.

HTTP Request
      |
      v
JWT Filter
      |
      v
Authorization Header
      |
      v
Extract JWT

The filter extracts the token and checks whether it can be used for authentication.

Step 7: Validate JWT

The application validates the token, including its signature and expiration.

JWT
 |
 +-- Signature Validation
 |
 +-- Expiration Check
 |
 +-- Claims Extraction

If the token is invalid or expired, the request should not be considered authenticated.

Step 8: SecurityContext

If the JWT is valid, Spring Security can create an Authentication object and place it in the SecurityContext.

Valid JWT
    |
    v
Authentication Object
    |
    v
SecurityContext

Spring Security can now determine which user the request is associated with.

Step 9: Authorization

Finally, Spring Security verifies whether the authenticated user has permission to access the requested endpoint.

For example:

GET /api/products
       |
       v
Authenticated?
       |
      YES
       |
       v
Required Role?
       |
       v
Access Granted

For an endpoint that requires administrator permissions:

DELETE /api/products/{id}
       |
       v
Authenticated?
       |
       v
ADMIN Role?
    /     \
  YES      NO
   |        |
   v        v
 Allow     Deny

This completes the JWT authentication and authorization flow.

Key Takeaways

JWT authentication and Spring Security work together to provide a structured security flow for REST APIs.

The main concepts to remember are:

The overall lifecycle can be summarized as:

Login
  |
  v
Validate Credentials
  |
  v
Generate JWT
  |
  v
Client Stores Token
  |
  v
Client Sends JWT
  |
  v
JWT Filter
  |
  v
Validate Token
  |
  v
SecurityContext
  |
  v
Authorization
  |
  v
Protected API

Understanding this lifecycle makes it easier to work with JWT authentication and Spring Security when building Spring Boot REST APIs.