0Pricing
Spring Boot 4 Complete Guide · 课时

OAuth2 客户端与授权码流程

配置 OAuth2 客户端,通过授权码授予获取和刷新令牌。

OAuth2 客户端与授权码流程 是 CoddyKit 上的免费 Spring Boot 4 Complete Guide 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Spring Boot 4 Complete Guide 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Spring Boot 4 Complete Guide 课程共包含 4 节课。

本课时的部分内容尚未翻译,以英文显示。

Why an OAuth2 Client?

When your Spring Boot app needs to act on behalf of a user against an external provider (Google, GitHub, Keycloak, Okta), it becomes an OAuth2 Client.

The client never sees the user's password. Instead it redirects the browser to the provider's authorization endpoint, the user logs in there, and the provider hands back an access_token (and optionally a refresh_token) that the client uses to call protected APIs.

  • Authorization Code grant is the recommended browser-based flow.
  • Spring Security's spring-boot-starter-oauth2-client implements the entire dance for you.

Adding the Starter

Bring in the OAuth2 client support. In Spring Boot 4 this lives in spring-boot-starter-oauth2-client, which transitively pulls in spring-security-oauth2-client and the JOSE/JWT libraries needed for OIDC.

This Maven dependency is all you need to enable login-with-provider and token acquisition.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

Registering a Client via Properties

The fastest way to register a provider is through application.yml. Spring auto-binds these into a ClientRegistration.

  • client-id / client-secret — issued by the provider.
  • scope — openid, profile, email for OIDC login.
  • authorization-grant-type — authorization_code.
  • redirect-uri — the callback Spring exposes, usually {baseUrl}/login/oauth2/code/{registrationId}.
spring:
  security:
    oauth2:
      client:
        registration:
          keycloak:
            client-id: spring-app
            client-secret: "${KEYCLOAK_SECRET}"
            authorization-grant-type: authorization_code
            scope: openid, profile, email
            redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
        provider:
          keycloak:
            issuer-uri: https://auth.example.com/realms/demo

Issuer Discovery vs. Manual Endpoints

For OIDC providers, setting issuer-uri lets Spring fetch the /.well-known/openid-configuration document at startup and auto-discover the authorization, token, JWK set, and userinfo endpoints.

For plain OAuth2 providers without discovery (e.g. classic GitHub), you must specify the endpoints yourself.

spring:
  security:
    oauth2:
      client:
        provider:
          github:
            authorization-uri: https://github.com/login/oauth/authorize
            token-uri: https://github.com/login/oauth/access_token
            user-info-uri: https://api.github.com/user
            user-name-attribute: id

Enabling oauth2Login in SecurityFilterChain

Wire the flow into your SecurityFilterChain. Calling oauth2Login() activates the full Authorization Code flow: unauthenticated requests get redirected to the provider, and the callback is handled automatically.

This is framework configuration, not a standalone program.

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/", "/error").permitAll()
                .anyRequest().authenticated())
            .oauth2Login(Customizer.withDefaults());
        return http.build();
    }
}

The Authorization Code Flow Step by Step

Once oauth2Login() is active, here is what happens behind the scenes:

  • 1. User hits a protected URL; Spring redirects the browser to /oauth2/authorization/{registrationId}.
  • 2. Spring sends the browser to the provider's authorization endpoint with response_type=code, state, and a PKCE code_challenge.
  • 3. The user authenticates and consents at the provider.
  • 4. The provider redirects back to /login/oauth2/code/{registrationId} carrying a one-time authorization code.
  • 5. Spring exchanges that code (server-to-server) at the token endpoint for tokens.

The browser never sees the access token in step 5 — it's a back-channel call.

Accessing the Authorized Client and Token

After login, the access token is stored in an OAuth2AuthorizedClient. Inject it with the @RegisteredOAuth2AuthorizedClient argument resolver to read the token your app obtained.

This token is what you attach when calling the downstream resource server.

@RestController
public class ApiController {

    @GetMapping("/token")
    public String token(
            @RegisteredOAuth2AuthorizedClient("keycloak")
            OAuth2AuthorizedClient client) {
        OAuth2AccessToken accessToken = client.getAccessToken();
        return "type=" + accessToken.getTokenType().getValue()
             + " expires=" + accessToken.getExpiresAt();
    }
}

Calling APIs with RestClient and the Token

Spring Boot 4 favors RestClient. Configure it with the OAuth2ClientHttpRequestInterceptor so it automatically attaches the bearer token from the authorized client (and refreshes it when needed).

  • The interceptor reads the registration id from the request attributes.
  • No manual Authorization header building required.
@Bean
RestClient restClient(OAuth2AuthorizedClientManager manager) {
    OAuth2ClientHttpRequestInterceptor interceptor =
        new OAuth2ClientHttpRequestInterceptor(manager);
    interceptor.setPrincipalResolver(
        new SecurityContextHolderPrincipalResolver());
    return RestClient.builder()
        .requestInterceptor(interceptor)
        .build();
}

The Authorized Client Manager

The OAuth2AuthorizedClientManager is the engine that obtains, caches, and refreshes tokens. You configure a provider chain describing which grants it supports.

Enabling refreshToken() here is what makes silent token renewal possible when an access token expires.

@Bean
OAuth2AuthorizedClientManager authorizedClientManager(
        ClientRegistrationRepository clients,
        OAuth2AuthorizedClientRepository authorizedClients) {

    OAuth2AuthorizedClientProvider provider =
        OAuth2AuthorizedClientProviderBuilder.builder()
            .authorizationCode()
            .refreshToken()
            .build();

    DefaultOAuth2AuthorizedClientManager manager =
        new DefaultOAuth2AuthorizedClientManager(clients, authorizedClients);
    manager.setAuthorizedClientProvider(provider);
    return manager;
}

How Refresh Works

To refresh tokens, two things must be true:

  • The provider issued a refresh_token — this typically requires the offline_access scope (Keycloak) or an offline grant.
  • The access token is expired (or within the configured clock skew) when the manager is next asked for the client.

When you call the API through a token-aware RestClient, the RefreshTokenOAuth2AuthorizedClientProvider detects expiry, posts grant_type=refresh_token to the token endpoint, and transparently swaps in the new access token. No user redirect is needed.

spring:
  security:
    oauth2:
      client:
        registration:
          keycloak:
            scope: openid, profile, offline_access
            authorization-grant-type: authorization_code

Modeling Token Expiry in Plain Java

The refresh decision boils down to comparing an expiry Instant against now, allowing for a clock-skew buffer. Here is that core logic as a complete standalone program you can run to see when a refresh would trigger.

import java.time.Duration;
import java.time.Instant;

public class Main {
    static boolean shouldRefresh(Instant expiresAt, Instant now, Duration skew) {
        return expiresAt == null || now.isAfter(expiresAt.minus(skew));
    }

    public static void main(String[] args) {
        Instant now = Instant.parse("2026-01-01T10:00:00Z");
        Duration skew = Duration.ofSeconds(60);

        Instant valid = now.plusSeconds(300);   // 5 min left
        Instant nearly = now.plusSeconds(30);    // inside skew window
        Instant expired = now.minusSeconds(10);

        System.out.println("valid  -> refresh? " + shouldRefresh(valid, now, skew));
        System.out.println("nearly -> refresh? " + shouldRefresh(nearly, now, skew));
        System.out.println("expired-> refresh? " + shouldRefresh(expired, now, skew));
    }
}

Quick Check

You configured oauth2Login() and call a downstream API through a token-aware RestClient. The access token expires after 5 minutes, but users stay on the page for 30 minutes without re-authenticating. What single change most directly enables silent token renewal without sending the user back to the login page?

Recap

You configured Spring Boot 4 as an OAuth2 client driving the Authorization Code flow:

  • Starter: spring-boot-starter-oauth2-client enables the flow.
  • Registration: client-id/secret, authorization_code grant, scopes, and a redirect-uri; OIDC providers auto-discover endpoints via issuer-uri.
  • Activation: oauth2Login() performs the redirect, PKCE code exchange, and callback handling.
  • Using tokens: inject @RegisteredOAuth2AuthorizedClient or call APIs via a token-aware RestClient backed by an OAuth2AuthorizedClientManager.
  • Refresh: request a refresh-capable scope and build the manager with .refreshToken() so expired access tokens renew silently via grant_type=refresh_token.

常见问题解答

「OAuth2 客户端与授权码流程」课时是免费的吗?

是的 — 「OAuth2 客户端与授权码流程」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Spring Boot 4 Complete Guide 课程的其余内容,请升级到 CoddyKit PRO。 Spring Boot 4 Complete Guide 课程共包含 4 节课。

「OAuth2 客户端与授权码流程」这节课中我会学到什么?

配置 OAuth2 客户端,通过授权码授予获取和刷新令牌。 你通过在浏览器中直接运行的动手代码来练习 Spring Boot 4 Complete Guide,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Spring Boot 4 Complete Guide 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Spring Boot 4 Complete Guide 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。

「OAuth2 客户端与授权码流程」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Spring Boot 4 Complete Guide 课中编写并运行代码吗?

能。每节 Spring Boot 4 Complete Guide 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 资源服务器 JWT 验证与声明
  2. OAuth2 客户端与授权码流程
  3. 使用 SpEL 与自定义投票器实现方法安全
  4. 不透明令牌自省与令牌交换
← 返回 Spring Boot 4 Complete Guide