OAuth2

OAuth2 (英語) は広く利用されている認証フレームワークです。

クライアント

クラスパスに spring-security-oauth2-client が含まれている場合、自動構成を利用して OAuth2/OpenID Connect クライアントを設定できます。この構成では、OAuth2ClientProperties (Javadoc) 配下のプロパティが使用されます。これらのプロパティは、サーブレットアプリケーションとリアクティブ Web アプリケーションの両方に適用可能です。

各登録では OAuth 2 プロバイダーを指定する必要があります。spring.security.oauth2.client.registration.<registration-id>.provider プロパティが設定されている場合は、その値が登録のプロバイダーの指定に使用されます。provider プロパティが設定されていない場合は、代わりに登録の ID が使用されます。両方のアプローチを次の例に示します。

  • プロパティ

  • YAML

spring.security.oauth2.client.registration.my-client.client-id=abcd
spring.security.oauth2.client.registration.my-client.client-secret=password
spring.security.oauth2.client.registration.my-client.provider=example
spring.security.oauth2.client.registration.example.client-id=abcd
spring.security.oauth2.client.registration.example.client-secret=password
spring:
  security:
    oauth2:
      client:
        registration:
          my-client:
            client-id: "abcd"
            client-secret: "password"
            provider: "example"
          example:
            client-id: "abcd"
            client-secret: "password"

登録 my-client と example はどちらも、ID が example のプロバイダーを使用します。前者は spring.security.oauth2.client.registration.my-client.provider プロパティの値に基づいて、後者は ID が example であり、登録に provider プロパティが設定されていないために、プロバイダーを使用します。

指定されるプロバイダーは、spring.security.oauth2.client.provider.<provider-id>.* プロパティを使用して構成されたプロバイダーへの参照、または既知の共通プロバイダーのいずれかになります。

次の例に示すように、spring.security.oauth2.client プレフィックスに複数の OAuth2 クライアントとプロバイダーを登録できます。

  • プロパティ

  • YAML

spring.security.oauth2.client.registration.my-login-client.client-id=abcd
spring.security.oauth2.client.registration.my-login-client.client-secret=password
spring.security.oauth2.client.registration.my-login-client.client-name=Client for OpenID Connect
spring.security.oauth2.client.registration.my-login-client.provider=my-oauth-provider
spring.security.oauth2.client.registration.my-login-client.scope=openid,profile,email,phone,address
spring.security.oauth2.client.registration.my-login-client.redirect-uri={baseUrl}/login/oauth2/code/{registrationId}
spring.security.oauth2.client.registration.my-login-client.client-authentication-method=client_secret_basic
spring.security.oauth2.client.registration.my-login-client.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.my-client-1.client-id=abcd
spring.security.oauth2.client.registration.my-client-1.client-secret=password
spring.security.oauth2.client.registration.my-client-1.client-name=Client for user scope
spring.security.oauth2.client.registration.my-client-1.provider=my-oauth-provider
spring.security.oauth2.client.registration.my-client-1.scope=user
spring.security.oauth2.client.registration.my-client-1.redirect-uri={baseUrl}/authorized/user
spring.security.oauth2.client.registration.my-client-1.client-authentication-method=client_secret_basic
spring.security.oauth2.client.registration.my-client-1.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.my-client-2.client-id=abcd
spring.security.oauth2.client.registration.my-client-2.client-secret=password
spring.security.oauth2.client.registration.my-client-2.client-name=Client for email scope
spring.security.oauth2.client.registration.my-client-2.provider=my-oauth-provider
spring.security.oauth2.client.registration.my-client-2.scope=email
spring.security.oauth2.client.registration.my-client-2.redirect-uri={baseUrl}/authorized/email
spring.security.oauth2.client.registration.my-client-2.client-authentication-method=client_secret_basic
spring.security.oauth2.client.registration.my-client-2.authorization-grant-type=authorization_code
spring.security.oauth2.client.provider.my-oauth-provider.authorization-uri=https://my-auth-server.com/oauth2/authorize
spring.security.oauth2.client.provider.my-oauth-provider.token-uri=https://my-auth-server.com/oauth2/token
spring.security.oauth2.client.provider.my-oauth-provider.user-info-uri=https://my-auth-server.com/userinfo
spring.security.oauth2.client.provider.my-oauth-provider.user-info-authentication-method=header
spring.security.oauth2.client.provider.my-oauth-provider.jwk-set-uri=https://my-auth-server.com/oauth2/jwks
spring.security.oauth2.client.provider.my-oauth-provider.user-name-attribute=name
spring:
  security:
    oauth2:
      client:
        registration:
          my-login-client:
            client-id: "abcd"
            client-secret: "password"
            client-name: "Client for OpenID Connect"
            provider: "my-oauth-provider"
            scope: "openid,profile,email,phone,address"
            redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
            client-authentication-method: "client_secret_basic"
            authorization-grant-type: "authorization_code"

          my-client-1:
            client-id: "abcd"
            client-secret: "password"
            client-name: "Client for user scope"
            provider: "my-oauth-provider"
            scope: "user"
            redirect-uri: "{baseUrl}/authorized/user"
            client-authentication-method: "client_secret_basic"
            authorization-grant-type: "authorization_code"

          my-client-2:
            client-id: "abcd"
            client-secret: "password"
            client-name: "Client for email scope"
            provider: "my-oauth-provider"
            scope: "email"
            redirect-uri: "{baseUrl}/authorized/email"
            client-authentication-method: "client_secret_basic"
            authorization-grant-type: "authorization_code"

        provider:
          my-oauth-provider:
            authorization-uri: "https://my-auth-server.com/oauth2/authorize"
            token-uri: "https://my-auth-server.com/oauth2/token"
            user-info-uri: "https://my-auth-server.com/userinfo"
            user-info-authentication-method: "header"
            jwk-set-uri: "https://my-auth-server.com/oauth2/jwks"
            user-name-attribute: "name"

この例では、3 つの登録があります。宣言順に、それぞれの ID は my-login-clientmy-client-1my-client-2 です。また、ID が my-oauth-provider のプロバイダーが 1 つあります。

OpenID Connect ディスカバリ (英語) をサポートする OpenID Connect プロバイダの場合、設定をさらに簡素化できます。プロバイダは、発行者識別子としてアサートする URI である issuer-uri で設定する必要があります。例: 提供される issuer-uri が https://example.com の場合、「OpenID プロバイダ設定リクエスト」が https://example.com/.well-known/openid-configuration に対して行われます。結果として「OpenID プロバイダ設定レスポンス」が返されることが期待されます。次の例は、OpenID Connect プロバイダを issuer-uri で設定する方法を示しています。

  • プロパティ

  • YAML

spring.security.oauth2.client.provider.oidc-provider.issuer-uri=https://dev-123456.oktapreview.com/oauth2/default/
spring:
  security:
    oauth2:
      client:
        provider:
          oidc-provider:
            issuer-uri: "https://dev-123456.oktapreview.com/oauth2/default/"

デフォルトでは、Spring Security の OAuth2LoginAuthenticationFilter (Javadoc) は /login/oauth2/code/* に一致する URL のみを処理します。redirect-uri をカスタマイズして別のパターンを使用する場合は、そのカスタムパターンを処理するための構成を提供する必要があります。例: サーブレットアプリケーションの場合、次のような独自の SecurityFilterChain (Javadoc) を追加できます。

  • Java

  • Kotlin

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;

@Configuration(proxyBeanMethods = false)
@EnableWebSecurity
public class MyOAuthClientConfiguration {

	@Bean
	public SecurityFilterChain securityFilterChain(HttpSecurity http) {
		http.authorizeHttpRequests((requests) ->
			requests.anyRequest().authenticated()
		);
		http.oauth2Login((login) ->
			login.redirectionEndpoint((endpoint) ->
				endpoint.baseUri("/login/oauth2/callback/*")
			)
		);
		return http.build();
	}

}
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.security.config.annotation.web.invoke
import org.springframework.security.web.SecurityFilterChain

@Configuration(proxyBeanMethods = false)
@EnableWebSecurity
open class MyOAuthClientConfiguration {

	@Bean
	open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
		http {
			authorizeHttpRequests {
				authorize(anyRequest, authenticated)
			}
			oauth2Login {
				redirectionEndpoint {
					baseUri = "/login/oauth2/callback/*"
				}
			}
		}
		return http.build()
	}

}
Spring Boot は、クライアント登録の管理のために Spring Security が使用する InMemoryOAuth2AuthorizedClientService (Javadoc) を自動構成します。InMemoryOAuth2AuthorizedClientService (Javadoc) の機能は制限されているため、開発環境でのみ使用することをお勧めします。本番環境では、JdbcOAuth2AuthorizedClientService (Javadoc) を使用するか、独自の OAuth2AuthorizedClientService (Javadoc) 実装を作成することを検討してください。

Common Provider の OAuth2 クライアント登録

一般的な OAuth2 および OpenID プロバイダー(Google、Github、Facebook、Okta)については、プロバイダーのデフォルト値のセットを提供しています。これらの一般的なプロバイダーの ID は、それぞれ googlegithubfacebookokta です。

これらのプロバイダをカスタマイズする必要がない場合は、登録の provider プロパティを共通プロバイダのいずれかの ID に設定してください。または、プロバイダの ID と一致する登録 ID を使用することもできます。次の例の 2 つの構成では、共通プロバイダである google を使用しています。

  • プロパティ

  • YAML

spring.security.oauth2.client.registration.my-client.client-id=abcd
spring.security.oauth2.client.registration.my-client.client-secret=password
spring.security.oauth2.client.registration.my-client.provider=google
spring.security.oauth2.client.registration.google.client-id=abcd
spring.security.oauth2.client.registration.google.client-secret=password
spring:
  security:
    oauth2:
      client:
        registration:
          my-client:
            client-id: "abcd"
            client-secret: "password"
            provider: "google"
          google:
            client-id: "abcd"
            client-secret: "password"

リソースサーバー

クラスパスに spring-security-oauth2-resource-server がある場合、Spring Boot は OAuth2 リソースサーバーをセットアップできます。JWT 構成の場合、次の例に示すように、JWK セット URI または OIDC 発行者 URI を指定する必要があります。

  • プロパティ

  • YAML

spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://example.com/oauth2/default/v1/keys
spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          jwk-set-uri: "https://example.com/oauth2/default/v1/keys"
  • プロパティ

  • YAML

spring.security.oauth2.resourceserver.jwt.issuer-uri=https://dev-123456.oktapreview.com/oauth2/default/
spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: "https://dev-123456.oktapreview.com/oauth2/default/"
認可サーバーが JWK Set URI をサポートしていない場合、JWT の署名の検証に使用される公開鍵でリソースサーバーを構成できます。これは、spring.security.oauth2.resourceserver.jwt.public-key-location プロパティを使用して実行できます。値は、PEM エンコードされた x509 形式の公開鍵を含むファイルを指す必要があります。

spring.security.oauth2.resourceserver.jwt.audiences プロパティを使用して、JWT の aud クレームの予期される値を指定できます。例: JWT に値 my-audience の aud クレームを含めるよう要求するには:

  • プロパティ

  • YAML

spring.security.oauth2.resourceserver.jwt.audiences[0]=my-audience
spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          audiences:
            - "my-audience"

同じプロパティがサーブレットアプリケーションとリアクティブアプリケーションの両方に適用されます。または、サーブレットアプリケーション用に独自の JwtDecoder (Javadoc) Bean を定義するか、リアクティブアプリケーション用に ReactiveJwtDecoder (Javadoc) を定義することもできます。

JWT の代わりに Opaque トークンが使用されている場合は、次のプロパティを構成して、イントロスペクションを通じてトークンを検証できます。

  • プロパティ

  • YAML

spring.security.oauth2.resourceserver.opaquetoken.introspection-uri=https://example.com/check-token
spring.security.oauth2.resourceserver.opaquetoken.client-id=my-client-id
spring.security.oauth2.resourceserver.opaquetoken.client-secret=my-client-secret
spring:
  security:
    oauth2:
      resourceserver:
        opaquetoken:
          introspection-uri: "https://example.com/check-token"
          client-id: "my-client-id"
          client-secret: "my-client-secret"

繰り返しますが、同じプロパティがサーブレットとリアクティブの両方のアプリケーションに適用可能です。

その結果、自動構成されたイントロスペクターが生成されます。SpringOpaqueTokenIntrospector (Javadoc) または、リアクティブアプリケーションの場合は SpringReactiveOpaqueTokenIntrospector (Javadoc) です。これらの自動構成されたイントロスペクターは、それぞれ SpringOpaqueTokenIntrospectorBuilderCustomizer (Javadoc) および SpringReactiveOpaqueTokenIntrospectorBuilderCustomizer (Javadoc) Bean を使用してカスタマイズできます。

イントロスペクションを完全にコントロールするには、独自の OpaqueTokenIntrospector (Javadoc) または ReactiveOpaqueTokenIntrospector (Javadoc) Bean を定義してください。

認可サーバー

クラスパスに spring-security-oauth2-authorization-server がある場合は、いくつかの自動構成を利用して、サーブレットベースの OAuth2 認可サーバーをセットアップできます。

次の例に示すように、spring.security.oauth2.authorizationserver.client プレフィックスで複数の OAuth2 クライアントを登録できます。

  • プロパティ

  • YAML

spring.security.oauth2.authorizationserver.client.my-client-1.registration.client-id=abcd
spring.security.oauth2.authorizationserver.client.my-client-1.registration.client-secret={noop}secret1
spring.security.oauth2.authorizationserver.client.my-client-1.registration.client-authentication-methods[0]=client_secret_basic
spring.security.oauth2.authorizationserver.client.my-client-1.registration.authorization-grant-types[0]=authorization_code
spring.security.oauth2.authorizationserver.client.my-client-1.registration.authorization-grant-types[1]=refresh_token
spring.security.oauth2.authorizationserver.client.my-client-1.registration.redirect-uris[0]=https://my-client-1.com/login/oauth2/code/abcd
spring.security.oauth2.authorizationserver.client.my-client-1.registration.redirect-uris[1]=https://my-client-1.com/authorized
spring.security.oauth2.authorizationserver.client.my-client-1.registration.scopes[0]=openid
spring.security.oauth2.authorizationserver.client.my-client-1.registration.scopes[1]=profile
spring.security.oauth2.authorizationserver.client.my-client-1.registration.scopes[2]=email
spring.security.oauth2.authorizationserver.client.my-client-1.registration.scopes[3]=phone
spring.security.oauth2.authorizationserver.client.my-client-1.registration.scopes[4]=address
spring.security.oauth2.authorizationserver.client.my-client-1.require-authorization-consent=true
spring.security.oauth2.authorizationserver.client.my-client-1.token.authorization-code-time-to-live=5m
spring.security.oauth2.authorizationserver.client.my-client-1.token.access-token-time-to-live=10m
spring.security.oauth2.authorizationserver.client.my-client-1.token.access-token-format=reference
spring.security.oauth2.authorizationserver.client.my-client-1.token.reuse-refresh-tokens=false
spring.security.oauth2.authorizationserver.client.my-client-1.token.refresh-token-time-to-live=30m
spring.security.oauth2.authorizationserver.client.my-client-2.registration.client-id=efgh
spring.security.oauth2.authorizationserver.client.my-client-2.registration.client-secret={noop}secret2
spring.security.oauth2.authorizationserver.client.my-client-2.registration.client-authentication-methods[0]=client_secret_jwt
spring.security.oauth2.authorizationserver.client.my-client-2.registration.authorization-grant-types[0]=client_credentials
spring.security.oauth2.authorizationserver.client.my-client-2.registration.scopes[0]=user.read
spring.security.oauth2.authorizationserver.client.my-client-2.registration.scopes[1]=user.write
spring.security.oauth2.authorizationserver.client.my-client-2.jwk-set-uri=https://my-client-2.com/jwks
spring.security.oauth2.authorizationserver.client.my-client-2.token-endpoint-authentication-signing-algorithm=RS256
spring:
  security:
    oauth2:
      authorizationserver:
        client:
          my-client-1:
            registration:
              client-id: "abcd"
              client-secret: "{noop}secret1"
              client-authentication-methods:
                - "client_secret_basic"
              authorization-grant-types:
                - "authorization_code"
                - "refresh_token"
              redirect-uris:
                - "https://my-client-1.com/login/oauth2/code/abcd"
                - "https://my-client-1.com/authorized"
              scopes:
                - "openid"
                - "profile"
                - "email"
                - "phone"
                - "address"
            require-authorization-consent: true
            token:
              authorization-code-time-to-live: 5m
              access-token-time-to-live: 10m
              access-token-format: "reference"
              reuse-refresh-tokens: false
              refresh-token-time-to-live: 30m
          my-client-2:
            registration:
              client-id: "efgh"
              client-secret: "{noop}secret2"
              client-authentication-methods:
                - "client_secret_jwt"
              authorization-grant-types:
                - "client_credentials"
              scopes:
                - "user.read"
                - "user.write"
            jwk-set-uri: "https://my-client-2.com/jwks"
            token-endpoint-authentication-signing-algorithm: "RS256"
client-secret プロパティは、構成された PasswordEncoder (Javadoc) と一致する形式である必要があります。PasswordEncoder (Javadoc) のデフォルトインスタンスは、PasswordEncoderFactories.createDelegatingPasswordEncoder() を介して作成されます。

Spring Boot が Spring Authorization Server に提供する自動構成は、すぐに開始できるように設計されています。ほとんどのアプリケーションはカスタマイズを必要とし、自動構成をオーバーライドするためにいくつかの Bean を定義する必要があります。

次のコンポーネントを Bean として定義して、Spring Authorization Server に固有の自動構成をオーバーライドできます。

Spring Boot は、登録されたクライアントの管理のために Spring Authorization Server が使用する InMemoryRegisteredClientRepository (Javadoc) を自動構成します。InMemoryRegisteredClientRepository (Javadoc) の機能は制限されているため、開発環境でのみ使用することをお勧めします。本番環境では、JdbcRegisteredClientRepository (Javadoc) を使用するか、独自の RegisteredClientRepository (Javadoc) 実装を作成することを検討してください。

追加情報については、Spring Security リファレンスドキュメントの入門の章を参照してください。