External Token認証
このドキュメントは、external-token 方式による外部トークンを使った認証処理の 概要・設定・利用方法 について説明します。
概要
External Token認証は、外部のアイデンティティプロバイダー(IdP)が発行したアクセストークンを使って、ユーザー認証とユーザー情報取得を行う方式です。
主な用途
- 他のIdP(Google、Azure AD、独自IdP等)で認証済みのユーザーを連携
- 既存システムのアクセストークンを使った認証
- API-to-API認証での利用
処理フロー
- クライアントが外部IdPからアクセストークンを取得
- そのアクセストークンをidp-serverに送信
- idp-serverが外部APIにトークンを送信してユーザー情報を取得
- 取得したユーザー情報でidp-server内のユーザーと紐付け
- 認証成功
設定
External Token認証を使用するには、テナントに type = "external-token" の認証設定を登録する必要があります。
基本構造
{
"id": "UUID",
"type": "external-token",
"attributes": {
"service_name": "external-service-name"
},
"metadata": {},
"interactions": {
"external-token": {
"request": {
"schema": {
"type": "object",
"properties": {
"access_token": { "type": "string" }
}
}
},
"execution": {
"function": "http_requests",
"http_requests": [
{ /* ユーザー概要取得API */ },
{ /* ユーザー詳細取得API */ }
]
},
"user_resolve": {
"user_mapping_rules": [ /* ユーザー情報マッピング */ ]
}
}
}
}
Request Schema
External Token認証で受け付けるリクエストの構造:
{
"request": {
"schema": {
"type": "object",
"properties": {
"access_token": {
"type": "string",
"description": "外部IdPが発行したアクセストークン"
}
},
"required": ["access_token"]
}
}
}
Execution: 複数HTTPリクエスト
function: http_requests
複数の外部APIを連続して呼び出し、ユーザー情報を取得します。
HTTP Requests 設定
{
"execution": {
"function": "http_requests",
"http_requests": [
{
"url": "https://external-service.com/user/overview",
"method": "POST",
"header_mapping_rules": [
{
"from": "$.request_body.access_token",
"to": "x-token",
"functions": [
{ "name": "format", "args": { "template": "Bearer {{value}}" } }
]
},
{
"from": "$.unused",
"to": "x-request-id",
"functions": [
{ "name": "random_string", "args": { "length": 6 } },
{ "name": "format", "args": { "template": "trace-id-{{value}}" } }
]
}
],
"body_mapping_rules": [
{ "from": "$.request_body", "to": "*" }
]
},
{
"url": "https://external-service.com/user/details",
"method": "POST",
"header_mapping_rules": [
{ "static_value": "your-client-id", "to": "x-client-id" }
],
"body_mapping_rules": [
{
"from": "$.execution_http_requests[0].response_body.id",
"to": "user_id"
}
]
}
]
}
}
主要項目
| 項目 | 説明 |
|---|---|
url | 外部APIのエンドポイント |
method | HTTPメソッド(POST/GET等) |
header_mapping_rules | HTTPヘッダーのマッピングルール |
body_mapping_rules | リクエストボディのマッピングルール |
condition | このリクエストを送るかどうかの条件(省略時は無条件で実行) |
condition: 条件付き実行
前段の応答に応じて後段を呼ぶかどうかを切り替えられます。false のときそのリクエストは送られません。
"http_requests": [
{ "url": "https://api.example.com/assess", "method": "POST" },
{
"url": "https://api.example.com/notify",
"method": "POST",
"condition": {
"operation": "eq",
"path": "$.execution_http_requests[0].response_body.result",
"value": "HIGH"
}
}
]
演算子の一 覧と、評価に失敗したときの挙動は condition(条件式) を参照してください。
参照できるコンテキスト
path に書けるキーは以下です。常に存在するとは限らない点に注意してください。
| パス | 存在する条件 | 内容 |
|---|---|---|
$.request_body | 常に | interaction のリクエストボディ |
$.request_attributes | 常に | ip_address / user_agent / resource / action / request_url / headers |
$.user | external-api-authentication の interaction でのみ、かつユーザーが確立しているとき | 許可リスト投影(sub / email / name / roles / custom_properties 等) |
$.interaction | previous_interaction を設定したときのみ | 前のインタラクションの保存データ |
$.execution_http_requests | 2本目以降のリクエストのみ | それまでの結果 |
$.request_body と $.request_attributes は最初から使えるため、チェーンの1本目を条件付きにできます。「クライアントが送った内容で、呼ぶAPIそのものを出し分ける」といっ た構成が書けます。
条件はリクエストを送る前に評価されるため、1本目の時点ではまだ結果がありません。参照しても null になり、eq などは false になるのでそのリクエストは常にスキップされます。エラーにはならないので気づけません。
$.user はこのページの設定では使えません
$.user は入りません$.user を注入しているのは ExternalApiAuthenticationInteractor の1箇所だけです。external-token / fido-uaf / sms / email の chain には一度も入りません。
このページの設定で {"operation": "exists", "path": "$.user.sub"} と書くと恒久的にスキップされ、missing と書くと常に実行されます。設定の登録も GET も成功するため、実行時まで気づけません。
external-api-authentication の interaction では使えます。その場合もユーザーが確立していなければキーごと存在しないため、「存在しない」ではなく「条件が false 側に倒れる」形で効きます。
| 条件 | ユーザー未確立 | ユーザー確立済み |
|---|---|---|
{"operation": "exists", "path": "$.user.sub"} | スキップ | 実行 |
{"operation": "missing", "path": "$.user.sub"} | 実行 | スキップ |
{"operation": "eq", "path": "$.user.email", ...} | スキップ | 値で判定 |
確立していれば chain の1本目からでも使えます(要素の位置ではなく、そのトランザクションにユーザーがいるかどうかで決まります)。
スキップしても添字は詰まりません
execution_http_requests[N] は「設定の N 番目」を指し、スキップされた枠には {"skipped": true} が入ります。
| 設定 | execution_http_requests |
|---|---|
[A, B(条件false), C] | [0]=A の結果 / [1]={"skipped": true} / [2]=C の結果 |
条件の真偽で後続の参照パスが変わらないため、$.execution_http_requests[2] は常に3番目の設定を指します。
全リクエストがスキップされた場合はエラーになります
設定したすべてのリクエストがスキップされた場合、interaction は失敗します。
外部サービスの呼び出しそのものが検証である以上、1本も実行されていなければ何も検証できていないためです。成功にしてしまうと、条件のパスを1文字間違えただけで「外部サービスに一度も問い合わせないまま認証ステップが通る」状態になります。
一部 だけスキップされる通常の分岐は該当しません。「今回は何も呼ばない」を正当に表現したい場合は、いずれか1本を条件なしにしてください。
失敗の理由(error / error_description)は response.body_mapping_rules を通るため、それを拾うルールを書いていなければレスポンスには現れません。ステータスコードとサーバーの warn ログでは確認できます。
HTTPエラー時のガードには不要です
前段が 4xx / 5xx を返した場合、後段はもともと実行されません(連鎖はその時点で中断します)。response_resolve_configs で 200 をエラーに寄せた場合も同じです。
condition の出番は「前段は成功扱いなのに、後段を呼びたくない」場合です。同じ「200 だがボディが業務エラー」に対して、次のように使い分けます。
| やりたいこと | 使うもの |
|---|---|
| interaction 全体を失敗にする | response_resolve_configs でエラーコードにマップ |
| interaction は成功のまま、後段だけ省く | condition |