Federation設定ガイド
このドキュメントの目的
外部IdP連携(Federation)の設定方法を理解します。
所要時間
⏱️ 約20分
Federationとは
**Federation(フェデレーション)**は外部Identity Provider(IdP)と連携してユーザー認証を行う機能です。
ユースケース:
- 既存の企業IdPと連携
- ソーシャルログイン(外部OIDC準拠IdP等)
- 他システムの認証情報を利用
設定の関係性
Federation認証を構成する3つの設定要素の関係を示します。
┌─────────────────────────────────────────────────────────────────────────────────┐
│ Consumer Tenant (認証を受ける側) │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌────── ────────────┐ ┌──────────────────────┐ ┌──────────────────┐ │
│ │ Client │ │ Authentication │ │ Federation │ │
│ │ │ │ Policy │ │ Configuration │ │
│ ├──────────────────┤ ├──────────────────────┤ ├──────────────────┤ │
│ │ client_id │ │ flow: "oauth" │ │ type: "oidc" │ │
│ │ scope: │─────▶│ conditions: │ │ sso_provider: │ │
│ │ "openid email" │ │ scopes: ["openid"] │ │ "google" │ │
│ │ redirect_uris │ │ │ │ │ │
│ └──────────────────┘ │ available_methods: │ │ payload: │ │
│ │ - "password" │ │ provider: │ │
│ scope参照 │ - "oidc-google" ◀──┼──────┤ "standard" │ │
│ │ │ │ │ issuer: ... │ │
│ ▼ │ success_conditions: │ │ client_id: ... │ │
│ ┌──────────────────────┐ │ oidc-google の │ │ userinfo_ │ │
│ │ 認可リクエスト │ │ success_count >= 1 │ │ mapping_rules │ │
│ │ GET /authorizations │ └──────────────────────┘ └────────┬─────────┘ │
│ │ ?scope=openid │ │ │ │
│ │ &client_id=xxx │ │ │ │
│ └──────────┬───────────┘ │ │ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ 認可フロー処理 │ │
│ │ 1. Client検証 → 2. Policy評価 → 3. 利用可能な認証方法を提示 │ │
│ │ (password, oidc-google) │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ │ユーザーがFederation選択 │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ Federation開始: POST /{tenant}/v1/authorizations/{id}/federations/oidc │ │
│ │ → Federation Configurationを参照してProvider IdPにリダイレクト │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │ │
└────────────────────────────────────────┼───────────────────────────────────────┘
│
▼
┌─────────────────────────────── ──────────────────────────────────────────────────┐
│ Provider Tenant (外部IdP) │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────────────────────────────────────────────────────────────┐ │
│ │ Authorization Server │ │
│ │ claims_supported: ["sub", "name", "email", "preferred_username"] │ │
│ │ ^^^^^^^^^^^^^^^^ ← これがないとUserInfoでemailが返らない! │ │
│ └──────────────────────────────────────────────────────────────────────────┘ │
│ │
│ 認証完了後、Consumer Tenantのcallback URLにリダイレクト: │
│ /{consumer-tenant}/v1/authorizations/federations/oidc/callback │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────────┐
│ Consumer Tenant (Callback処理) │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ OidcFederationInteractor.callback() │ │
│ │ 1. code → token交換 │ │
│ │ 2. UserInfo取得 │ │
│ │ 3. userinfo_mapping_rules でUser属性マッピング │ │
│ │ 4. 既存ユーザーを検索し、見つかればそれをベースに 3 を重ねる │ │
│ │ 5. applyIdentityPolicy() で preferred_username 設定 │ │
│ └────────────────────────── ───────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
設定要素の紐づけ
┌─────────────────── ──────────────────┐
│ Client │
│ scope: "openid email" │
│ extension: │
│ available_federations: │
│ - id: {federation_config_id} │
│ type: "oidc" │
│ sso_provider: "google" ─────┼──────────┐
│ auto_selected: true │ │
└─────────────────┬───────────────────┘ │
│ scope参照 │ sso_provider参照
▼ ▼
┌─────────────────────────────┐ ┌─────────────────────────────┐
│ Authentication Policy │ │ Federation Configuration │
│ │ │ │
│ conditions: │ │ id: {federation_config_id} │
│ scopes: ["openid"] │ │ type: "oidc" │
│ │ │ sso_provider: "google" ◀────┼── 一致
│ available_methods: │ │ │
│ - "password" │ │ payload: │
│ - "oidc-google" ◀─────────┼────┤ provider: "standard" │
│ │ │ issuer: ... │
│ success_conditions: │ │ userinfo_mapping_rules │
│ oidc-google.success >= 1 │ │ │
└─────────────────────────────┘ └─────────────────────────────┘
紐づけルール:
- Client → Federation:
extension.available_federations[].sso_providerで利用可能なFederation Configurationを指定 - Policy → Federation:
available_methodsにoidc-{sso_provider}形式でFederation Configurationを参照 - auto_selected:
trueの場合、認証画面でこのFederationが自動選択される
設定ファイル構造
federation/oidc/external-idp.json
{
"id": "dc000822-a7ca-47b9-aea2-f81e2772b037",
"type": "oidc",
"sso_provider": "external-idp",
"payload": {
"issuer": "${EXTERNAL_IDP_ISSUER}",
"issuer_name": "external-idp",
"type": "oauth-extension",
"provider": "oauth-extension",
"authorization_endpoint": "${EXTERNAL_IDP_AUTHORIZATION_ENDPOINT}",
"token_endpoint": "${EXTERNAL_IDP_TOKEN_ENDPOINT}",
"userinfo_endpoint": "${EXTERNAL_IDP_USERINFO_ENDPOINT}",
"client_id": "${EXTERNAL_IDP_CLIENT_ID}",
"client_secret": "${EXTERNAL_IDP_CLIENT_SECRET}",
"client_authentication_type": "client_secret_post",
"redirect_uri": "${IDP_SERVER_URL}/${TENANT_ID}/v1/authorizations/federations/oidc/callback",
"scopes_supported": [
"openid",
"profile",
"email"
],
"userinfo_mapping_rules": [
{
"from": "$.sub",
"to": "external_user_id"
},
{
"from": "$.name",
"to": "name"
},
{
"from": "$.email",
"to": "email"
}
],
"access_token_expires_in": 300,
"refresh_token_expires_in": 1800,
"store_credentials": true
}
}
主要なフィールド
基本情報
| フィールド | 必須 | 説明 | 例 |
|---|---|---|---|
id | ✅ | Federation設定ID(UUID) | dc000822-... |
type | ✅ | プロトコルタイプ | oidc / saml |
sso_provider | ✅ | プロバイダーID | external-idp |
Payloadセクション
Executorタイプ
| フィールド | 必須 | 説明 | 値 |
|---|---|---|---|
type | ✅ | プロトコル種別 | standard |
provider | ✅ | Executorタイプ | standard / oauth-extension / Facebook |
providerの選択基準:
standard: 標準OIDCフロー(Google, Azure AD等)oauth-extension: カスタムUserInfo取得が必要な場合(userinfo_executionと併用)Facebook: Facebook Login専用(大文字始まり)
⚠️ 注意: 無効なprovider値を指定するとサーバーエラーになります。値は大文字小文字を区別します。
OIDC基本設定
| フィールド | 必須 | 説明 |
|---|---|---|
issuer | ✅ | 外部IdPのIssuer |
issuer_name | ✅ | IdP識別名(ユーザーのexternal_idp_issuerに設定) |
authorization_endpoint | ✅ | 認可エンドポイント |
token_endpoint | ✅ | トークンエンドポイント |
userinfo_endpoint | ✅ | UserInfoエンドポイント |
client_id | ✅ | idp-serverのクライ アントID |
client_secret | ✅ | idp-serverのクライアントシークレット |
redirect_uri | ✅ | コールバックURI(/{tenant-id}/v1/authorizations/federations/oidc/callback) |
scopes_supported | ✅ | リクエストするスコープ |
UserInfo Mapping Rules
外部IdPのUserInfo → idp-serverのUserへのマッピング:
{
"userinfo_mapping_rules": [
{
"from": "$.sub",
"to": "external_user_id"
},
{
"from": "$.name",
"to": "name"
},
{
"from": "$.email",
"to": "email"
},
{
"from": "$.custom_field",
"to": "custom_properties.custom_field"
}
]
}
JSONPath: $. で外部IdPのUserInfo JSONを参照
Executorタイプによるレスポンス構造の違い
| Executorタイプ | JSONPath構造 | 例 |
|---|---|---|
standard | $.http_request.response_body.xxx | $.http_request.response_body.email |
oauth-extension | $.xxx または $.userinfo_execution_http_requests[N].response_body.xxx | $.email |
Facebook | $.http_request.response_body.xxx | $.http_request.response_body.email |
⚠️ StandardOidcExecutor: UserInfoレスポンスがhttp_request.response_bodyでラップされるため、JSONPathを調整が必要です。
standard / Facebook では、レスポンスボディ以外に次も参照できます。
| パス | 内容 | 値の形 |
|---|---|---|
$.http_request.status_code | UserInfo レスポンスのHTTPステータスコード | 数値 |
$.http_request.response_headers.* | UserInfo レスポンスヘッダー | 文字列(同名ヘッダーが複数ある場合は先頭の値) |
oauth-extension の $.userinfo_execution_http_requests[N].response_headers.* と同じ形です。
staus_code という綴りでしたステータスコードのキーは staus_code(タイポ)でした 。status_code に修正し、旧キーは削除しました。
staus_code を参照している userinfo_mapping_rules があれば status_code に書き換えてください。参照パスが解決しなくなってもエラーにはならず、値が null になるだけです。
idp-server同士のフェデレーション時の注意
Provider IdPがidp-serverの場合、Provider側の認可サーバーにclaims_supportedを設定する必要があります:
{
"authorization_server": {
"claims_supported": ["sub", "name", "email", "email_verified", "preferred_username"]
}
}
これがないと、UserInfoエンドポイントはsubのみを返し、email等のクレームがマッピングされません。
高度なUserInfo取得(http_requests)
単純なUserInfoエンドポイントでは不十分な場合に、複数のAPIを連続実行してUserInfoを構築します。
基本パターン: 複数API連続実行
{
"userinfo_execution": {
"function": "http_requests",
"http_requests": [
{
"url": "${EXTERNAL_API_URL}/accounts",
"method": "GET",
"note": "1. アカウント情報取得"
},
{
"url": "${EXTERNAL_API_URL}/profile",
"method": "GET",
"note": "2. プロファイル情報取得"
}
]
},
"userinfo_mapping_rules": [
{
"from": "$.userinfo_execution_http_requests[0].response_body.account_id",
"to": "external_user_id"
},
{
"from": "$.userinfo_execution_http_requests[1].response_body.name",
"to": "name"
}
]
}
condition: 条件付き実行
各リクエストに condition を書くと、false のときそのリクエストを送らずにスキップします。前段の応答で後段を呼ぶかどうかを決められます。
{
"url": "${EXTERNAL_API_URL}/profile",
"method": "GET",
"condition": {
"operation": "eq",
"path": "$.execution_http_requests[0].response_body.account_type",
"value": "PREMIUM"
}
}
演算子の一覧と、評価に失敗したときの挙動は condition(条件式) を参照してください。
参照できるコンテキストは2つだけです。
| パス | 存在する条件 | 内容 |
|---|---|---|
$.request_body | 常に | {"access_token": "<上流のアクセストークン>"} |
$.execution_http_requests | 2本目以降のリクエストのみ | それまでの結果 |
認証側にある $.request_attributes / $.user / $.interaction はフェデレーションにはありません。
条件の中で前段を参照するパスは $.execution_http_requests[...](実行中のコンテキスト)で、userinfo_mapping_rules 側の $.userinfo_execution_http_requests[...](実行完了後のコンテキスト)とは異なります。取り違えても値が null になるだけでエラーにならないため、条件が常に false になってそのリクエストが永久にスキップされます。
条件はリクエストを送る前に評価されるため、1本目の時点ではまだ結果がありません。参照しても null になり、そのリクエストは常にスキップされます。
スキップしても添字は詰まりません。 userinfo_execution_http_requests[N] は「設定の N 番目」を指し、スキップされた枠には {"skipped": true} が入ります。条件の真偽で userinfo_mapping_rules の参照先がずれることはありません。
設定したすべてのリクエストがスキップされた場合、userinfo 取得は失敗します(SSO ログイン全体が失敗します)。
この chain は上流IdPからユーザー情報を取得する手段そのものです。1本も実行されなければ取得結果が空になり、そのまま成功にすると external_user_id が解決できないまま新規ユーザーを作成する経路に入ります。条件のパスを1文字間違えただけで、上流IdPに一度も問い合わせないままフェデレーションユーザーが増えることになるため、失敗として扱います。
一部だけスキップされる通常の分岐は該当しません。
排他的な条件で「A のあと B か C のどちらか」を書く場合、userinfo_mapping_rules 側にも {"operation": "missing", "path": "$.userinfo_execution_http_requests[N].skipped"} のガードが必要です(マッピングは後勝ちで、値が解決しなくても null を書き込むため)。詳しくは外部トークン認証の設定の同じ節を参照してください。
重要:
userinfo_execution_http_requests[0]- 1番目のAPIレスポンスuserinfo_execution_http_requests[1]- 2番目のAPIレスポンス- インデックス順に実行される
高度なパターン: Access Tokenを使った認証
外部IdPから取得したAccess Tokenで、外部APIにアクセス:
{
"userinfo_execution": {
"function": "http_requests",
"http_requests": [
{
"url": "${EXTERNAL_API_URL}/accounts",
"method": "GET",
"note": "Access Tokenで外部API呼び出し",
"header_mapping_rules": [
{
"static_value": "application/json",
"to": "Accept"
},
{
"from": "$.request_body.access_token",
"to": "Authorization",
"convertType": "string",
"functions": [
{
"name": "format",
"args": {
"template": "Bearer {{value}}"
}
}
]
}
]
}
]
}
}
重要なポイント:
$.request_body.access_token- 外部IdPから取得したAccess Tokenfunctions-format関数で"Bearer "プレフィックスを付与convertType: "string"- 文字列として扱う
最高度パターン: OAuth 2.0認証付きAPI呼び出し
外部APIが独自のOAuth 2.0認証を要求する場合:
{
"userinfo_execution": {
"function": "http_requests",
"http_requests": [
{
"url": "${EXTERNAL_API_URL}/secure-data",
"method": "POST",
"note": "OAuth 2.0認証が必要なAPI",
"auth_type": "oauth2",
"oauth_authorization": {
"type": "client_credentials",
"token_endpoint": "${EXTERNAL_AUTH_URL}/token",
"client_id": "${EXTERNAL_CLIENT_ID}",
"client_secret": "${EXTERNAL_CLIENT_SECRET}",
"client_authentication_type": "client_secret_post",
"scope": "read:data",
"cache_enabled": true,
"cache_ttl_seconds": 3600,
"cache_buffer_seconds": 10
}
}
]
}
}
OAuth認証のキャッシュ設定:
cache_enabled: true- トークンをキャッシュcache_ttl_seconds: 3600- キャッシュ有効期限(秒)cache_buffer_seconds: 10- 期限切れ10秒前に再取得
動作:
- 初回: Token Endpointでトークン取得 → キャッシュ保存
- 2回目以降: キャッシュから取得(高速)
- 期限切れ前: 自動的に再取得
複数APIの結果を統合する例
{
"userinfo_mapping_rules": [
{
"from": "$.userinfo_execution_http_requests[0].response_body.user_id",
"to": "external_user_id",
"note": "1番目のAPI(/accounts)から取得"
},
{
"from": "$.userinfo_execution_http_requests[0].response_body.account_type",
"to": "custom_properties.account_type",
"note": "1番目のAPIから取得"
},
{
"from": "$.userinfo_execution_http_requests[1].response_body.email",
"to": "email",
"note": "2番目のAPI(/email)から取得"
},
{
"from": "$.userinfo_execution_http_requests[2].response_body.phone",
"to": "phone_number",
"note": "3番目のAPI(/phone)から取得"
}
]
}
重要: 各APIのレスポンスを[0], [1], [2]のインデックスで参照
詳細: HttpRequestExecutor実装ガイド、Mapping Functions
トークン保存
| フィールド | 説明 | デフォルト |
|---|---|---|
store_credentials | 外部IdPのトークンを保存 | false |
access_token_expires_in | Access Token有効期限 | 300秒 |
refresh_token_expires_in | Refresh Token有効期限 | 1800秒 |
用途: 外部APIへの後続アクセスでトークンを再利用