Chaturmind
LearnDSASystem DesignInterview PrepDevOpsEngineering GrowthBlog
Start learning
Chaturmind

Structured learning paths for engineers who want to go deep. Written by practitioners.

Learn

  • Java
  • DSA
  • System Design
  • Spring Boot
  • AI / ML
  • DevOps
  • Engineering Growth
  • Java Interview Prep

Company

  • Blog
  • Contact

Legal

  • Privacy Policy
  • Terms of Service

© 2026 Chaturmind. All rights reserved.

Built for engineers who want to go deep.


← Java Interview Prep: 8+ Years (Senior & Lead)

Expert Core Java

  • Tricky Java Output, Operators & OOP Edge Cases — Interview Questions
  • Tricky Exceptions, Memory & Keyword Questions — Interview Questions
  • Classic Java Language Questions, Senior-Grade Answers — Interview Questions
  • Classic Collections, Threads & JDK APIs, Senior-Grade Answers — Interview Questions
  • Reflection, Dynamic Proxies, final & Modern OOP Design — Interview Questions

JVM Internals & Performance

  • Class Loading, Bytecode & Object Layout — Interview Questions
  • JIT Compilation & Runtime Optimisations — Interview Questions
  • Garbage Collectors Deep Dive — Interview Questions
  • JVM Tuning, GC Logs & Memory Footprint — Interview Questions
  • Memory Leaks, OutOfMemoryErrors & Profiling Tools — Interview Questions
  • Modules, Agents & Advanced JVM APIs — Interview Questions

Collections & Concurrency at Scale

  • Collections Internals & Complexity — Interview Questions
  • Iterators, Comparators & Ordering Contracts — Interview Questions
  • Concurrent Collections, Queues & Lock-Free Structures — Interview Questions
  • Threads, Executors & ForkJoin Internals — Interview Questions
  • Locks, Atomics, CAS & Synchronizers — Interview Questions
  • Java Memory Model, volatile, Fences & ThreadLocal — Interview Questions
  • Deadlock, Livelock, Starvation & Concurrent Design — Interview Questions
  • CompletableFuture, Parallel Streams & Non-Blocking I/O — Interview Questions

Modern Java (8 to 21+)

  • Lambdas & Functional Interfaces Internals — Interview Questions
  • Streams & Collectors Deep Dive — Interview Questions
  • Optional & Interface Default/Static Methods — Interview Questions
  • Java 9–25 Features & Virtual Threads — Interview Questions

Design Patterns, SOLID & Clean Code

  • Design Pattern Trade-offs & Combinations — Interview Questions
  • SOLID, Clean Code & Anti-Patterns — Interview Questions

Spring & Spring Boot Internals

  • IoC, Dependency Injection & Bean Lifecycle Internals — Interview Questions
  • Spring AOP, Proxies & @Async Internals — Interview Questions
  • Spring Configuration, Auto-Configuration & Custom Starters — Interview Questions
  • Spring MVC & REST Internals, Exception Frameworks — Interview Questions
  • Spring Security Advanced Internals — Interview Questions
  • Spring WebFlux, Reactor & R2DBC — Interview Questions
  • Spring Cloud, Observability & Distributed Tracing — Interview Questions
  • Spring Boot 3, Native Images & Production Scenarios — Interview Questions

JPA, Hibernate & Databases at Scale

  • Spring Data JPA — Queries, Projections, Custom Repositories & Locking — Interview Questions
  • JPA Entity Mapping, Associations & Cascades — Interview Questions
  • JPQL vs Native Queries in Depth — Interview Questions
  • Hibernate Caching — First-Level, Second-Level & Query Cache — Interview Questions
  • Lazy vs Eager Loading, LazyInitializationException & N+1 — Interview Questions
  • JPA Transactions, Propagation, Isolation & Dirty Checking — Interview Questions
  • SQL vs NoSQL, Indexing & Query Tuning — Interview Questions
  • Database Scaling, Replication, Pooling & Consistency Models — Interview Questions
  • Redis, Search, Time-Series, CDC & Transactional Data Modelling — Interview Questions

Testing Strategy & API Design

  • Spring Boot Test Slices, Context & Test Strategy — Interview Questions
  • Testing Web, Persistence, Security, Async & Messaging in Spring Boot — Interview Questions
  • JUnit 5 & Mockito, Advanced — Interview Questions
Chaturmind
← Java Interview Prep: 8+ Years (Senior & Lead)

Expert Core Java

  • Tricky Java Output, Operators & OOP Edge Cases — Interview Questions
  • Tricky Exceptions, Memory & Keyword Questions — Interview Questions
  • Classic Java Language Questions, Senior-Grade Answers — Interview Questions
  • Classic Collections, Threads & JDK APIs, Senior-Grade Answers — Interview Questions
  • Reflection, Dynamic Proxies, final & Modern OOP Design — Interview Questions

JVM Internals & Performance

  • Class Loading, Bytecode & Object Layout — Interview Questions
  • JIT Compilation & Runtime Optimisations — Interview Questions
  • Garbage Collectors Deep Dive — Interview Questions
  • JVM Tuning, GC Logs & Memory Footprint — Interview Questions
  • Memory Leaks, OutOfMemoryErrors & Profiling Tools — Interview Questions
  • Modules, Agents & Advanced JVM APIs — Interview Questions

Collections & Concurrency at Scale

  • Collections Internals & Complexity — Interview Questions
  • Iterators, Comparators & Ordering Contracts — Interview Questions
  • Concurrent Collections, Queues & Lock-Free Structures — Interview Questions
  • Threads, Executors & ForkJoin Internals — Interview Questions
  • Locks, Atomics, CAS & Synchronizers — Interview Questions
  • Java Memory Model, volatile, Fences & ThreadLocal — Interview Questions
  • Deadlock, Livelock, Starvation & Concurrent Design — Interview Questions
  • CompletableFuture, Parallel Streams & Non-Blocking I/O — Interview Questions

Modern Java (8 to 21+)

  • Lambdas & Functional Interfaces Internals — Interview Questions
  • Streams & Collectors Deep Dive — Interview Questions
  • Optional & Interface Default/Static Methods — Interview Questions
  • Java 9–25 Features & Virtual Threads — Interview Questions

Design Patterns, SOLID & Clean Code

  • Design Pattern Trade-offs & Combinations — Interview Questions
  • SOLID, Clean Code & Anti-Patterns — Interview Questions

Spring & Spring Boot Internals

  • IoC, Dependency Injection & Bean Lifecycle Internals — Interview Questions
  • Spring AOP, Proxies & @Async Internals — Interview Questions
  • Spring Configuration, Auto-Configuration & Custom Starters — Interview Questions
  • Spring MVC & REST Internals, Exception Frameworks — Interview Questions
  • Spring Security Advanced Internals — Interview Questions
  • Spring WebFlux, Reactor & R2DBC — Interview Questions
  • Spring Cloud, Observability & Distributed Tracing — Interview Questions
  • Spring Boot 3, Native Images & Production Scenarios — Interview Questions

JPA, Hibernate & Databases at Scale

  • Spring Data JPA — Queries, Projections, Custom Repositories & Locking — Interview Questions
  • JPA Entity Mapping, Associations & Cascades — Interview Questions
  • JPQL vs Native Queries in Depth — Interview Questions
  • Hibernate Caching — First-Level, Second-Level & Query Cache — Interview Questions
  • Lazy vs Eager Loading, LazyInitializationException & N+1 — Interview Questions
  • JPA Transactions, Propagation, Isolation & Dirty Checking — Interview Questions
  • SQL vs NoSQL, Indexing & Query Tuning — Interview Questions
  • Database Scaling, Replication, Pooling & Consistency Models — Interview Questions
  • Redis, Search, Time-Series, CDC & Transactional Data Modelling — Interview Questions

Testing Strategy & API Design

  • Spring Boot Test Slices, Context & Test Strategy — Interview Questions
  • Testing Web, Persistence, Security, Async & Messaging in Spring Boot — Interview Questions
  • JUnit 5 & Mockito, Advanced — Interview Questions
HomeLearnJava Interview PrepJava Interview Prep: 8+ Years (Senior & Lead)Spring & Spring Boot Internals
✓ FreeAdvanced· 8 min read

Spring Security Advanced Internals — Interview Questions

Method-level RBAC and dynamic permission checks, custom AuthenticationProviders, invalidating stateless JWTs, opaque tokens vs JWTs, how @PreAuthorize works behind the scenes, @Secured vs @RolesAllowed vs @PreAuthorize, session-based vs stateless login, OAuth2 vs JWT (not the same kind of thing), and Spring Authorization Server.

Published September 25, 2026


How to use this lesson

The basics (the filter chain, SecurityFilterChain, JWT flows) are covered in the 5–8 years tier. This lesson goes deeper: authorisation internals, token lifecycle trade-offs, and identity-provider choices. Use Spring Security 6 APIs (AuthorizationManager, @EnableMethodSecurity).

Q1. How do you implement role-based access control at method level, including dynamic rules?

Short answer:

  1. Enable it with @EnableMethodSecurity (Spring Security 6; it replaces @EnableGlobalMethodSecurity).
  2. Annotate the service methods:
    • @PreAuthorize("hasRole('ADMIN')");
    • hasAuthority('SCOPE_orders.write');
    • SpEL with the arguments: @PreAuthorize("#userId == authentication.name");
    • @PostAuthorize("returnObject.ownerId == authentication.name"), for object-level checks on results;
    • @PreFilter/@PostFilter for collections (with care, because they filter in memory).
  3. For dynamic, data-driven permissions, delegate to a bean, @PreAuthorize("@orderPolicy.canApprove(authentication, #orderId)"), or implement a PermissionEvaluator (hasPermission(#id, 'Order', 'APPROVE')). The policy bean can consult a database, ABAC attributes, or an external policy engine (OPA, Cerbos).
  4. Map roles to authorities from the JWT claims (JwtAuthenticationConverter), or from the database. Use a RoleHierarchy bean for ADMIN > MANAGER > USER.
@Component("orderPolicy")
class OrderPolicy {
    boolean canApprove(Authentication auth, UUID orderId) {
        Order o = orders.find(orderId);
        return auth.getAuthorities().stream().anyMatch(a -> a.getAuthority().equals("ROLE_MANAGER"))
            && o.region().equals(regionOf(auth))
            && o.total().compareTo(limitFor(auth)) <= 0;             // approval limit per manager
    }
}

@PreAuthorize("@orderPolicy.canApprove(authentication, #orderId)")
public void approve(UUID orderId) { ... }

Learn it in depth → Role-Based Access Control

Q2. How do you implement a custom AuthenticationProvider?

Short answer: Implement AuthenticationProvider:

  • authenticate(Authentication) validates the credentials in the incoming token, and returns an authenticated Authentication, with authorities. It throws AuthenticationException subclasses on failure (BadCredentialsException, LockedException), or returns null to let other providers try.
  • supports(Class<?>) declares which Authentication types it handles.

Register it as a bean, or on HttpSecurity/AuthenticationManager. ProviderManager iterates through the providers.

@Component
class ApiKeyAuthenticationProvider implements AuthenticationProvider {
    private final ApiKeyService keys;
    ApiKeyAuthenticationProvider(ApiKeyService keys) { this.keys = keys; }

    @Override public Authentication authenticate(Authentication auth) {
        String presented = (String) auth.getCredentials();
        ApiClient client = keys.findByHashedKey(sha256(presented))                     // store hashes, never raw keys
                .orElseThrow(() -> new BadCredentialsException("Invalid API key"));
        return ApiKeyAuthenticationToken.authenticated(client.id(), client.authorities());
    }
    @Override public boolean supports(Class<?> type) { return ApiKeyAuthenticationToken.class.isAssignableFrom(type); }
}

It's paired with a filter (or AuthenticationConverter + AuthenticationFilter) that extracts the credential from the request.

Use cases: API keys, a legacy SSO token, OTP or MFA steps, LDAP plus custom rules, and partner-issued signatures. Use constant-time comparisons, rate limiting and audit logging.

Q3. How do you invalidate JWTs, since they're stateless?

Short answer: You can't "delete" a self-contained signed token, so you limit its life, and add state where necessary:

  • Short-lived access tokens (5–15 minutes), plus refresh tokens that are stored server-side, rotated, and revocable. Logout or compromise revokes the refresh token, and the access token dies soon after.
  • A denylist of revoked jti values (in Redis, with a TTL equal to the token's remaining lifetime), checked by the resource servers. It adds a lookup per request, but only for the short remaining window.
  • Token versioning: a tokenVersion or sessionVersion claim, compared against the user's current version (bumped on password change or "log out everywhere").
  • Switch to opaque tokens with introspection where immediate revocation is required.
  • Key rotation revokes all tokens signed with a compromised key (an emergency measure).
  • Sender-constrained tokens (DPoP or mTLS) reduce the value of stolen tokens.

Q4. What's the difference between opaque tokens and JWTs in OAuth2?

Short answer:

JWT (self-contained)Opaque token (reference)
ContentSigned claims (sub, scope, exp…), readable by anyoneA random string, meaningless to clients and resource servers
ValidationLocally: signature + claims, through the JWKS (fast, no network call)Introspection call to the authorisation server (RFC 7662), usually cached
RevocationHard: wait for expiry, or use a denylistImmediate: the authorisation server says it's inactive
PrivacyClaims are exposed (unless encrypted)Nothing leaks
SizeLarger headersSmall
CouplingResource servers trust the issuer's keysResource servers depend on the authorisation server being available

Spring's resource server supports both: oauth2ResourceServer(o -> o.jwt(...)) or .opaqueToken(...). A common hybrid is opaque tokens at the edge, exchanged by the gateway for internal JWTs (the "phantom token" pattern).

Q5. How does @PreAuthorize work behind the scenes?

Short answer:

  1. @EnableMethodSecurity registers advisors, including an AuthorizationManagerBeforeMethodInterceptor backed by PreAuthorizeAuthorizationManager.
  2. Beans with @PreAuthorize get an AOP proxy, so the proxy rules apply (self-invocation and private methods are skipped).
  3. On each call, the interceptor:
    • obtains the Authentication from the SecurityContextHolder;
    • builds a MethodSecurityExpressionHandler evaluation context (the authentication, the method arguments as #name through parameter-name discovery, beans through @bean, plus hasRole, hasAuthority and hasPermission functions);
    • evaluates the SpEL expression (the parsed expressions are cached);
    • if it's false, throws AccessDeniedException (mapped to 403 by ExceptionTranslationFilter in web requests);
    • otherwise, proceeds.

@PostAuthorize evaluates after execution, with returnObject available, so side effects have already happened. Use it for reads only.

Q6. How do @Secured, @RolesAllowed and @PreAuthorize differ?

Short answer:

  • @Secured("ROLE_ADMIN"): Spring's legacy annotation. It's a simple list of authorities, with no SpEL. You enable it with @EnableMethodSecurity(securedEnabled = true).
  • @RolesAllowed("ADMIN"): a JSR-250 / Jakarta standard annotation (portable). The role prefix is added automatically. Enable it with jsr250Enabled = true.
  • @PreAuthorize/@PostAuthorize: Spring, SpEL-based: arguments, the return object, bean methods, and complex conditions. They're enabled by default with @EnableMethodSecurity, and they're the most powerful and the most common today.

Use @PreAuthorize for anything beyond static roles. Avoid mixing styles in one codebase.

Q7. Session-based login or stateless login: which, and why?

Short answer:

  • Session-based: after login, the server stores the SecurityContext in an HTTP session, and the browser sends a session cookie (HttpOnly, Secure, SameSite).
    • Pros: easy revocation (invalidate the session), small cookies, and the server controls the state. It works well for server-rendered applications and BFFs.
    • Cons: you need CSRF protection, and session storage to scale horizontally (Spring Session with Redis, or sticky sessions).
  • Stateless (token-based): each request carries a bearer token (a JWT or opaque token), and the server keeps no session (SessionCreationPolicy.STATELESS).
    • Pros: easy horizontal scaling, and suited to APIs, mobile and service-to-service calls.
    • Cons: revocation is harder (Q3), token storage in browsers is risky (XSS), and tokens are bigger.
  • The modern recommendation for SPAs: a backend-for-frontend (BFF). The browser holds a session cookie with the BFF, and the BFF holds the OAuth2 tokens server-side, then calls APIs with bearer tokens. That combines the strengths of both.

Q8. OAuth2 vs JWT: what's the difference?

Short answer: They're different kinds of things, so the question is a common trap:

  • OAuth2 is an authorisation framework (a protocol). It defines roles (resource owner, client, authorisation server, resource server) and grant flows (authorisation code + PKCE, client credentials, device code, refresh token) for obtaining access tokens. OpenID Connect adds authentication (ID tokens, userinfo).
  • JWT is a token format: signed (JWS) or encrypted (JWE) JSON claims.

OAuth2 access tokens may be JWTs, or opaque strings. You can also use JWTs without OAuth2 (a home-grown login that issues JWTs), but then you must build what OAuth2 already standardises: key rotation, refresh, revocation, scopes, and client registration.

Q9. What is Spring Authorization Server?

Short answer: Spring's OAuth 2.1 and OpenID Connect 1.0 authorisation server framework (it replaced the deprecated Spring Security OAuth). It lets you run your own identity provider on Spring Boot:

  • the authorisation code + PKCE, client credentials, refresh token, device authorisation and token exchange grants;
  • JWT or opaque access tokens, token introspection and revocation endpoints;
  • OIDC (ID tokens, userinfo, discovery, logout);
  • JWKS endpoints, with key rotation;
  • client registration (persisted through JDBC);
  • consent screens, and customisable token claims.

When to use it: when you need a customised, embedded identity provider (special claims, a multi-tenant setup, integration with a legacy user store) and have the security expertise to run it. Otherwise, a managed or off-the-shelf IdP (Keycloak, Okta/Auth0, Entra ID, Cognito) reduces risk and effort.

Follow-up questions this topic invites — and their answers

Q: How is the SecurityContext propagated to @Async threads, or reactive code? A: Through DelegatingSecurityContextExecutor or TaskDecorator wrappers (or SecurityContextHolder strategies) for thread pools. In WebFlux, it's carried in the Reactor Context (ReactiveSecurityContextHolder), not in a ThreadLocal.

Q: Why does hasRole('ADMIN') check for ROLE_ADMIN? A: hasRole automatically adds the ROLE_ prefix. hasAuthority('ROLE_ADMIN') checks the exact string. OAuth2 scopes arrive as SCOPE_x authorities by default, so use hasAuthority('SCOPE_orders.read').

Q: How do you test method security? A: With @WithMockUser(roles = "ADMIN"), @WithUserDetails, or custom @WithSecurityContext annotations, in slice or integration tests. Assert that AccessDeniedException is thrown for unauthorised calls.

Q: What is AuthorizationManager? A: Spring Security 6's unified authorisation abstraction (check(authentication, object) returning an AuthorizationDecision). It's used for both request authorisation (authorizeHttpRequests) and method security, replacing the older AccessDecisionManager/voters.

Previous

Spring MVC & REST Internals, Exception Frameworks — Interview Questions

Next

Spring WebFlux, Reactor & R2DBC — Interview Questions

AI Tutor

Lesson: Spring Security Advanced Internals — Interview Questions

Quick actions

AI responses can be inaccurate. Verify critical information.