Back to Spring Boot Course

Spring Boot Course

OAuth2 in Spring Boot

OAuth2 (Open Authorization 2.0) is an authorization framework (defined in RFC 6749) that allows a third-party application to obtain limited access to a user's account on an HTTP service — without the user sharing their credentials with that application directly. The user grants access, the authorization server issues a token, and the third-party application uses that token to access protected resources.

Key terms:

  • Resource Owner: The user who owns the data and grants access.
  • Client: The application requesting access on behalf of the user.
  • Authorization Server: Issues access tokens after authenticating the resource owner and obtaining their consent. Examples: Google, GitHub, Okta, Keycloak, AWS Cognito.
  • Resource Server: The API server hosting the protected resources. Validates access tokens on each request.
  • Access Token: A short-lived credential (usually a JWT) the client uses to call the resource server.
  • Refresh Token: A longer-lived credential used to obtain new access tokens without requiring the user to log in again.

OAuth2 vs JWT: OAuth2 is an authorization framework — it defines the flow for obtaining tokens. JWT is a token format. In most modern OAuth2 implementations, the access token issued by the authorization server is a JWT, but OAuth2 doesn't mandate JWT; it could be an opaque token. Spring Boot's resource server supports both: JWT (decoded locally using public key/JWKS endpoint) and opaque tokens (introspected against the authorization server on each request).

OAuth2 Grant Types (Flows)

  • Authorization Code (+ PKCE for public clients): The standard, most secure flow for web apps and mobile apps. User is redirected to the authorization server to consent; the server redirects back with an authorization code; the client exchanges the code for tokens. PKCE (Proof Key for Code Exchange) prevents authorization code interception attacks for public clients (SPAs, mobile apps) where a client secret cannot be stored securely.
  • Client Credentials: Machine-to-machine (M2M) — no user involved. The client authenticates directly with the authorization server using its client ID and secret and receives an access token. Used for service-to-service API calls in microservices.
  • Device Authorization: For devices with no browser/keyboard (smart TVs, IoT devices). The device displays a code; user authenticates on a separate device.
  • ~~Implicit~~: Deprecated in OAuth 2.1 — do not use. Superseded by Authorization Code + PKCE.
  • ~~Resource Owner Password Credentials (ROPC)~~: Deprecated in OAuth 2.1 — do not use. The user's credentials are sent directly to the client and then to the authorization server, which defeats the security purpose of OAuth2.

Spring Boot as an OAuth2 Client

Use case: your Spring Boot web application allows users to log in with Google, GitHub, or another identity 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} provider: google: issuer-uri: https://accounts.google.com

Security configuration:

@Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { return http .authorizeHttpRequests(auth -> auth .requestMatchers("/", "/public/**").permitAll() .anyRequest().authenticated() ) .oauth2Login(oauth2 -> oauth2 .defaultSuccessUrl("/dashboard", true) ) .logout(logout -> logout .logoutSuccessUrl("/") ) .build(); } }

Spring Boot auto-configures the OAuth2 client based on application.yml. When the user hits a protected URL, Spring Security redirects to the chosen provider's authorization endpoint. After the user consents and authenticates, the provider redirects back and Spring Security exchanges the code for tokens, loads the user's profile, and creates a session.


Spring Boot as an OAuth2 Resource Server

Use case: your Spring Boot REST API validates JWT access tokens issued by an external authorization server (Keycloak, Okta, AWS Cognito, Auth0).

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-oauth2-resource-server</artifactId> </dependency>
spring: security: oauth2: resourceserver: jwt: issuer-uri: https://your-auth-server.com/realms/myrealm # Spring Boot auto-fetches the JWKS (public keys) from {issuer-uri}/.well-known/openid-configuration
@Configuration @EnableWebSecurity @EnableMethodSecurity // enables @PreAuthorize, @PostAuthorize, @Secured public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { return http .csrf(AbstractHttpConfigurer::disable) // REST APIs don't need CSRF .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) // no sessions .authorizeHttpRequests(auth -> auth .requestMatchers("/api/v1/auth/**").permitAll() .requestMatchers(HttpMethod.DELETE, "/api/v1/**").hasRole("ADMIN") .anyRequest().authenticated() ) .oauth2ResourceServer(oauth2 -> oauth2 .jwt(jwt -> jwt.jwtAuthenticationConverter(jwtAuthenticationConverter())) ) .build(); } @Bean public JwtAuthenticationConverter jwtAuthenticationConverter() { JwtGrantedAuthoritiesConverter grantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter(); // Map the "roles" claim from your JWT to Spring Security authorities grantedAuthoritiesConverter.setAuthoritiesClaimName("roles"); grantedAuthoritiesConverter.setAuthorityPrefix("ROLE_"); JwtAuthenticationConverter jwtConverter = new JwtAuthenticationConverter(); jwtConverter.setJwtGrantedAuthoritiesConverter(grantedAuthoritiesConverter); return jwtConverter; } }

With issuer-uri configured, Spring Boot automatically:

  • Fetches the JWKS (JSON Web Key Set) endpoint from the authorization server at startup
  • Validates the signature, issuer, audience, and expiry of incoming JWT access tokens on every request
  • Caches and periodically refreshes the public keys

Method-level security with @EnableMethodSecurity:

@RestController @RequestMapping("/api/v1/employees") public class EmployeeController { @GetMapping @PreAuthorize("hasAnyRole('USER', 'ADMIN')") public List<Employee> getAllEmployees() { ... } @DeleteMapping("/{id}") @PreAuthorize("hasRole('ADMIN')") public void deleteEmployee(@PathVariable Long id) { ... } }

Service-to-Service (Client Credentials)

When microservice A needs to call microservice B (no user involved), use the Client Credentials flow:

spring: security: oauth2: client: registration: billing-service: client-id: order-service client-secret: ${BILLING_CLIENT_SECRET} authorization-grant-type: client_credentials scope: billing:read, billing:write provider: billing-service: token-uri: https://your-auth-server.com/realms/myrealm/protocol/openid-connect/token

Use a WebClient with ServletOAuth2AuthorizedClientExchangeFilterFunction to automatically attach tokens:

@Bean public WebClient billingWebClient(OAuth2AuthorizedClientManager authorizedClientManager) { var oauth2Client = new ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager); oauth2Client.setDefaultClientRegistrationId("billing-service"); return WebClient.builder() .baseUrl("http://billing-service") .apply(oauth2Client.oauth2Configuration()) .build(); }

Spring Security handles token acquisition, caching, and refresh automatically.


OpenID Connect (OIDC)

OpenID Connect is an identity layer built on top of OAuth2. While OAuth2 deals with authorization (what can this app do?), OIDC deals with authentication (who is this user?). OIDC adds an ID Token (a JWT carrying user identity claims: sub, name, email, picture) to the OAuth2 flow.

When you add scope: openid to your OAuth2 client registration, Spring Security automatically parses the ID Token and makes the user's profile claims available via OidcUser. This is what spring-boot-starter-oauth2-client uses to populate the authenticated user's details when you log in with Google/GitHub.

Spring Security 6 / Spring Boot 3.x has full OIDC support built in — no separate library needed.