Handling authentication
~8 minFour files, all standard Spring Security: login flow, token validation, and scope-based access control. Spring Security is maintained by the Spring team; ThunderID maintains this guide and the configuration below.
Add Spring's OAuth2 starters
Both are Spring Boot artifacts: client for browser login, resource-server for bearer-token APIs. Versions come from the Spring Boot BOM. Drop whichever you do not need.
implementation("org.springframework.boot:spring-boot-starter-oauth2-client")
implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server")Point the app at your ThunderID issuer
These are Spring's standard OIDC properties. There are no ThunderID-specific configuration keys to learn.
spring:
security:
oauth2:
client:
registration:
thunderid:
client-id: ${THUNDERID_CLIENT_ID}
client-secret: ${THUNDERID_CLIENT_SECRET}
scope: openid, profile, email
provider:
thunderid:
issuer-uri: https://acme.thunderid.dev
resourceserver:
jwt:
issuer-uri: https://acme.thunderid.devDeclaring both client and resourceserver lets one application serve browser sessions and bearer-token API calls. Omit either block if you only need one.
Secure your endpoints
An ordinary SecurityFilterChain bean. Scopes from the ThunderID token arrive prefixed with SCOPE_.
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/actuator/health").permitAll()
.requestMatchers("/api/billing/**").hasAuthority("SCOPE_billing:read")
.anyRequest().authenticated())
.oauth2Login(Customizer.withDefaults())
.oauth2ResourceServer(rs -> rs.jwt(Customizer.withDefaults()))
.build();
}
}Read the authenticated principal
Inject Spring's own OidcUser for session-based flows, or Jwt for bearer-token requests. Claims map straight through.
@RestController
public class ProfileController {
@GetMapping("/me")
public Map<String, Object> me(@AuthenticationPrincipal OidcUser user) {
return Map.of(
"sub", user.getSubject(),
"email", user.getEmail(),
"org", user.getClaimAsString("org_id")
);
}
@PreAuthorize("hasAuthority('SCOPE_billing:read')")
@GetMapping("/api/billing")
public Invoice billing(@AuthenticationPrincipal Jwt jwt) {
return service.forTenant(jwt.getClaimAsString("org_id"));
}
}Enable @PreAuthorize with @EnableMethodSecurity on any configuration class.
Claim mapping
How ThunderID token claims arrive on the Spring side. This is the reference you will actually reach for, since there is no separate ThunderID API surface to learn.
Requirements
Beyond this guide
Everything past this configuration is ordinary Spring Security, documented by the Spring team. These are the pages worth bookmarking.
Where to get help
Two projects, two places to ask.
Something wrong in this guide?
The guide and the ThunderID configuration it documents are ours. We keep it current with each Spring Boot release.
Something wrong in Spring Security?
The library itself is maintained by the Spring team. Bugs and feature requests belong on their tracker, not ours.