CIBA
CIBA (Client Initiated Backchannel Authentication)
CIBAは、クライアントがユーザーのデバイスに直接アクセスすることなく、ユーザーの認証リクエストを開始できる認証フローです。認証は別のデバイス(例:モバイル電話)でバックチャネルを通じて行われます。
概要
- 仕様: OpenID Connect CIBA Flow Core 1.0
- ステータス: 完全実装
- エンドポイント:
POST /bc-authorize - 配信モード: Poll、Ping、Push
なぜCIBAを使用するのか?
ユースケース
- IoTデバイス: 入力機能のないデバイスでユーザーを認証
- コールセンター: エージェントが顧客のモバイルデバイスで認証を開始
- バンキング: Webアプリケーション使用中にモバイルアプリで取引承認
- スマートTV: TVリモコンで入力する代わりに電話で認証
Device Flowとの比較
| 機能 | CIBA | Device Flow |
|---|---|---|
| ユーザー識別 | クライアントがユーザーヒントを提供 | ユーザーがコードを入力 |
| 開始 | クライアント開始 | ユーザー開始 |
| ユーザー発見 | サーバーがユーザーを認識 | ユーザーが自己識別 |
| 最適用途 | 既知のユーザー、バックチャネル | 不明なユーザー、セルフサービス |
CIBAの仕組み
フロー概要
- クライアントがリクエストを開始:
login_hint付きでPOST /bc-authorizeを送信 - サーバーが通知を送信: ユーザーのデバイスに通知(プッシュ、SMS、メール)
- ユーザーが承認: ユーザーがデバイスでリクエストを承認
- クライアントがトークンをポーリング: クライアントが
/tokenエンドポイントをポーリング(pollモード) - サーバーがトークンを返却: ユーザー承認後、トークンを返却
トークン配信モード
クライアントがauth_req_idでトークンエンドポイントをポーリング:
POST /tokengrant_type=urn:openid:params:grant-type:ciba&auth_req_id=1c266114-a1be-4252-8ad1-04986c5b9ac1&client_id=my_client_id&client_secret=my_client_secretユーザー承認時にサーバーがHTTP POST通知を送信、その後クライアントがトークンを取得:
POST https://client.example.com/ciba/notifyContent-Type: application/json
{ "auth_req_id": "1c266114-a1be-4252-8ad1-04986c5b9ac1"}サーバーが通知でトークンを直接送信:
POST https://client.example.com/ciba/notifyContent-Type: application/json
{ "auth_req_id": "1c266114-a1be-4252-8ad1-04986c5b9ac1", "access_token": "eyJhbGc...", "token_type": "Bearer", "expires_in": 3600, "id_token": "eyJhbGc..."}APIリファレンス
バックチャネル認証エンドポイント
POST /bc-authorize
リクエスト
POST /bc-authorize HTTP/1.1Content-Type: application/x-www-form-urlencoded
scope=openid+profile+email&client_id=my_client_id&client_secret=my_client_secret&binding_message=Transaction+ID:+12345リクエストパラメータ
| パラメータ | 必須 | 説明 |
|---|---|---|
scope | Yes | OAuthスコープ(openidを含む必要がある) |
client_id | Yes | クライアント識別子 |
login_hint | いずれか* | ユーザー識別子(メール、電話、ユーザー名) |
login_hint_token | いずれか* | ログインヒントを含むJWT |
id_token_hint | いずれか* | 以前発行されたIDトークン |
binding_message | No | 人間が読めるメッセージ(最大140文字) |
user_code | No | ユーザー確認コード |
requested_expiry | No | リクエスト有効期限(秒) |
client_notification_token | 条件付き | ping/pushモードで必須 |
*login_hint、login_hint_token、id_token_hintのいずれか1つが必須
レスポンス
{ "auth_req_id": "1c266114-a1be-4252-8ad1-04986c5b9ac1", "expires_in": 300, "interval": 5}トークンエンドポイント(Pollモード)
POST /token
POST /token HTTP/1.1Content-Type: application/x-www-form-urlencoded
grant_type=urn:openid:params:grant-type:ciba&client_id=my_client_id&client_secret=my_client_secret&auth_req_id=1c266114-a1be-4252-8ad1-04986c5b9ac1レスポンス状態
保留中:
{ "error": "authorization_pending", "error_description": "ユーザーはまだ認証リクエストを認可していません"}拒否:
{ "error": "access_denied", "error_description": "ユーザーが認証リクエストを拒否しました"}成功:
{ "access_token": "eyJhbGc...", "token_type": "Bearer", "expires_in": 3600, "id_token": "eyJhbGc...", "refresh_token": "eyJhbGc...", "scope": "openid profile email"}ログインヒント形式
login_hintパラメータは複数の形式をサポート:
メール
電話(E.164)
login_hint=+14155552671login_hint=tel:+14155552671サブジェクト識別子
login_hint=sub:user123ユーザー名
login_hint=johndoeバインディングメッセージ
binding_messageは承認時にユーザーに表示されます:
binding_message=Banking Appにサインインbinding_message=取引ID: 12345binding_message=$100.00の支払いを承認制約:
- 最大140文字
- Unicode文字、数字、句読点、スペースを許可
- ユーザー承認UIで目立つように表示
使用例
// 1. CIBAリクエストを開始const cibaResponse = await fetch('https://auth.example.com/bc-authorize', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: new URLSearchParams({ scope: 'openid profile email', client_id: 'my_client_id', client_secret: 'my_client_secret', binding_message: 'My Appにサインイン', }),});
const { auth_req_id, interval } = await cibaResponse.json();
// 2. トークンをポーリングlet tokens;while (!tokens) { await new Promise(resolve => setTimeout(resolve, interval * 1000));
const tokenResponse = await fetch('https://auth.example.com/token', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: new URLSearchParams({ grant_type: 'urn:openid:params:grant-type:ciba', client_id: 'my_client_id', client_secret: 'my_client_secret', auth_req_id, }), });
if (tokenResponse.ok) { tokens = await tokenResponse.json(); }}
console.log('認証完了:', tokens);セキュリティ考慮事項
ログインヒント検証
- ログインヒントが正しい形式であることを検証
- 通知開始前にユーザーが存在することを確認
- スパム防止のためログインヒントごとにレート制限
バインディングメッセージインジェクション
- フィッシング防止のためバインディングメッセージをサニタイズ
- 生テキストのみ表示、HTMLやスクリプトなし
- UI問題防止のため長さを制限
リプレイ保護
auth_req_idは1回限りの使用- リクエストは設定されたタイムアウト後に期限切れ(デフォルト5分)
- トークン発行はアトミックで追跡
クライアント認証
- CIBAでは常にクライアント認証を要求
- client_secretまたは相互TLSを使用
- クライアントがCIBAグラントタイプを認可されていることを検証
エラーコード
| エラー | HTTPステータス | 説明 |
|---|---|---|
invalid_request | 400 | 必須パラメータの欠落または無効な形式 |
unauthorized_client | 401 | クライアントがCIBA用に登録されていない |
expired_token | 400 | 承認前に認証リクエストが期限切れ |
authorization_pending | 400 | ユーザーがまだ承認していない |
slow_down | 400 | クライアントのポーリングが頻繁すぎる |
access_denied | 403 | ユーザーがリクエストを拒否 |