Spring Security Tutorial

30 posts in this section

LDAP Authentication: Enterprise Directory Integration

LDAP in the Enterprise LDAP (Lightweight Directory Access Protocol) is the standard protocol for directory services. Microsoft Active Directory, OpenLDAP, and many other enterprise identity providers use LDAP. If your application must authenticate users from a corporate directory, LDAP integration is the path. sequenceDiagram participant Client participant SpringSecurity as Spring Security participant LDAP as LDAP / Active Directory Client->>SpringSecurity: POST /login {username, password} SpringSecurity->>LDAP: Bind as service account (manager DN) LDAP-->>SpringSecurity: Bind success SpringSecurity->>LDAP: Search for user:\n(uid=alice,ou=users,dc=example,dc=com) LDAP-->>SpringSecurity: User DN found SpringSecurity->>LDAP: Bind as user (verify password) LDAP-->>SpringSecurity: Bind success = password correct SpringSecurity->>LDAP: Search groups for user LDAP-->>SpringSecurity: Groups: [cn=developers, cn=devops] SpringSecurity->>SpringSecurity: Map groups to roles SpringSecurity-->>Client: Authentication success (ROLE_DEVELOPER, ROLE_DEVOPS) Dependencies <!

Continue reading »

Method Security: @PreAuthorize, @PostAuthorize, @Secured

Why Method Security Exists URL-based authorization in authorizeHttpRequests() protects HTTP endpoints, but it has blind spots: The same service method may be called from multiple controllers, scheduled tasks, or message listeners — none of which pass through the HTTP filter chain Fine-grained rules based on method arguments or return values cannot be expressed as URL patterns Authorization logic spread across a large security config is hard to read alongside the code it protects Method security moves the authorization decision to the method itself.

Continue reading »

Multi-Factor Authentication (TOTP and WebAuthn)

Why MFA Matters A password alone is a single point of failure. Phishing, credential stuffing, and password reuse mean that knowing a password is not proof of identity. Multi-factor authentication requires something the user knows (password) and something they have (phone, hardware key) — compromising one factor is no longer sufficient. TOTP: Time-Based One-Time Passwords TOTP (RFC 6238) generates a 6-digit code that changes every 30 seconds, derived from a shared secret and the current time.

Continue reading »

OAuth2 Fundamentals: Grant Types and Flows

OAuth2 in One Sentence OAuth2 lets a user grant a third-party application limited access to their account on another service — without giving the third party their password. Classic example: “Sign in with Google.” Your app never sees the user’s Google password. Google verifies the user’s identity and gives your app a token with limited permissions. The Four OAuth2 Roles flowchart TD RO["**Resource Owner**\nThe user who owns the data\n(e.g. Alice, the Google account owner)"

Continue reading »

OAuth2 Login: Sign In with Google, GitHub, and Custom Providers

What OAuth2 Login Does OAuth2LoginConfigurer implements the Authorization Code flow for user authentication. When a user clicks “Sign in with Google”: Spring redirects to Google’s /authorize endpoint User authenticates on Google and grants consent Google redirects back to your app with a code Spring exchanges the code for tokens (back channel) Spring fetches the user profile from /userinfo Spring creates an OAuth2User and stores it in the SecurityContext Dependencies <dependency> <groupId>org.

Continue reading »

OAuth2 Resource Server: Protecting APIs with Bearer Tokens

What Is a Resource Server? In OAuth2, a Resource Server is an API that accepts access tokens and returns protected resources. It doesn’t issue tokens — that’s the Authorization Server’s job. The Resource Server just validates tokens and enforces access control. flowchart LR Client[API Client\nor SPA/Mobile] -->|"1. POST /token\n{client_id, secret}"| AS[Authorization Server\nGoogle / Okta / Custom] AS -->|"2. access_token"| Client Client -->|"3. GET /api/products\nAuthorization: Bearer {token}"| RS[Your Spring Boot API\nResource Server] RS -->|"

Continue reading »

Password Encoding: BCrypt, Argon2, and DelegatingPasswordEncoder

Why Passwords Must Be Hashed Storing plaintext passwords is a critical security failure. When a database is breached, attackers immediately have every user’s password — and because people reuse passwords, those credentials work on other sites too. Password hashing is not encryption. Encryption is reversible. Hashing is one-way: you can verify a password by hashing it and comparing to the stored hash, but you cannot recover the original password from the hash.

Continue reading »

Password Management: Registration, Reset, and Migration

Secure Registration Registration is where passwords enter your system. Get it wrong here and no amount of downstream security saves you. The Registration Flow User submits form → Validate password strength → Check username/email uniqueness → Encode password with PasswordEncoder → Persist user (disabled) → Send verification email → User clicks link → enable account Registration Endpoint @RestController @RequestMapping("/auth") public class RegistrationController { private final UserService userService; private final PasswordEncoder passwordEncoder; @PostMapping("/register") public ResponseEntity<Void> register(@Valid @RequestBody RegistrationRequest request) { userService.

Continue reading »

Reactive Security with Spring WebFlux

Reactive vs. Servlet Security Spring Security’s standard configuration targets Servlet-based applications (Spring MVC). Reactive applications built with Spring WebFlux run on a non-blocking event loop — there is no thread-per-request model, so ThreadLocal-based SecurityContextHolder does not work. Spring Security provides a parallel reactive stack: Servlet Reactive SecurityFilterChain SecurityWebFilterChain HttpSecurity ServerHttpSecurity SecurityContextHolder ReactiveSecurityContextHolder UserDetailsService ReactiveUserDetailsService AuthenticationManager ReactiveAuthenticationManager @EnableWebSecurity @EnableWebFluxSecurity @EnableMethodSecurity @EnableReactiveMethodSecurity Dependencies <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> Spring Security auto-configures reactive security when WebFlux is on the classpath.

Continue reading »

Refresh Tokens and Token Rotation

Why Refresh Tokens? Short-lived access tokens (15–60 minutes) limit the damage if a token is stolen — it expires quickly. But forcing users to log in every hour is terrible UX. Refresh tokens solve this: a long-lived token (7–30 days) stored securely lets the client silently obtain a new access token when the old one expires. The user stays logged in indefinitely without re-entering credentials. sequenceDiagram participant Client participant AuthServer as Auth Endpoint participant API as Protected API Client->>AuthServer: POST /api/auth/login AuthServer-->>Client: {accessToken: exp 15min, refreshToken: exp 7d} Note over Client,API: Normal API usage (15 min) Client->>API: GET /api/data\nAuthorization: Bearer {accessToken} API-->>Client: 200 OK Note over Client,API: Access token expires Client->>API: GET /api/data\nAuthorization: Bearer {expiredToken} API-->>Client: 401 Unauthorized Note over Client,API: Silent token refresh Client->>AuthServer: POST /api/auth/refresh\n{refreshToken} AuthServer-->>Client: {newAccessToken, newRefreshToken} Client->>API: GET /api/data\nAuthorization: Bearer {newAccessToken} API-->>Client: 200 OK Token Rotation: Every Refresh Issues a New Refresh Token Token rotation is the critical security mechanism: every time a refresh token is used, the server issues a new refresh token and invalidates the old one.

Continue reading »