On this page
OAuth2 Integration
Spring Security provides first-class support for OAuth 2.0 and OpenID Connect, covering both client (login with Google/GitHub) and resource server (protect APIs with JWT) scenarios.
OAuth2 Roles
| Role | Description |
|---|---|
| Authorization Server | Issues tokens (Keycloak, Auth0, Okta) |
| Resource Server | Protects APIs, validates tokens |
| Client | Redirects users to login, receives tokens |
OAuth2 Client (Login with Provider)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
spring:
security:
oauth2:
client:
registration:
google:
client-id: ${GOOGLE_CLIENT_ID}
client-secret: ${GOOGLE_CLIENT_SECRET}
scope: openid, profile, email
github:
client-id: ${GITHUB_CLIENT_ID}
client-secret: ${GITHUB_CLIENT_SECRET}
scope: read:user, user:email
provider:
google:
issuer-uri: https://accounts.google.com
http.oauth2Login(oauth2 -> oauth2
.loginPage("/login")
.defaultSuccessUrl("/dashboard")
.userInfoEndpoint(userInfo -> userInfo
.userService(oauth2UserService())
)
);
Custom OAuth2 User Service
@Service
public class CustomOAuth2UserService extends DefaultOAuth2UserService {
@Override
public OAuth2User loadUser(OAuth2UserRequest request) throws OAuth2AuthenticationException {
OAuth2User oauth2User = super.loadUser(request);
String email = oauth2User.getAttribute("email");
User user = userRepository.findByEmail(email)
.orElseGet(() -> createUserFromOAuth2(oauth2User));
return new CustomOAuth2User(oauth2User, user);
}
}
OAuth2 Resource Server (JWT)
Protect REST APIs with bearer tokens:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: https://auth.example.com/realms/myapp
# or jwk-set-uri: https://auth.example.com/.well-known/jwks.json
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/public/**").permitAll()
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()));
Extract Claims from JWT
@GetMapping("/api/me")
public Map<String, Object> me(@AuthenticationPrincipal Jwt jwt) {
return Map.of(
"subject", jwt.getSubject(),
"email", jwt.getClaim("email"),
"roles", jwt.getClaim("roles")
);
}
Map JWT Roles to Authorities
@Bean
public JwtAuthenticationConverter jwtAuthenticationConverter() {
JwtGrantedAuthoritiesConverter granted = new JwtGrantedAuthoritiesConverter();
granted.setAuthoritiesClaimName("roles");
granted.setAuthorityPrefix("ROLE_");
JwtAuthenticationConverter converter = new JwtAuthenticationConverter();
converter.setJwtGrantedAuthoritiesConverter(granted);
return converter;
}
Authorization Code Flow
Browser → /oauth2/authorization/google
→ Google login page
→ Redirect to /login/oauth2/code/google?code=...
→ Spring exchanges code for tokens
→ User authenticated in SecurityContext
Best Practices
- Use a dedicated identity provider (Keycloak, Auth0) rather than rolling your own
- Validate JWT issuer and audience in resource servers
- Store client secrets in environment variables or secret managers
- Use PKCE for public clients (SPAs, mobile apps)
- Configure token refresh for long-lived sessions