Spring Bootで外部認証サーバーを利用したOpenID Connect認証を実装する方法【初心者向け】

OpenID Connect (OIDC)はOAuth 2.0の上に構築された認証用プロトコルで、ユーザーのログイン状態や属性情報を安全に確認できる点が特徴です。この記事ではSpring BootSpring Securityを使い、外部の認証サーバー(OpenID Provider/IdP)でログイン処理を行うOIDC認証をGradleベースのAPIモジュールに組み込む手順を解説します。初心者がつまずきやすい箇所や設定例を交えながら、外部IdPを利用したログインとAPI保護を実装する方法を紹介します。

OpenID Connectの概要とメリット

OpenID ConnectはOAuth 2.0を拡張し、アクセストークンのほかにIDトークンを発行してユーザーの認証情報を提供します。IdP側に認証やユーザー管理を任せるため、アプリケーション側ではユーザー情報を保持せずに済みます。また、統一的な仕様に基づいているため、Okta・Keycloak・Auth0・Azure ADなど多様なIdPと簡単に連携できます。Spring Securityはバージョン5以降でOIDCに標準対応しており、設定ファイルへのプロパティ追加だけで自動設定されます。

準備:Gradle依存関係の追加

Spring Bootのアプリケーションで外部IdPを利用するには、Spring SecurityとOAuth 2.0クライアントのスターターを追加します。build.gradle (Kotlinの場合はbuild.gradle.kts) に以下の依存関係を記述します。Spring Boot 3以降ではspring-boot-starter-oauth2-clientspring-boot-starter-securityで自動的にOAuth2ログインが構成されます。

plugins {
    id 'org.springframework.boot' version '3.3.0'
    id 'io.spring.dependency-management' version '1.1.4'
    id 'java'
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
    implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server' // APIにJWT検証を追加したい場合
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

ポイント

  • spring-boot-starter-oauth2-client は認証フロー(認可コードグラント)を実現するための依存ライブラリです。
  • API側で受け取るJWTの検証が必要な場合は spring-boot-starter-oauth2-resource-server を追加します。Spring Securityはissuer-urijwk-set-uriなどのプロパティを参照して公開鍵を自動取得し、トークンを検証してくれます。

IdPとの連携設定(application.yml

IdPの発行するID・アクセストークンをSpringアプリケーションが正しく受け取るためには、クライアント登録を設定します。以下はCurity Identity Serverを例に、application.ymlに記述する設定です。

spring:
  security:
    oauth2:
      client:
        registration:
          demo-basic-client:
            client-name: "Curity Identity Serverでログイン"
            client-id: "demo-basic-client"   # IdPで発行されたクライアントID
            client-secret: "Secr3t"         # IdPで設定したクライアントシークレット
            authorization-grant-type: authorization_code
            redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
            scope: openid, profile
            provider: idsvr
        provider:
          idsvr:
            issuer-uri: https://idsvr.example.com/oauth/v2/oauth-anonymous

この設定では以下のポイントを押さえます。

  • client-id / client-secret – IdP(管理者画面)で登録したクライアント情報に合わせます。クライアントシークレットは漏洩しないよう注意が必要です。
  • authorization-grant-type – 認可コードグラントを利用します。Spring SecurityはPKCEにも対応しているため、フロントエンドが別の場合でも拡張できます。
  • redirect-uri – 認証後にユーザーがリダイレクトされるURLです。{baseUrl}はアプリケーションのホストURL(例:http://localhost:8080)、{registrationId}demo-basic-clientに置き換わります。
  • scope – ユーザー情報取得に必要なスコープを指定します。一般的にはopenidprofile、メールアドレスを取得する場合はemailを追加します。
  • provider.issuer-uri – IdPのOIDCメタデータエンドポイントのベースURIです。この値からSpring Securityが自動的に認証エンドポイントや公開鍵を発見します。

IdPに合わせてclient-idissuer-uriを変更すれば、KeycloakやOkta、Azure ADなど別のプロバイダーとも接続できます。

SecurityFilterChainでの認証設定

Spring Bootの自動設定に任せる場合はapplication.ymlへの登録だけで動作しますが、ルーティングごとにアクセス制御を行う場合はSecurityFilterChainをカスタマイズします。以下のように@Configurationクラスを作成し、全てのリクエストに認証を要求しつつ、ログインフローを有効にする例です。

@Configuration
@EnableWebSecurity
public class SecurityConfig {
  @Bean
  public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
      .authorizeHttpRequests(authorize -> authorize
        .requestMatchers("/", "/error").permitAll() // 公開ページ
        .anyRequest().authenticated()                 // それ以外は認証が必要
      )
      .oauth2Login(Customizer.withDefaults());        // OAuth2/OIDCログインを有効化
    return http.build();
  }
}

oauth2Login() を追加するだけで、Spring Securityは /login への自動生成ログインページを提供し、application.ymlで登録したすべてのクライアント(registrationId)をリスト表示します。ログインボタンをクリックすると、ユーザーは外部IdPへリダイレクトされ、認証に成功すると元のアプリケーションに戻ってきます。

ログイン後のユーザー情報取得

OIDCでは認証後に IDトークン が返され、ユーザーの属性(sub, name, emailなど)を取得できます。Spring Securityでは@AuthenticationPrincipalアノテーションとOidcUser型を利用して、IDトークンからユーザー情報を取り出すことができます。次のようにエンドポイントを定義すれば、ログイン済みユーザーの属性をJSONで返すAPIを実装できます。

@RestController
public class UserController {
  @GetMapping("/user")
  public Map<String, Object> user(@AuthenticationPrincipal OidcUser principal) {
    Map<String, Object> result = new HashMap<>();
    result.put("subject", principal.getSubject());             // ユーザー識別子 (sub)
    result.put("name", principal.getFullName());              // 表示名
    result.put("email", principal.getEmail());                // メールアドレス (取得できる場合)
    return result;
  }
}

このAPIにアクセスすると、未認証の場合は自動的にログインページにリダイレクトされ、ログイン後はIDトークンに含まれるユーザー情報が確認できます。

JWTでAPIを保護する(Resource Server設定)

ログインが必要なWebアプリに対してはoauth2Login()だけで十分ですが、バックエンドAPIだけを提供するモジュールではアクセストークン (JWT) の検証を行う Resource Server 機能が便利です。Spring Bootはissuer-uriを指定するだけで、IdPのJWKエンドポイントから公開鍵を取得してJWTの署名検証や有効期限チェックを自動で行います。

次のようにapplication.ymlへ設定します。

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: https://idp.example.com/issuer
          # IdPによってはJWK公開鍵エンドポイントを個別に指定することもできます
          # jwk-set-uri: https://idp.example.com/.well-known/jwks.json

そして、SecurityFilterChainoauth2ResourceServer()を有効化します。

@Configuration
@EnableWebSecurity
public class ApiSecurityConfig {
  @Bean
  public SecurityFilterChain resourceFilterChain(HttpSecurity http) throws Exception {
    http
      .authorizeHttpRequests(authorize -> authorize
        .requestMatchers("/public/**").permitAll()   // 認証不要API
        .anyRequest().authenticated()                 // それ以外はJWT必須
      )
      .oauth2ResourceServer(resource -> resource
        .jwt(Customizer.withDefaults())
      );
    return http.build();
  }
}

この構成により、APIへAuthorization: Bearer <token>ヘッダーが付与されたリクエストのみが処理されます。Spring SecurityはIdPの issueraudience を検証し、不正なトークンを拒否します。

動作確認

  1. IdPにクライアント登録 – KeycloakやOktaなどの管理画面でクライアントを登録し、client-idclient-secretを取得します。リダイレクトURIにはhttp://localhost:8080/login/oauth2/code/demo-basic-clientのようにアプリURLを指定します。
  2. Spring Bootアプリの起動./gradlew bootRun でアプリを起動します。初回アクセス時に/loginにリダイレクトされ、IdPのログイン画面が表示されます。
  3. ログインとリダイレクト – 認証に成功すると、Idトークンとアクセストークンがブラウザに送られ、アプリにリダイレクトされます。/user エンドポイントへアクセスするとIDトークンに含まれるユーザー情報が確認できます。
  4. API保護の確認 – Resource Server設定を有効にした場合、未認証でAPIへアクセスするとHTTP 401が返されます。IdPから取得したアクセストークンをAuthorizationヘッダーに付与してリクエストすると、APIが利用できます。

外部認証サーバー連携のイメージ図

下図は、Spring Bootアプリケーションが外部のIdPと連携して認証し、APIへアクセスするまでの流れを示した概念図です。ブラウザ(ユーザー)、クライアントアプリ(Spring Boot)、IdP、APIサーバー間の通信を矢印で表しています。

まとめ

外部認証サーバーを用いたOpenID Connect認証は、ユーザー管理をIdPに任せることでアプリケーション側の責務を軽減し、セキュリティを向上させる方法です。Spring BootとSpring SecurityはOIDCに標準対応しており、application.ymlにクライアント情報を登録し、oauth2Login()oauth2ResourceServer()を有効化するだけで認証フローやJWT検証を自動設定してくれます。さらに、@AuthenticationPrincipalを利用すればIDトークンから簡単にユーザー情報を取り出せます。IdPの構築にはKeycloakやOkta、Azure ADなど多数の選択肢があるので、用途に合ったサービスを選択し、クライアント登録情報を設定するだけで本格的な認証機能をAPIモジュールへ導入できます。

是非フォローしてください

最新の情報をお伝えします

類似投稿