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.

Code
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:

  • USER

  • ADMIN

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:

Code
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:

Code
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:

Code
Header.Payload.Signature

A JWT has a structure similar to:

Code
xxxxx.yyyyy.zzzzz

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

For example:

Code
{
  "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:

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

Common claims include:

  • sub: Subject or user identifier

  • iat: Issued-at time

  • exp: Expiration time

  • role: User role

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:

Code
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:

Code
Client
  |
  v
Session
  |
  v
Server
  |
  v
Session Data

With JWT-based authentication:

Code
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:

  • Password verification

  • Authentication

  • Authorization

  • Roles and permissions

  • Request filtering

  • Security context

  • Protected endpoints

  • Authentication failures

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:

Code
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.

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

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

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

In simple terms:

Code
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:

Code
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.

Code
POST /api/auth/login

For example:

Code
{
  "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.

Code
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.

Code
AuthenticationManager
       |
       v
UserDetailsService
       |
       v
Database
       |
       v
User

The user information can include:

  • Email

  • Password

  • Role

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.

Code
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:

Code
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.

Code
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.

Code
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.

Code
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:

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

For an endpoint that requires administrator permissions:

Code
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:

  • Authentication determines who the user is.

  • Authorization determines what the user can access.

  • JWT provides a token-based mechanism that can be used for stateless authentication.

  • AuthenticationManager handles the authentication process.

  • UserDetailsService retrieves user information.

  • The JWT filter extracts and validates the token from incoming requests.

  • The SecurityContext holds the authenticated user's security information for the current request.

  • Roles and permissions are used to control access to protected resources.

The overall lifecycle can be summarized as:

Code
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.