HttpSecurity

About

HttpSecurity is a Spring Security class that allows developers to configure security policies for their applications. It provides a fluent API to define security rules, including authentication, authorization, session management, CSRF protection, CORS, and custom security filters.

It is highly customizable and is used inside the SecurityFilterChain bean.

Responsibilities of HttpSecurity

Responsibility

Description

Authentication Configuration

Specifies login mechanisms (e.g., form-based login, HTTP Basic, OAuth2, JWT, etc.). Defines custom authentication filters.

Authorization Rules

Controls access to different resources based on user roles and permissions. Supports method-level security.

Session Management

Configures session policies (e.g., stateless sessions for REST APIs). Prevents session fixation attacks.

Cross-Site Request Forgery (CSRF) Protection

Enables or disables CSRF protection. Allows fine-grained control over CSRF behavior.

Cross-Origin Resource Sharing (CORS) Policies

Configures CORS rules for handling requests from different origins.

Security Headers Management

Sets HTTP security headers such as Strict-Transport-Security, X-Frame-Options, etc.

Adding Custom Security Filters

Allows adding custom authentication and authorization filters at specific positions in the filter chain.

Sample Usage

A standard Spring Security configuration using HttpSecurity looks like this -

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .csrf(csrf -> csrf.disable()) // Disable CSRF for APIs
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/public/**").permitAll() // Allow public access
                .requestMatchers("/admin/**").hasRole("ADMIN") // Only ADMIN can access
                .anyRequest().authenticated() // All other requests need authentication
            )
            .formLogin(Customizer.withDefaults()) // Enable default form-based login
            .logout(logout -> logout.logoutUrl("/logout").permitAll()); // Custom logout settings
        
        return http.build();
    }
}

Authentication Configuration

Spring Security allows authentication configuration through HttpSecurity. The authentication mechanism determines how users provide credentials and how the system validates them.

Syntax for Authentication Configuration

Authentication is configured inside a SecurityFilterChain bean:

  • authorizeHttpRequests(auth -> auth...) → Defines access rules for different endpoints.

  • requestMatchers("/public/**").permitAll() → Allows access without authentication.

  • requestMatchers("/admin/**").hasRole("ADMIN") → Restricts access to users with the ADMIN role.

  • anyRequest().authenticated() → Requires authentication for all other endpoints.

  • httpBasic(Customizer.withDefaults()) → Enables Basic Authentication.

  • formLogin(Customizer.withDefaults()) → Enables Form-Based Authentication.

1. Basic Authentication

HTTP Basic Authentication is a simple authentication scheme where the client sends a username and password in the Authorization header of each request. The credentials are Base64-encoded but not encrypted, making it insecure over HTTP (use HTTPS only). Suitable for APIs or internal applications where user sessions are not needed.

Configuring Basic Authentication

How Basic Authentication Works

  1. The client sends a request with an Authorization header:

    (Where dXNlcjpwYXNzd29yZA== is user:password encoded in Base64)

  2. Spring Security decodes the credentials and checks them against the user database.

  3. If valid, access is granted; otherwise, a 401 Unauthorized response is returned.

circle-check

When to Use Basic Authentication

2. Form-Based Authentication

Form-Based Authentication uses an HTML login page where users enter their credentials. The credentials are submitted to a login endpoint, verified by Spring Security, and a session is created.

Configuring Form-Based Authentication

How Form-Based Authentication Works

  1. The user navigates to /login and enters their credentials.

  2. The credentials are sent via POST to /login (default endpoint).

  3. Spring Security authenticates the user and creates a session.

  4. If successful, the user is redirected to /home.

  5. If failed, they are redirected to /login?error=true.

circle-check

Customizing Login & Logout

3. JWT Authentication (Using Custom Filter)

JWT (JSON Web Token) Authentication is a stateless authentication mechanism. A token is generated after login and sent with each request instead of using sessions.

Configuring JWT Authentication

Create a Custom JWT Filter

Register JWT Filter in Security Configuration

How JWT Authentication Works

  1. User logs in and receives a JWT token.

  2. The token is included in the Authorization header (Bearer <token>) for every request.

  3. The JWT filter extracts and validates the token.

  4. If valid, authentication is set in the SecurityContext.

circle-check

When to Use JWT Authentication

4. OAuth2 Login (Social Logins)

Allows authentication using external providers like Google, Facebook, GitHub, etc. Users don't need to enter credentials in the application; they authenticate via the provider.

Configuring OAuth2 Login

How OAuth2 Authentication Works

  1. The user is redirected to Google/GitHub/etc. for login.

  2. After authentication, the provider sends an authorization code.

  3. Spring Security exchanges this code for an access token.

  4. The application retrieves user details and grants access.

circle-check

When to Use OAuth2 Authentication

Authorization Rules

Authorization determines what actions an authenticated user can perform. Spring Security provides several ways to define access control, including:

  1. Role-Based Access Control (RBAC)

  2. Method-Level Security

Configuring Authorization Rules in Spring Security

Spring Security defines authorization rules inside the SecurityFilterChain using authorizeHttpRequests().

Basic Authorization Configuration

  • permitAll() → Allows access to everyone (unauthenticated users).

  • hasRole("USER") → Allows only users with the USER role.

  • hasRole("ADMIN") → Restricts access to users with the ADMIN role.

  • anyRequest().authenticated() → Requires authentication for all other endpoints.

1. Role-Based Access Control

RBAC is a security model where access is granted based on user roles.

Defining User Roles

In Spring Security, user roles are typically stored in a UserDetailsService.

Example: Creating a User with Roles

  • The roles() method automatically prefixes "ROLE_" to the given role names.

  • roles("USER") becomes ROLE_USER in the system.

Role-Based Authorization in Security Configuration

circle-info
  • First, Spring Security checks if the request matches /admin/**

    • If YES, it checks if the user has ROLE_ADMIN.

    • If NO, it moves to the next rule.

  • Then, it checks if the request matches /user/**

    • If YES, it checks if the user has ROLE_USER or ROLE_ADMIN.

    • If NO, it moves to the next rule.

  • Then, it checks if the request matches /reports/**

    • If YES, it checks if the user has the REPORT_VIEW permission.

    • If NO, it moves to the next rule.

  • For all other requests (anyRequest())

    • If a request does NOT match any of the above paths (/admin/**, /user/**, /reports/**), this rule applies:

    • This means all other endpoints require authentication (but no specific role/authority is needed).

    • The user just needs to log in to access these routes.

If we changed it to

  • Then any request that doesn't match /admin/**, /user/**, or /reports/** would be publicly accessible (no authentication required).

hasAuthority() vs. hasRole()

Method

Description

hasRole("ADMIN")

Checks if user has ROLE_ADMIN (Spring Security adds the ROLE_ prefix).

hasAuthority("REPORT_VIEW")

Checks if user has the specific authority/permission (without ROLE_ prefix).

hasAnyRole("USER", "ADMIN")

Allows users with either ROLE_USER or ROLE_ADMIN.

hasAnyAuthority("READ_PRIVILEGES", "WRITE_PRIVILEGES")

Allows users with at least one of the specified permissions.

Storing Permissions Instead of Roles

If we need fine-grained permissions (e.g., READ_PRIVILEGES, EDIT_POST), use Authorities instead of roles.

  • Roles → Used for broad access control (e.g., ROLE_ADMIN, ROLE_USER).

  • Authorities → Used for fine-grained permissions (e.g., EDIT_POST, DELETE_USER).

2. Method-Level Security

Spring Security allows restricting access at the method level using annotations.

Enabling Method Security

Add @EnableMethodSecurity in the configuration class:

@PreAuthorize - Check Before Method Execution

Example: Restricting API Calls

@PreAuthorize("hasRole('ADMIN')") → Only allows users with ROLE_ADMIN to execute the method.

@PostAuthorize - Check After Method Execution

Used when authorization depends on the returned object.

The method runs first, and then Spring Security checks if the returned object's username matches the logged-in user.

@Secured - Alternative to @PreAuthorize

Unlike @PreAuthorize, @Secured does not support SpEL expressions.

@RolesAllowed - JSR-250 Alternative

Works like @Secured, but allows specifying multiple roles.

Combining Role-Based & Method-Level Security

Combining URL-Based Security (authorizeHttpRequests()) and Method-Level Security (@PreAuthorize, @PostAuthorize) provides multiple layers of security, ensuring that:

  1. Unauthorized requests are blocked as early as possible (at the filter level).

  2. Granular, context-aware security rules can be enforced at the service level.

circle-info

Problems with Using Only URL-Based Security

If we rely only on authorizeHttpRequests(), we may face security loopholes: Pros:

  • Easy to configure in HttpSecurity.

  • Centralized security rules for REST APIs.

  • Protects against direct access via URLs.

Cons:

  • Only protects controller endpoints (not service methods).

  • Does not protect internal method calls.

  • If a new API method is introduced and not explicitly secured, it might be accidentally left open.

Problems with Using Only Method-Level Security

If we rely only on @PreAuthorize, @PostAuthorize, or @Secured: Pros:

  • Fine-grained security at method level.

  • Can apply dynamic authorization logic (e.g., checking if the user owns a resource).

  • Works well for non-REST applications (like microservices or service-layer security).

Cons:

  • Methods are still exposed via HTTP endpoints unless restricted by HttpSecurity.

  • No centralized visibility—developers must check each method for security annotations.

  • Does not block unauthorized requests early (the request still reaches the service layer).

Example: Combining Both Approaches

Controller with Method-Level Security

Session Management

Session management controls how user sessions are created, maintained, and invalidated in a Spring Security-based application. It is crucial for:

  • Security (Preventing session hijacking, session fixation)

  • Performance (Reducing server memory usage)

  • Scalability (Especially for REST APIs where stateless authentication is preferred)

Configuring Session Management in Spring Security

Spring Security allows configuring session management using sessionManagement() in the HttpSecurity configuration.

Stateless Session (For REST APIs)

REST APIs should be stateless to ensure scalability and avoid session-based authentication overhead.

Why Stateless Sessions for REST APIs?

  • Improves scalability (No need to store session data in memory)

  • Better performance (Avoids extra lookups for session validation)

  • Ideal for microservices (No need for session replication across nodes)

How to Implement Stateless Sessions in Spring Security?

Use SessionCreationPolicy.STATELESS to disable session management.

  • sessionCreationPolicy(SessionCreationPolicy.STATELESS) → Prevents the creation of a session.

  • No HttpSession is stored or used → Every request must include authentication (e.g., JWT token).

  • Disables CSRF (csrf.disable()) → CSRF protection is not needed in stateless APIs.

  • Custom JWT Filter (JwtAuthenticationFilter) → Extracts user authentication from JWT in each request.

Example: Custom JWT Authentication Filter

  • Extracts the JWT token from the request header.

  • Validates the token and retrieves user details.

  • Sets the user authentication in SecurityContextHolder.

Preventing Session Fixation Attacks

A session fixation attack occurs when an attacker tricks a user into using a known session ID, allowing them to hijack the session after login.

How to Prevent Session Fixation?

Spring Security provides built-in protection using sessionFixation().

Session Fixation Strategies in Spring Security

Strategy

Description

migrateSession() (Default)

Creates a new session ID but retains session attributes.

newSession()

Creates a completely new session, discarding previous session attributes.

none()

No protection against session fixation (not recommended).

Example: Custom Login Handler to Invalidate Old Sessions

  • Invalidates old sessions after successful login.

  • Prevents session fixation attacks by creating a new session.

Managing Concurrent Sessions

Spring Security allows limiting the number of concurrent sessions per user.

Explanation

  • maximumSessions(1) → Restricts users to a single active session.

  • maxSessionsPreventsLogin(true) → Prevents a new login if the user is already logged in elsewhere.

CSRF Protection

Cross-Site Request Forgery (CSRF) is a web security vulnerability that allows an attacker to execute unauthorized actions on behalf of an authenticated user. Spring Security provides built-in CSRF protection, which is enabled by default for web applications. However, for stateless APIs, it is typically disabled.

circle-check

Disabling CSRF for APIs

Since REST APIs are typically stateless, CSRF protection is not needed. API clients (e.g., mobile apps, Postman) do not rely on browser cookies, which makes CSRF attacks irrelevant.

circle-check

Enabling CSRF for Web Applications

For web applications using session-based authentication (cookies), CSRF protection should remain enabled.

  • csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) → Stores the CSRF token in a cookie, making it accessible to JavaScript for AJAX requests.

  • withHttpOnlyFalse() → Allows JavaScript to read the token for AJAX calls.

How the CSRF Token Works Here?

  • Spring Security sends a CSRF token in a cookie (XSRF-TOKEN).

  • The frontend must send the token in the X-CSRF-TOKEN header in AJAX requests.

Example: Fetching the CSRF Token in JavaScript

CORS

CORS is a security mechanism implemented by browsers to restrict cross-origin HTTP requests. It prevents unauthorized websites from making requests to your backend services.

Same-Origin Policy (SOP): By default, browsers block requests if the origin (protocol, domain, and port) is different from the requested resource.

CORS Policy: CORS allows web applications to bypass SOP and make cross-origin requests by defining allowed origins, methods, headers, etc.

Spring provides multiple ways to configure CORS:

  • Using WebMvcConfigurer (Global CORS Policy)

  • Using HttpSecurity (Security-Specific CORS Configuration)

  • Configuring it for specific controllers

CORS Configuration

Spring Security adds an additional layer of security that might override global CORS settings. We need to explicitly enable it in HttpSecurity.

  • This configures CORS inside Spring Security, ensuring security rules don’t block valid requests.

  • Uses CorsConfigurationSource to define allowed origins, methods, and headers.

Security Headers

Apart from CORS, Spring Security also enforces security headers to protect against various web vulnerabilities.

Default Security Headers Added by Spring Security

Spring Security adds the following headers automatically:

Header

Purpose

X-Frame-Options: DENY

Prevents Clickjacking attacks.

X-Content-Type-Options: nosniff

Prevents MIME type sniffing.

Strict-Transport-Security

Forces HTTPS connections.

X-XSS-Protection: 1; mode=block

Protects against XSS attacks.

Content-Security-Policy

Prevents inline JavaScript execution.

Customizing Security Headers

If we need custom headers, we can configure them using HttpSecurity.headers().

  • contentSecurityPolicy("default-src 'self'") → Restricts resources to the same domain.

  • frameOptions(frame -> frame.sameOrigin()) → Allows embedding only from the same domain.

  • xssProtection(xss -> xss.block(true)) → Enables XSS blocking.

We might need to disable certain headers in some cases, e.g., when using custom security mechanisms.

Custom Security Filters

A security filter in Spring Security is a component that intercepts HTTP requests and applies security logic before passing them to the application.

  • Spring Security uses a filter chain to process authentication, authorization, and other security concerns.

  • Filters allow us to modify request/response handling at different stages.

Custom filters are needed when:

  • Adding custom authentication mechanisms (e.g., API key authentication).

  • Logging request details for security auditing.

  • Implementing rate limiting for APIs.

  • Validating JWT tokens in a custom way.

  • Modifying headers before passing requests to controllers.

Adding a Custom Filter

Example: Logging All Incoming Requests

Let’s create a filter that logs request details before passing them to controllers.

  • OncePerRequestFilter ensures the filter runs once per request.

  • Logs request details (method and URI).

  • Passes control to the next filter (filterChain.doFilter(...)).

Registering the Filter in Spring Security

We need to add the filter to the Spring Security filter chain.

  • addFilterBefore(requestLoggingFilter, UsernamePasswordAuthenticationFilter.class)Runs the custom filter before authentication.

Last updated