Spring Security Authentication with MySQL: A Complete Beginner Guide

Adding authentication to a Spring Boot application is one of the first steps toward creating a secure REST API. While Spring Security provides a powerful framework, it can initially feel overwhelming because many different components work together.

This guide explains the entire authentication flow in simple terms, including common pitfalls such as receiving 403 Forbidden responses even after a successful login.


What Spring Security Actually Does

When a user logs in, Spring Security performs four major steps:

  1. Receives the username and password.
  2. Loads the user from the database.
  3. Verifies the password.
  4. Stores the authenticated user.

If using session authentication, Spring creates an HTTP session and sends a JSESSIONID cookie back to the client.

Subsequent requests simply send that cookie instead of sending the username and password again.

Client
   |
POST /login
(username/password)
   |
Spring Security
   |
AuthenticationManager
   |
UserDetailsService
   |
MySQL Database
   |
Authentication Success
   |
Create HTTP Session
   |
Return JSESSIONID Cookie

Creating the User Entity

A typical user table contains information similar to:

  • Username
  • Password
  • Full name
  • Role
  • Profile picture identifier
  • Internal user identifier

The password should always be stored using BCrypt.

Never store passwords in plain text.


Loading Users from MySQL

Spring Security never queries the database directly.

Instead, it asks a class implementing UserDetailsService.

Its job is simple:

  • Find the user
  • Throw an exception if the user doesn’t exist
  • Return a Spring Security UserDetails

Example flow:

Login Request

↓

UserDetailsService

↓

User Repository

↓

MySQL

↓

UserDetails

Roles and Authorities

Many beginners assume that simply authenticating a user is enough.

It isn’t.

Spring Security distinguishes between:

  • Authentication
  • Authorization

Authentication answers:

Who are you?

Authorization answers:

What are you allowed to access?

If an endpoint requires

ROLE_USER

then the authenticated user must actually have that authority.

For example:

ROLE_USER
ROLE_ADMIN
ROLE_MANAGER

If the authority doesn’t exist, authentication succeeds but authorization fails with:

403 Forbidden

Protecting REST Endpoints

Public endpoints might include:

  • Login
  • Registration
  • Health checks
  • Public resources

Everything else should require authentication.

Typical configuration:

/login
/register
/public/**

↓

Permit All

Everything else

↓

Authenticated

Session Authentication

Session authentication is still one of the simplest approaches for traditional web applications.

After login:

POST /login

↓

Authentication Successful

↓

Spring creates session

↓

JSESSIONID

↓

Browser/Postman stores cookie

↓

Future requests automatically send cookie

The backend simply looks up the session instead of authenticating the user again.


Understanding JSESSIONID

Receiving a JSESSIONID cookie only means:

A session exists.

It does not necessarily mean the user is authenticated.

Spring stores authentication separately inside the session.

If authentication never reaches the Security Context, the session exists but contains no authenticated user.

This often leads to confusion.


Why 403 Forbidden Happens After Login

One of the most common beginner problems is:

  • Login returns HTTP 200
  • JSESSIONID is received
  • Every protected endpoint returns
403 Forbidden

This usually means one of the following:

1. User Has No Authority

Authentication succeeded.

Authorization failed.


2. Wrong Role Name

Spring typically expects:

ROLE_USER

not

USER

unless configured otherwise.


3. Authentication Was Never Saved

A custom authentication filter may authenticate the user but never store the Authentication object inside the Security Context.

Without this step, every subsequent request appears anonymous.


4. Stateless Sessions

Using

SessionCreationPolicy.STATELESS

disables HTTP sessions.

No authentication is remembered between requests.

This setting is intended for JWT authentication, not JSESSIONID authentication.


5. Authentication Filter Doesn’t Continue the Filter Chain

A custom filter should either:

  • Continue processing
  • Or correctly finish authentication

Improper filter implementation can prevent Spring Security from saving the authenticated user.


The Difference Between 401 and 403

Many developers confuse these responses.

401 Unauthorized

Means:

You are not authenticated.

Examples:

  • Missing session
  • Missing JWT
  • Invalid credentials

403 Forbidden

Means:

You are authenticated, but you don’t have permission.

This distinction is extremely important during debugging.


Debugging Spring Security

One of the easiest ways to diagnose security problems is enabling debug logging.

Spring Security prints messages explaining:

  • Who authenticated
  • Which filter processed the request
  • Which authorities were loaded
  • Why access was denied

These logs often identify the exact configuration issue.


Preparing for Angular

Many developers initially use sessions while testing with Postman before moving to Angular.

There are two common approaches.

Session Authentication

Advantages

  • Very easy
  • Automatic cookie handling
  • Minimal code

Disadvantages

  • Server stores sessions
  • Requires cookie support

JWT Authentication

Advantages

  • Stateless
  • Better for SPAs
  • Better for mobile apps
  • Easier horizontal scaling

Disadvantages

  • Slightly more complex
  • Requires token management

Most Angular applications eventually migrate to JWT authentication.


Recommended Development Workflow

A practical progression looks like this:

  1. Create User entity
  2. Create UserRepository
  3. Implement UserDetailsService
  4. Configure AuthenticationManager
  5. Create login endpoint
  6. Verify BCrypt passwords
  7. Verify authorities
  8. Test with Postman
  9. Protect endpoints
  10. Integrate Angular

Building the authentication system incrementally makes debugging much easier.


Common Beginner Mistakes

Avoid these frequent issues:

  • Storing plain-text passwords
  • Forgetting BCrypt encoding
  • Missing ROLE_ prefix
  • Using stateless sessions with JSESSIONID
  • Not saving Authentication into the Security Context
  • Assuming a session automatically means authentication
  • Mixing JWT and session authentication
  • Forgetting to whitelist the login endpoint
  • Returning custom login responses without preserving authentication
  • Ignoring Spring Security debug logs

Best Practices

For a maintainable Spring Security implementation:

  • Always hash passwords with BCrypt.
  • Separate authentication from authorization.
  • Store user roles in the database.
  • Keep public endpoints to a minimum.
  • Enable debug logging during development.
  • Test authentication thoroughly with Postman before integrating a frontend.
  • Decide early whether the application will use sessions or JWT tokens.
  • Avoid mixing multiple authentication mechanisms unless absolutely necessary.

Conclusion

Spring Security provides a robust foundation for securing REST APIs, but it requires understanding how authentication, authorization, sessions, and roles interact.

A successful login is only one part of the process. Protected endpoints also require the authenticated user’s information to be correctly stored and recognized on subsequent requests. Many issues—such as receiving a 403 Forbidden response despite having a valid JSESSIONID—are usually caused by missing authorities, incorrect session configuration, or an incomplete authentication flow.

By understanding each component individually and testing incrementally, developers can build a secure, scalable backend that is ready for future integration with frameworks such as Angular while following modern Spring Security best practices.


References

  • Spring Security Reference Documentation
  • Spring Boot Reference Guide
  • Spring Framework Documentation
  • Jakarta Servlet Specification
  • OWASP Authentication Cheat Sheet
This article is inspired by real-world challenges we tackle in our projects. If you're looking for expert solutions or need a team to bring your idea to life,

Let's talk!

    Please fill your details, and we will contact you back

      Please fill your details, and we will contact you back