メインコンテンツまでスキップ

Tenant設定ガイド(開発者向け)

📍 このドキュメントの位置づけ

対象読者: Phase 1(how-to 01-05)完了済みの開発者

このドキュメントで学べること:

  • 本番運用に向けた詳細なTenant設定
  • ユースケース別の設定パターン
  • 高度な機能(Extension、カスタムスコープ、カスタムクレーム)
  • セキュリティとパフォーマンスのベストプラクティス

How-toガイドとの違い:

ドキュメント目的内容
How-to最小構成で動かす実践的な手順(動作確認重視)
Developer Guide本番設定を理解する詳細仕様と設計パターン

前提知識:


🧭 Tenantアーキテクチャの理解

Tenantとは

Tenant(テナント)は、マルチテナント環境における完全に独立した認証・認可ドメインです。

Organization vs Tenant

┌─────────────────────────────────────────────────────────┐
│ Organization (企業A) │
│ │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ Organizer Tenant │ │ Public Tenant │ │
│ │ (組織管理用) │ │ (アプリ用) │ │
│ ├──────────────────┤ ├──────────────────┤ │
│ │ - 組織管理者 │ │ - Client 1 │ │
│ │ - テナント管理 │ │ - Client 2 │ │
│ │ │ │ - Users │ │
│ └──────────────────┘ └──────────────────┘ │
└─────────────────────────────────────────────────────────┘

データ分離の仕組み

各Tenantで完全に分離されるもの:

  • ユーザーデータ: 認証情報、プロファイル
  • クライアント設定: OAuth/OIDCクライアント
  • 認証ポリシー: パスワードポリシー、MFA設定
  • トークン設定: 有効期限、署名鍵
  • セキュリティイベントログ: 監査ログ

テナント種別

種別説明作成方法用途
ADMINシステム管理用テナントシステム初期化時に自動作成システム管理・初期設定用
ORGANIZER組織管理用テナント組織作成(Onboarding API)時に自動作成組織管理者の管理操作用
PUBLICアプリケーション用テナント組織レベルAPIで作成通常のアプリケーション用

実装リファレンス:

重要: 組織レベルAPI(POST /v1/management/organizations/{org-id}/tenants)で作成されるテナントは常にtype: "PUBLIC"です。ADMINORGANIZERは手動で作成できません。


📖 API仕様リファレンス

テナント作成・更新のAPI詳細仕様(リクエスト/レスポンススキーマ、全パラメータ説明)は、OpenAPI仕様書を参照してください。

📖 OpenAPI仕様書:


🎯 シナリオ別設定例

実際のユースケースに応じた認可サーバー設定例を紹介します。

#シナリオユースケース主なポイント詳細
1Webアプリケーション(標準)ユーザーがWebブラウザから安全にログインし、セッション中は再認証なしでサービスを利用する• Opaque Token
• Access Token: 30分
• Refresh Token: 1時間
詳細
2モバイルアプリ(PKCE)モバイルユーザーが再ログインなしで長期間(30日)アプリを利用し続ける• PKCE必須
• 長期Refresh Token(30日)
• EXTENDS戦略
詳細
3金融グレード(FAPI)銀行顧客が口座・取引情報に安全にアクセスし、厳格なセキュリティ基準を満たす• Private Key JWT / mTLS
• Pairwise Subject
• Access Token: 10分
詳細
4SaaS型マルチテナント企業ユーザーが所属組織・部署情報を含むトークンでSaaSサービスにアクセスする• JWT Token
• カスタムクレーム
• M2M通信対応
詳細

📋 シナリオ詳細設定

1. Webアプリケーション向け(標準)

要件:

  • Authorization Code Flow
  • Refresh Token使用
  • Access Token: 30分
  • Refresh Token: 1時間

ユースケース: 一般的なWebアプリケーション、SPA

設定JSON例を表示
{
"tenant": {
"id": "web-app-tenant",
"name": "Web Application Tenant",
"domain": "https://app.example.com",
"authorization_provider": "idp-server"
},
"authorization_server": {
"issuer": "https://app.example.com/web-app-tenant",
"authorization_endpoint": "https://app.example.com/web-app-tenant/v1/authorizations",
"token_endpoint": "https://app.example.com/web-app-tenant/v1/tokens",
"userinfo_endpoint": "https://app.example.com/web-app-tenant/v1/userinfo",
"jwks_uri": "https://app.example.com/web-app-tenant/v1/jwks",
"scopes_supported": ["openid", "profile", "email"],
"grant_types_supported": ["authorization_code", "refresh_token"],
"response_types_supported": ["code"],
"token_endpoint_auth_methods_supported": ["client_secret_post", "client_secret_basic"],
"extension": {
"access_token_type": "opaque",
"access_token_duration": 1800,
"refresh_token_duration": 3600,
"rotate_refresh_token": true
}
}
}

設定ポイント:

  • access_token_type: "opaque": 高速な不透明トークン
  • rotate_refresh_token: true: セキュリティ向上のためリフレッシュトークンをローテーション

2. モバイルアプリ向け(PKCE対応)

要件:

  • Authorization Code Flow + PKCE
  • 長期間のRefresh Token(30日)
  • カスタムスコープ(プッシュ通知、オフラインアクセス)

ユースケース: iOS/Androidアプリ、ネイティブアプリ

設定JSON例を表示
{
"tenant": {
"id": "mobile-app-tenant",
"name": "Mobile Application Tenant",
"domain": "https://mobile.example.com",
"authorization_provider": "idp-server"
},
"authorization_server": {
"issuer": "https://mobile.example.com/mobile-app-tenant",
"authorization_endpoint": "https://mobile.example.com/mobile-app-tenant/v1/authorizations",
"token_endpoint": "https://mobile.example.com/mobile-app-tenant/v1/tokens",
"userinfo_endpoint": "https://mobile.example.com/mobile-app-tenant/v1/userinfo",
"jwks_uri": "https://mobile.example.com/mobile-app-tenant/v1/jwks",
"scopes_supported": [
"openid",
"profile",
"email",
"offline_access",
"notifications:push"
],
"grant_types_supported": ["authorization_code", "refresh_token"],
"response_types_supported": ["code"],
"token_endpoint_auth_methods_supported": ["none"],
"extension": {
"access_token_type": "opaque",
"access_token_duration": 3600,
"refresh_token_duration": 2592000,
"rotate_refresh_token": true,
"refresh_token_strategy": "EXTENDS"
}
}
}

設定ポイント:

  • token_endpoint_auth_methods_supported: ["none"]: PKCE専用(Client Secretなし)
  • refresh_token_duration: 2592000: 30日間の長期トークン
  • refresh_token_strategy: "EXTENDS": リフレッシュの度にトークン有効期限を延長(ユーザー体験向上)

3. 金融グレード(FAPI準拠)

要件:

  • FAPI 1.0 Advanced Profile準拠
  • 強力なクライアント認証(Private Key JWT, mTLS)
  • Pairwise Subject(プライバシー保護)
  • カスタムスコープ(OpenBanking)

ユースケース: オンラインバンキング、金融API、機密データアクセス

設定JSON例を表示
{
"tenant": {
"id": "banking-tenant",
"name": "Online Banking Platform",
"domain": "https://banking.example.com",
"authorization_provider": "idp-server"
},
"session_config": {
"use_secure_cookie": true,
"cookie_same_site": "Strict",
"switch_policy": "STRICT"
},
"cors_config": {
"allow_origins": ["https://banking.example.com"]
},
"authorization_server": {
"issuer": "https://banking.example.com/banking-tenant",
"authorization_endpoint": "https://banking.example.com/banking-tenant/v1/authorizations",
"token_endpoint": "https://banking.example.com/banking-tenant/v1/tokens",
"userinfo_endpoint": "https://banking.example.com/banking-tenant/v1/userinfo",
"jwks_uri": "https://banking.example.com/banking-tenant/v1/jwks",
"scopes_supported": [
"openid",
"profile",
"email",
"openbanking:accounts",
"openbanking:transactions",
"openbanking:payments"
],
"grant_types_supported": ["authorization_code", "refresh_token"],
"response_types_supported": ["code"],
"response_modes_supported": ["query", "jwt"],
"token_endpoint_auth_methods_supported": [
"private_key_jwt",
"tls_client_auth"
],
"subject_types_supported": ["pairwise"],
"extension": {
"access_token_type": "jwt",
"access_token_duration": 600,
"refresh_token_duration": 3600,
"authorization_code_valid_duration": 300,
"fapi_baseline_scopes": ["openbanking:accounts", "openbanking:transactions"],
"fapi_advance_scopes": ["openbanking:payments"],
"id_token_strict_mode": true
}
}
}

設定ポイント:

  • token_endpoint_auth_methods_supported: private_key_jwt, tls_client_authのみ許可
  • subject_types_supported: ["pairwise"]: ユーザー識別子を分離(プライバシー保護)
  • access_token_type: "jwt": JWT形式で署名検証可能
  • access_token_duration: 600: 10分の短い有効期限(セキュリティ向上)
  • fapi_baseline_scopes / fapi_advance_scopes: FAPI検証スコープ
  • switch_policy: "STRICT": 別ユーザー認証を拒否(ログアウト必須)

FAPI準拠の利点:

  • 金融機関レベルのセキュリティ
  • 国際標準への準拠
  • 監査対応の容易さ

4. SaaS型マルチテナント

要件:

  • 複数企業の従業員が利用
  • カスタムクレーム(企業ID、部署、権限)
  • JWT形式のAccess Token
  • M2M通信(Client Credentials Grant)

ユースケース: B2B SaaS、企業向けプラットフォーム

設定JSON例を表示
{
"tenant": {
"id": "saas-tenant",
"name": "SaaS Platform Tenant",
"domain": "https://saas.example.com",
"authorization_provider": "idp-server"
},
"authorization_server": {
"issuer": "https://saas.example.com/saas-tenant",
"authorization_endpoint": "https://saas.example.com/saas-tenant/v1/authorizations",
"token_endpoint": "https://saas.example.com/saas-tenant/v1/tokens",
"userinfo_endpoint": "https://saas.example.com/saas-tenant/v1/userinfo",
"jwks_uri": "https://saas.example.com/saas-tenant/v1/jwks",
"scopes_supported": [
"openid",
"profile",
"email",
"claims:organization_id",
"claims:department",
"claims:role"
],
"grant_types_supported": ["authorization_code", "refresh_token", "client_credentials"],
"response_types_supported": ["code"],
"extension": {
"access_token_type": "jwt",
"access_token_duration": 3600,
"custom_claims_scope_mapping": true
}
}
}

設定ポイント:

  • custom_claims_scope_mapping: true: カスタムクレームをスコープでマッピング
  • claims:organization_id, claims:department: 企業・部署情報をトークンに含める
  • grant_types_supported: client_credentialsを追加(M2M通信)
  • access_token_type: "jwt": クレーム情報をトークン内に含める

⚙️ 高度な設定

Extension設定の詳細

extensionオブジェクトには、idp-server固有の拡張設定を含めます。

トークン設定

フィールドデフォルト値説明推奨値
access_token_typeopaqueトークン形式(opaque / jwtWeb: opaque, SaaS: jwt
access_token_duration1800秒 (30分)アクセストークン有効期限30分~1時間
id_token_duration3600秒 (60分)IDトークン有効期限1時間
refresh_token_duration3600秒 (60分)リフレッシュトークン有効期限Web: 1時間、Mobile: 30日
rotate_refresh_tokentrueリフレッシュトークンローテーションtrue 推奨
refresh_token_strategyFIXED期限戦略(FIXED / EXTENDSMobile: EXTENDS

認可フロー設定

フィールドデフォルト値説明推奨値
authorization_code_valid_duration600秒 (10分)認可コード有効期限5~10分(RFC 6749推奨)
oauth_authorization_request_expires_in1800秒 (30分)認可リクエスト有効期限30分
authorization_response_duration60秒 (1分)認可レスポンス有効期限1分
default_max_age86400秒 (24時間)デフォルト最大認証有効期間24時間

セキュリティ設定

フィールドデフォルト値説明
id_token_strict_modefalseIDトークン厳密モード(OIDC仕様準拠、詳細は下記参照)
id_token_strict_mode - IDトークンクレーム制御

目的: IDトークンに含めるクレームの判定ロジックをOIDC仕様に厳密準拠させます。

デフォルト値: false

動作の違い:

モードscope=profileのみ指定claimsパラメータで明示的要求用途
false(デフォルト)name, given_name等を全て含める明示的に要求されたクレームのみ後方互換性・利便性優先
true(厳密モード)クレームを含めない明示的に要求されたクレームのみOIDC仕様準拠・FAPI準拠

OIDC仕様の解釈:

  • OpenID Connect Core 1.0 Section 5.4: "profile scopeはUserInfoエンドポイントでクレームへのアクセスを要求する"
  • IDトークンへの包含は、claimsパラメータでの明示的要求が推奨される

実装における挙動:

// GrantIdTokenClaims.java:218-221
if (idTokenStrictMode) {
return idTokenClaims.hasName(); // claimsパラメータでの明示的要求のみ
}
return scopes.contains("profile"); // scopeだけで含める(非厳密モード)

使用例:

非厳密モード(id_token_strict_mode: false、デフォルト):

GET /authorize?scope=openid profile&...

→ IDトークンに name, given_name, family_name 等が含まれる

厳密モード(id_token_strict_mode: true:

GET /authorize?scope=openid profile&claims={"id_token":{"name":null}}&...

nameのみIDトークンに含まれる(claimsで明示的要求)

推奨設定:

  • 一般的なアプリケーション: false(利便性優先)
  • 金融グレード(FAPI): true(仕様準拠・最小限のデータ公開)
  • OIDC4IDA: true(検証済みクレームの厳密制御)

判断基準:

設定値選択条件理由
trueFAPI/OIDC仕様への厳密準拠が必要FAPI、OIDC4IDAではIDトークンのクレームを明示的に要求することが求められる
trueクライアントがclaimsパラメータに対応済みOIDC仕様に準拠した実装が可能
falseクライアントがclaimsパラメータに対応困難レガシーシステム、既存実装の改修コストが高い
false開発・テスト環境での利便性を優先クレーム取得を簡素化して開発効率を向上

移行戦略:

新規プロジェクトの場合:

  1. 最初からtrueで設計: 将来的な規制対応を見据える
  2. クライアント実装時にclaimsパラメータを考慮

既存プロジェクトの場合:

  1. 段階的移行:
    • Phase 1: falseのまま、クライアントにclaimsパラメータ実装
    • Phase 2: 検証環境でtrueに変更してテスト
    • Phase 3: 本番環境でtrueに変更
  2. 互換性確認: UserInfoエンドポイントで同じクレームが取得できることを確認

関連設定:

  • custom_claims_scope_mapping: カスタムクレームのclaims:スコープマッピング
  • claims_supported: サポートするクレームの宣言(Discovery)

実装リファレンス:

FAPI設定

フィールドデフォルト値説明
fapi_baseline_scopes[]FAPI Baseline検証スコープ
fapi_advance_scopes[]FAPI Advanced検証スコープ

実装リファレンス: AuthorizationServerExtensionConfiguration.java


カスタムスコープ

標準スコープ(openid, profile, email)に加えて、独自のスコープを定義できます。

定義方法

scopes_supportedにカスタムスコープを追加:

{
"scopes_supported": [
"openid",
"profile",
"email",
"identity_verification_application",
"notifications:push",
"api:read",
"api:write"
]
}

スコープ命名規則

パターン用途
domain:actionapi:read, notifications:push機能別アクセス制御
claims:fieldclaims:vip_statusカスタムクレームアクセス
単独名offline_access標準的な追加スコープ

Claims(クレーム)設定

OpenID Connectでは、**クレーム(claim)**とはユーザーに関する情報項目(名前、メール、電話番号等)を指します。

claims_supported - サポートするクレームの宣言

目的: 認可サーバーが返却可能なクレーム(ユーザー情報項目)を宣言します。

OpenID Connect Discovery仕様: OpenID Connect Discovery 1.0 Section 3

設定例:

{
"claims_supported": [
"sub",
"name",
"email",
"email_verified",
"preferred_username",
"given_name",
"family_name",
"picture",
"phone_number",
"phone_number_verified"
]
}

標準クレーム(OIDC Core仕様):

クレーム説明
subSubject(ユーザー識別子)248289761001
nameフルネームJane Doe
given_nameJane
family_nameDoe
emailメールアドレスjanedoe@example.com
email_verifiedメール検証済みフラグtrue
preferred_username優先ユーザー名jane.doe
phone_number電話番号+1 (555) 123-4567
phone_number_verified電話番号検証済みフラグtrue
pictureプロフィール画像URLhttps://example.com/jane.jpg
profileプロフィールページURLhttps://example.com/jane
websiteウェブサイトURLhttps://janedoe.com
gender性別female
birthdate生年月日1990-01-01
zoneinfoタイムゾーンAsia/Tokyo
localeロケールja-JP
address住所(JSON構造){"formatted": "..."}

参照: OpenID Connect Core 1.0 Section 5.1 - Standard Claims

実装における重要な注意点:

  • claims_supported宣言のみであり、実際に返却されるかはUserInfoエンドポイントやIDトークンの実装に依存します
  • クライアントはscopeclaimsリクエストパラメータでクレームを要求します
  • 未実装のクレームを宣言すると、クライアントが誤動作する可能性があります

claim_types_supported - クレームタイプの宣言

目的: クレームの配布方式の種別を宣言します。

OpenID Connect Discovery仕様: OpenID Connect Discovery 1.0 Section 3

現在の実装状況: normalのみサポート

設定例:

{
"claim_types_supported": ["normal"]
}

OIDC仕様で定義されているクレームタイプ:

タイプ説明idp-server対応状況
normalクレームを直接UserInfo/IDトークンに含めるサポート済み
aggregatedクレームを外部ソースから集約して返却❌ 未サポート
distributedクレームを外部エンドポイントへのリファレンスとして返却❌ 未サポート

参照: OpenID Connect Core 1.0 Section 5.6 - Claim Types

実装リファレンス: AuthorizationServerConfiguration.java:58

将来の拡張: aggregated/distributedは高度なユースケース(複数IDプロバイダー統合、プライバシー保護)で有用ですが、現状では実装されていません。


カスタムクレーム

claims:パターン

claims: プレフィックスで、特定のClaimにアクセス:

{
"scopes_supported": [
"openid",
"profile",
"claims:vip_status",
"claims:verified_at",
"claims:account_type"
],
"extension": {
"custom_claims_scope_mapping": true
}
}

設定: custom_claims_scope_mapping: true で有効化

ユースケース例

SaaS型マルチテナント:

"claims:organization_id"  // 所属企業ID
"claims:department" // 部署
"claims:role" // 権限ロール

サブスクリプションサービス:

"claims:subscription_plan"  // サブスクリプションプラン
"claims:billing_status" // 請求ステータス

Tenant Attributes

attributesオブジェクトで、テナント固有の動作をカスタマイズできます。

設定可能な属性

フィールドデフォルト値説明
cookie_nameIDP_SESSIONセッションCookie名
use_secure_cookietrueSecure属性を付与(HTTPS必須)
allow_origins[]CORS許可オリジン
signin_page/signin/サインインページパス
security_event_log_persistence_enabledtrueイベントログ保存

設定例

{
"tenant": {
"id": "example-tenant",
"name": "Example Tenant",
"domain": "https://auth.example.com"
},
"session_config": {
"cookie_name": "AUTH_SESSION",
"use_secure_cookie": true
},
"cors_config": {
"allow_origins": [
"https://app.example.com",
"https://admin.example.com"
]
},
"ui_config": {
"signin_page": "/login/"
},
"security_event_log_config": {
"persistence_enabled": true
}
}

🔧 Type-Safe Configuration Classes

idp-serverでは、Tenant設定を型安全な6つのConfigurationクラスに分離しています。

UI Configuration

目的: カスタムサインイン/サインアップページの設定

フィールド:

{
"ui_config": {
"signup_page": "/auth-views/signup/index.html",
"signin_page": "/auth-views/signin/index.html"
}
}
フィールドデフォルト説明
signup_pagestring/auth-views/signup/index.htmlカスタムサインアップページのパス
signin_pagestring/auth-views/signin/index.htmlカスタムサインインページのパス

実装: UIConfiguration.java


CORS Configuration

目的: クロスオリジンリソース共有の設定

フィールド:

{
"cors_config": {
"allow_origins": ["https://app.example.com"],
"allow_headers": "Authorization, Content-Type, Accept, x-device-id",
"allow_methods": "GET, POST, PUT, PATCH, DELETE, OPTIONS",
"allow_credentials": true
}
}
フィールドデフォルト説明
allow_originsarray[string][]許可するオリジンのリスト
allow_headersstringAuthorization, Content-Type, Accept, x-device-id許可するヘッダー
allow_methodsstringGET, POST, PUT, PATCH, DELETE, OPTIONS許可するHTTPメソッド
allow_credentialsbooleantrueクレデンシャル送信を許可

実装: CorsConfiguration.java


Session Configuration

目的: セッション管理とCookie設定

フィールド:

{
"session_config": {
"cookie_name": null,
"cookie_domain": "example.com",
"cookie_same_site": "Lax",
"use_secure_cookie": true,
"use_http_only_cookie": true,
"cookie_path": "/",
"timeout_seconds": 3600,
"switch_policy": "SWITCH_ALLOWED"
}
}
フィールドデフォルト説明
cookie_namestring | nullnull (自動生成)セッションCookie名
cookie_domainstring | nullnullCookie Domain属性(サブドメイン共有用)
cookie_same_sitestringNoneSameSite属性 (None, Lax, Strict)
use_secure_cookiebooleantrueSecure属性を使用
use_http_only_cookiebooleantrueHttpOnly属性を使用
cookie_pathstring/Cookieのパス(API Gateway対応、詳細は下記参照)
timeout_secondsnumber3600セッションタイムアウト(秒)
switch_policystringSWITCH_ALLOWEDセッション切替ポリシー

重要: cookie_namenullの場合、IDP_SERVER_SESSION_{tenant-id-prefix}形式で自動生成されます。

switch_policy - セッション切替ポリシー

同一ブラウザで別ユーザーが認証しようとした場合の動作を制御します。

動作ユースケース
STRICTエラーを返す(ログアウト必須)金融、エンタープライズ
SWITCH_ALLOWED古いセッション削除→新規作成(デフォルト)一般的なWebアプリ、共有PC
MULTI_SESSION新規作成(古いのは残る)後方互換性維持

同一ユーザーの再認証時: ポリシーに関係なく、既存セッションを再利用します(lastAccessedAt更新)。これにより孤立セッションの発生を防止します。

構成パターン別の推奨設定

IdPとRP(アプリケーション)の構成に応じて、Cookie設定を適切に行う必要があります。

【Same-Origin vs Same-Site の違い】

Same-Origin: スキーム + ホスト + ポート が一致
Same-Site: eTLD+1(有効トップレベルドメイン+1)が一致

例: idp.example.com と app.example.com
→ Cross-Origin だが Same-Site
→ SameSite=Lax でも Cookie が送信される
構成cookie_domaincookie_same_site説明
同一オリジンexample.com/idp, example.com/app指定なしLax / Strict全て同じドメイン
サブドメインidp.example.com, app.example.comexample.comLaxSame-Site内で共有
クロスサイトidp.example.com, app.another.com指定なしNone異なるサイト間
【cookie_domain: "example.com" の場合】

Set-Cookie: SESSION=xxx; Domain=example.com; ...

以下の全ドメインでCookieが送信される:
✅ example.com
✅ idp.example.com
✅ app.example.com
✅ auth.example.com

【cookie_domain: null(未指定)の場合】

Set-Cookie: SESSION=xxx; ... (Domain属性なし)

Cookieは設定元のホストにのみ送信される:
✅ idp.example.com (設定元)
❌ app.example.com
❌ auth.example.com

SameSite属性とCookie送信

Same-Siteリクエスト(サブドメイン間を含む)では、SameSite属性に関係なく全て送信されます。

Cross-Siteリクエストの場合のみ、SameSite属性が効きます:

SameSite値GETナビゲーションPOSTfetch/XHR用途
Strict高セキュリティ(金融グレード)
Lax推奨(OIDCリダイレクトフロー対応)
NoneCross-Site構成(Secure必須)

構成パターン別の設定例

パターン1: サブドメイン構成(推奨)

{
"session_config": {
"cookie_domain": "example.com",
"cookie_same_site": "Lax",
"use_secure_cookie": true
}
}

idp.example.com, app.example.com, auth.example.com 間でCookieを共有

パターン2: クロスサイト構成

{
"session_config": {
"cookie_same_site": "None",
"use_secure_cookie": true
}
}

idp.example.comapp.another.com 間でCookieを送信

パターン3: 高セキュリティ(同一オリジン)

{
"session_config": {
"cookie_same_site": "Strict",
"use_secure_cookie": true
}
}

→ Cross-Siteからの全リクエストでCookie送信を拒否

背景: idp-serverをAPI Gateway経由でデプロイする場合、コンテキストパス(例: /idp-admin)が追加されることがあります。この場合、Cookieのパスを適切に設定しないと、ブラウザがCookieを送信せず認証エラーが発生します。

問題の例:

# API Gateway構成
https://api.example.com/idp-admin/* → idp-server (/)

# デフォルトのCookieパス(cookie_path未設定)
Set-Cookie: IDP_AUTH_SESSION=xxx; Path=/{tenant_id}/

# ブラウザがアクセスするパス
/idp-admin/{tenant_id}/v1/authorizations

# → パスが一致しないためCookieが送信されない → auth_session_mismatch エラー

解決策: cookie_pathにAPI Gatewayのコンテキストパスを設定

{
"session_config": {
"cookie_path": "/idp-admin",
"cookie_same_site": "None",
"use_secure_cookie": true
}
}

設定後のCookieパス:

Set-Cookie: IDP_AUTH_SESSION=xxx; Path=/idp-admin/{tenant_id}/

→ API Gateway経由のリクエストでもCookieが正しく送信される

設定例: config/examples/oidcc-cross-site-context-path/ にAPI Gateway + コンテキストパスの完全な設定例があります。

ローカルテスト: docker-compose.yamlのapp-view-context-pathサービスとnginx.confの/idp-admin/ルーティングを使用してAPI Gateway動作をシミュレートできます。

実装: SessionConfiguration.java

関連ドキュメント: Webセッションの基礎 - オリジンとCookieの送信


Security Event Log Configuration

目的: セキュリティイベントログの詳細設定

フィールド:

{
"security_event_log_config": {
"format": "structured_json",
"debug_logging": false,
"stage": "processed",
"include_user_id": true,
"include_user_name": true,
"include_user_ex_sub": true,
"include_client_id": true,
"include_ip_address": true,
"include_user_agent": true,
"include_event_detail": false,
"include_user_detail": false,
"include_user_pii": false,
"allowed_user_pii_keys": "",
"include_trace_context": false,
"service_name": "idp-server",
"custom_tags": "",
"tracing_enabled": false,
"persistence_enabled": false,
"statistics_enabled": false,
"detail_scrub_keys": ""
}
}
フィールドデフォルト説明
formatstringstructured_jsonログフォーマット (structured_json, plain_text)
debug_loggingbooleanfalseデバッグログ出力を有効化
stagestringprocessedログ出力タイミング
include_user_idbooleantrueユーザーIDを含める
include_user_namebooleantrueユーザー名を含める
include_user_ex_subbooleantrue外部ユーザーIDを含める
include_client_idbooleantrueクライアントIDを含める
include_ip_addressbooleantrueIPアドレスを含める
include_user_agentbooleantrueUser-Agentを含める
include_event_detailbooleanfalseイベント詳細を含める
include_user_detailbooleanfalseユーザー詳細を含める
include_user_piibooleanfalse個人情報を含める(⚠️ 注意)
allowed_user_pii_keysstring""許可するPIIキー(カンマ区切り)
include_trace_contextbooleanfalseトレーシング情報を含める
service_namestringidp-serverサービス名
custom_tagsstring""カスタムタグ(カンマ区切り)
tracing_enabledbooleanfalse分散トレーシングを有効化
persistence_enabledbooleanfalseデータベース永続化を有効化
statistics_enabledbooleanfalse統計データ記録を有効化
detail_scrub_keysstring(必須キー)スクラブするキー(カンマ区切り)

デフォルトでスクラブされるキー: authorization, cookie, password, secret, token, access_token, refresh_token, api_key, api_secret

プライバシー推奨設定:

  • 本番環境: include_user_pii: false, include_user_detail: false
  • デバッグ: debug_logging: true, include_event_detail: true(一時的のみ)

実装: SecurityEventLogConfiguration.java


Security Event User Attribute Configuration

目的: セキュリティイベントに含めるユーザー属性の制御

フィールド:

{
"security_event_user_config": {
"include_id": true,
"include_name": true,
"include_external_user_id": true,
"include_email": false,
"include_phone_number": false,
"include_given_name": false,
"include_family_name": false,
"include_preferred_username": false,
"include_profile": false,
"include_picture": false,
"include_website": false,
"include_gender": false,
"include_birthdate": false,
"include_zoneinfo": false,
"include_locale": false,
"include_address": false,
"include_roles": false,
"include_permissions": false,
"include_current_tenant": false,
"include_assigned_tenants": false,
"include_verified_claims": false,
"include_status": true,
"include_authentication_device_ids": false
}
}

主要フィールドの説明:

フィールド記録される値説明
include_idsubユーザーの内部識別子
include_namepreferred_username管理者が識別しやすい名前(IDポリシーにより決定)
include_external_user_idex_sub外部システム連携用の識別子
include_statusstatusユーザーステータス(REGISTERED, LOCKED等)
include_authentication_device_idsauthentication_device_ids認証デバイスIDリスト(Issue #1124)

注意: include_nameに記録される値は、テナントのIDポリシー設定により決定されます。

  • EMAIL_OR_EXTERNAL_USER_ID(デフォルト): メールアドレスが記録される
  • USERNAME_OR_EXTERNAL_USER_ID: ユーザー名が記録される

デフォルト: include_idinclude_nameinclude_external_user_idinclude_statustrue(管理者による識別のためinclude_nameを追加、Issue #1114でステータスを追加)

プライバシーレベル別設定:

レベル設定用途
最小include_id, include_name, include_external_user_id, include_statusのみ本番環境(推奨)
標準+ include_email, include_roles監査要件がある場合
詳細+ include_phone_numberデバッグ・調査時(一時的)
フル全てtrue❌ 非推奨(GDPR/個人情報保護法違反リスク)

実装: SecurityEventUserAttributeConfiguration.java


Identity Policy Configuration

目的: ユーザー識別キーとパスワードポリシーの設定

フィールド:

{
"identity_policy_config": {
"identity_unique_key_type": "EMAIL_OR_EXTERNAL_USER_ID",
"password_policy": {
"min_length": 8,
"max_length": 72,
"require_uppercase": false,
"require_lowercase": false,
"require_number": false,
"require_special_char": false,
"max_history": 0,
"max_attempts": 5,
"lockout_duration_seconds": 900
}
}
}
フィールドデフォルト説明
identity_unique_key_typestringEMAIL_OR_EXTERNAL_USER_IDユニークキー種別
password_policyobjectデフォルトポリシーパスワードポリシー設定

identity_unique_key_type - ユーザー識別キー戦略

許可される値:

説明用途
USERNAMEユーザー名を一意キーとして使用ユーザー名ベース認証
USERNAME_OR_EXTERNAL_USER_IDユーザー名、なければ外部ユーザーID外部IdP連携(ユーザー名優先)
EMAILメールアドレスを一意キーとして使用メールベース認証(厳密)
EMAIL_OR_EXTERNAL_USER_IDメールアドレス、なければ外部ユーザーID推奨:外部IdP連携(メール優先)
PHONE電話番号を一意キーとして使用電話番号ベース認証
PHONE_OR_EXTERNAL_USER_ID電話番号、なければ外部ユーザーID外部IdP連携(電話番号優先)
EXTERNAL_USER_ID外部ユーザーIDを一意キーとして使用外部システム完全連携

デフォルト値: EMAIL_OR_EXTERNAL_USER_ID (Issue #729対応)

フォールバック動作:

フォールバックが発生した場合(例: GitHubでメール非公開)、preferred_usernameは以下の形式で設定されます:

  • 外部IdP: {provider_id}.{external_user_id} (例: google.123456, github.987654)
  • ローカル(idp-server): {external_user_id} (例: 550e8400-e29b-41d4-a716-446655440000)

重要: フォールバックが発生しない場合(メール等が存在する場合)、preferred_usernameは通常の値(メールアドレス等)が設定されます。

推奨設定:

  • 外部IdP統合: EMAIL_OR_EXTERNAL_USER_ID - GitHub等でメール非公開の場合に対応
  • 独自ユーザーDB: EMAIL - メールアドレスを厳密に使用
  • 電話番号認証: PHONE_OR_EXTERNAL_USER_ID - SMS認証等

password_policy - パスワードポリシー設定

OWASP/NIST準拠: OWASP Password Storage Cheat Sheet, NIST SP 800-63B

フィールドデフォルト説明
min_lengthnumber8最小文字数
max_lengthnumber72最大文字数(BCrypt制限)
require_uppercasebooleanfalse大文字必須
require_lowercasebooleanfalse小文字必須
require_numberbooleanfalse数字必須
require_special_charbooleanfalse特殊文字必須
max_historynumber0パスワード履歴保持数(将来対応 Issue #741)
max_attemptsnumber5ブルートフォース対策: 最大連続失敗回数(0で無制限)
lockout_duration_secondsnumber900ブルートフォース対策: ロックアウト期間(秒、デフォルト15分)

NIST推奨: 最小8文字、複雑性要件なし(ユーザビリティ優先)

ブルートフォース対策: max_attempts回連続でパスワード認証に失敗すると、lockout_duration_secondsの間そのユーザーの認証を拒否します。Redisのアトミックカウンター(INCR + TTL)で実装されており、認証成功時にカウンターはリセットされます。

使用例:

パターン1: NIST推奨(デフォルト)

{
"identity_policy_config": {
"identity_unique_key_type": "EMAIL_OR_EXTERNAL_USER_ID",
"password_policy": {
"min_length": 8,
"require_uppercase": false,
"require_lowercase": false,
"require_number": false,
"require_special_char": false
}
}
}

パターン2: 金融グレード(高セキュリティ)

{
"identity_policy_config": {
"identity_unique_key_type": "EMAIL",
"password_policy": {
"min_length": 12,
"require_uppercase": true,
"require_lowercase": true,
"require_number": true,
"require_special_char": true,
"max_attempts": 3,
"lockout_duration_seconds": 1800
}
}
}

パターン3: 外部IdP統合(メールフォールバック)

{
"identity_policy_config": {
"identity_unique_key_type": "EMAIL_OR_EXTERNAL_USER_ID"
}
}

→ GitHub等でメールを非公開にしているユーザーでもexternal_user_idで識別可能

パターン4: 電話番号認証

{
"identity_policy_config": {
"identity_unique_key_type": "PHONE_OR_EXTERNAL_USER_ID",
"password_policy": {
"min_length": 6
}
}
}

パターン5: ブルートフォース対策のみカスタマイズ

{
"identity_policy_config": {
"password_policy": {
"max_attempts": 10,
"lockout_duration_seconds": 600
}
}
}

→ パスワード複雑性はデフォルト(NIST推奨)のまま、10回失敗で10分ロックアウト

実装リファレンス:


🛠️ 運用ノウハウ

パフォーマンスチューニング

トークン有効期限とパフォーマンス

設定パフォーマンス影響セキュリティ影響
短い有効期限頻繁なトークン更新→負荷増セキュリティ向上
長い有効期限トークン更新頻度減→負荷減セキュリティ低下

推奨バランス:

  • Access Token: 30分~1時間
  • Refresh Token: 1時間~30日(用途による)

Refresh Tokenの活用

{
"extension": {
"access_token_duration": 1800, // 30分(短め)
"refresh_token_duration": 2592000, // 30日(長め)
"rotate_refresh_token": true, // セキュリティ維持
"refresh_token_strategy": "EXTENDS" // UX向上(リフレッシュ毎に期限延長)
}
}

メリット:

  • Access Tokenは短くしてセキュリティ確保
  • Refresh Tokenで頻繁な再認証を回避
  • ユーザー体験とセキュリティの両立

セキュリティベストプラクティス

1. Secure Cookie必須

{
"session_config": {
"use_secure_cookie": true, // 必須(HTTPS環境)
"use_http_only_cookie": true, // XSS対策
"cookie_same_site": "Strict" // CSRF対策(本番環境推奨)
}
}

2. CORS設定の適切な管理

{
"cors_config": {
"allow_origins": [
"https://app.example.com" // 必要最小限のオリジンのみ
],
"allow_credentials": true
}
}

危険: allow_origins: ["*"] は本番環境では絶対に使用しない

3. トークン有効期限の適切な設定

用途Access TokenRefresh Token
金融グレード5~10分1時間
標準Webアプリ30分~1時間1時間~1日
モバイルアプリ1時間7~30日

4. 強力なクライアント認証

金融グレード・機密データアクセス:

{
"token_endpoint_auth_methods_supported": [
"private_key_jwt",
"tls_client_auth"
]
}

通常のアプリケーション:

{
"token_endpoint_auth_methods_supported": [
"client_secret_post",
"client_secret_basic"
]
}

5. Pairwise Subject(プライバシー保護)

{
"subject_types_supported": ["pairwise"]
}

効果: クライアント間でユーザー識別子を分離(追跡防止)


トラブルシューティング

問題1: issuerの不一致

エラー:

{
"error": "invalid_issuer",
"error_description": "issuer does not match token issuer"
}

原因: issuerが実際のURLと一致しない

解決策:

{
"issuer": "https://app.example.com/{tenant-id}" // 実際のアクセスURLと一致させる
}

問題2: カスタムスコープ未定義

エラー:

{
"error": "invalid_scope",
"error_description": "scope 'claims:custom_field' is not supported"
}

原因: scopes_supportedに未定義

解決策:

{
"scopes_supported": [
"openid",
"profile",
"email",
"claims:custom_field" // 追加
]
}

問題3: 認可コードが期限切れ

エラー:

{
"error": "invalid_grant",
"error_description": "authorization code has expired"
}

原因: authorization_code_valid_durationが短すぎる、またはリダイレクトに時間がかかりすぎる

解決策:

{
"extension": {
"authorization_code_valid_duration": 600 // 10分(推奨)
}
}

問題4: CORS エラー

エラー:

Access to XMLHttpRequest at 'https://idp.example.com/...' from origin 'https://app.example.com' has been blocked by CORS policy

原因: allow_originsにオリジンが含まれていない

解決策:

{
"cors_config": {
"allow_origins": ["https://app.example.com"]
}
}

📚 リファレンス(付録)

全フィールド一覧表

Tenantセクション

フィールド必須説明
idstring (UUID)テナントID18ffff8d-...
namestringテナント名(最大255文字)Example Tenant
domainstring (URI)認証画面のドメインhttps://auth.example.com
descriptionstringテナント説明説明文
authorization_providerstring認可プロバイダー(固定値)idp-server
attributesobjectテナント固有属性オブジェクト

OpenAPI仕様: swagger-cp-tenant-ja.yaml

Authorization Serverセクション

必須フィールド
フィールド説明
issuerIssuer識別子(HTTPS URL、クエリ/フラグメント不可)
authorization_endpoint認可エンドポイント(HTTPS URL)
token_endpointトークンエンドポイント
jwks_uriJWKS URI(HTTPS URL)
scopes_supportedサポートするスコープ(openid必須)
response_types_supportedサポートするResponse Type(code必須)
response_modes_supportedサポートするResponse Mode
subject_types_supportedSubject識別子タイプ(public/pairwise

OpenAPI仕様: swagger-cp-tenant-ja.yaml

推奨フィールド
フィールド説明
userinfo_endpointUserInfoエンドポイント(HTTPS URL)
registration_endpoint動的クライアント登録エンドポイント
claims_supportedサポートするクレーム(ユーザー情報項目)のリスト
claim_types_supportedサポートするクレームタイプ(現状はnormalのみ)
オプショナルフィールド
フィールドデフォルト値
grant_types_supported["authorization_code", "implicit"]
acr_values_supported[]
token_endpoint_auth_methods_supported["client_secret_basic"]
id_token_signing_alg_values_supported["RS256"]
extension-

デフォルト値一覧

Extension設定デフォルト値

フィールドデフォルト値単位
access_token_duration1800秒 (30分)
refresh_token_duration3600秒 (60分)
id_token_duration3600秒 (60分)
authorization_code_valid_duration600秒 (10分)
oauth_authorization_request_expires_in1800秒 (30分)
authorization_response_duration60秒 (1分)
default_max_age86400秒 (24時間)
access_token_typeopaque-
rotate_refresh_tokentrue-
refresh_token_strategyFIXED-
custom_claims_scope_mappingfalse-
id_token_strict_modefalse-

Tenant Attributesデフォルト値

フィールドデフォルト値
cookie_nameIDP_SESSION
use_secure_cookietrue
allow_origins[]
signin_page/signin/
security_event_log_persistence_enabledtrue

実装クラスへのリンク

Core:

Control Plane:


次のステップ

✅ Tenant設定を理解した!

次に読むべきドキュメント

  1. Client設定 - クライアント登録とOAuth 2.0クライアント設定
  2. Authentication Policy - 認証ポリシーとMFA設定

最終更新: 2025-12-20