CIBAでユーザーを認証する
CIBA(Client-Initiated Backchannel Authentication)はログインや認証の処理について、クライアントアプリケーションがブラウザーでユーザーをリダイレクトすることに依存しません。その代わりに、クライアントアプリケーションがバックチャネル要求を通して直接OpenIDプロバイダーを呼び出し、認証フローを開始します。
以下のシーケンス図はCIBAフローの実装をまとめたものです。

シーケンス図では、認可しているユーザーと開始しているユーザーという2人の行為者が定義されています。認可や開始を行うユーザーは、たとえばコールセンターに問い合わせている人とコールセンターの担当者など、別の2人になる可能性があります。他のユースケースでは、たとえば認証して販売店や別の接続デバイスにアクセスしようとしている人など、同じ人になる可能性もあります。
以下のセクションでは、CIBAフローでユーザー認証が動作する仕組みについて、手順を追って説明します。
前提条件
CIBAのプッシュ要求を開始するには、認可しているユーザーがプッシュ通知でMFAに登録されていなければなりません。Auth0 Dashboardで確認するには、[User Management(ユーザーの管理)]>[Users(ユーザー)]に移動して、ユーザーをクリックします。

テナントで多要素認証を常に必須に設定した場合は、ユーザーが次回にログインするときに、MFAへの登録が求められます。また、Actionsを使用して、MFAの登録を促すこともできます。
MFAのプッシュ通知は通常、Guardian SDKを組み込んだカスタムのモバイルアプリ内で実装されます。詳細については、「CIBA(Client-Initiated Backchannel Authentication)を構成するをお読みください。
ステップ1:クライアントアプリケーションがCIBA要求を開始する
ユーザー検索APIを使用して、認可しているユーザーを見つけます。このユーザーのためにCIBA要求を始めてユーザーIDを取得することになります。
認可しているユーザーのユーザーIDを入手したら、Authentication APIまたはAuth0のSDKを使用して、CIBA要求を/bc-authorize
エンドポイントに送信します。
curl --location 'https://[TENANT].auth0.com/bc-authorize' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=[CLIENT ID]' \
--data-urlencode 'client_secret=[CLIENT SECRET]' \
--data-urlencode 'login_hint={ "format": "iss_sub", "iss": "https://[TENANT].auth0.com/", "sub": "[USER ID]" }' \
--data-urlencode 'scope=[SCOPE]' \
--data-urlencode 'binding_message=[BINDING MESSAGE]'
Was this helpful?
var response = await authenticationApiClient.ClientInitiatedBackchannelAuthorization(
new ClientInitiatedBackchannelAuthorizationRequest()
{
ClientId = "your-client-id",
Scope = "openid",
ClientSecret = "your-client-secret",
BindingMessage = "your-binding-message",
LoginHint = new LoginHint()
{
Format = "iss_sub",
Issuer = "your-issuer-domain",
Subject = "auth0|user-id-here"
}
}
);
Was this helpful?
resp, err := authAPI.CIBA.Initiate(context.Background(), ciba.Request{
ClientID: mgmtClientID,
ClientSecret: mgmtClientSecret,
Scope: "openid",
LoginHint: map[string]string{
"format": "iss_sub",
"iss": "your-issuer-domain",
"sub": "auth0|user-id-here",
},
BindingMessage: "TEST-BINDING-MESSAGE",
})
Was this helpful?
//Creating AuthClient Instance
AuthAPI auth = AuthAPI.newBuilder(domain, clientId, clientSecret).build();
//Authorize
Map<String, Object> loginHint = new HashMap<>();
loginHint.put("format", "iss_sub");
loginHint.put("iss", "your-issuer-domain");
loginHint.put("sub", "auth0|user-id-here");
Request<BackChannelAuthorizeResponse> request = auth.authorizeBackChannel("openid", "your-binding-message", loginHint);
BackChannelAuthorizeResponse resp = request.execute().getBody();
Was this helpful?
パラメーター | 説明 |
---|---|
TENANT | テナント名。カスタムドメインにすることもできます。 |
CLIENT ID | クライアントアプリケーション識別子 |
CLIENT SECRET | クライアントシークレット、プライベートキーJWT、mTLS認証など、CIBAを使ったユーザー認証に使用されるクライアント認証方法。 |
SCOPE | openid を含める必要があります。スコープには、リフレッシュトークンを要求するための offline_access をオプションで含めることができます。ただし、CIBAフローを使ったトランザクションのワンタイム認証にはリフレッシュトークンは必要なく、その場合は意味を持ちません。 |
USER ID | login_hint 構造で渡される、認証を受けるユーザーのユーザーID。フェデレーション接続のユーザーIDは、フォーマットが異なることがあります。 |
EXPIRY | CIBAフローの要求された有効期限は1秒から300秒の間で、デフォルトは300秒です。 |
BINDING MESSAGE | 認証デバイスと消費デバイス間でCIBAフローをバインドするために使用されるメッセージ。バインドメッセージは必須で、最大64文字です。英数字と+-_.,:# の文字のみを使用してください。 |
AUDIENCE | 発行されたトークンに対するオーディエンスを表す一意の識別子。 |
ステップ2:Auth0テナントがCIBA要求を確認する
Auth0テナントがPOST要求の受信に成功したら、その要求を参照したauth-req-id
のある応答を受け取るはずです。
{
"auth_req_id": "eyJh...",
"expires_in": 300,
"interval": 5
}
Was this helpful?
auth_req_id
値はCIBAフローの完了をポーリングするために、/token
エンドポイントに渡されます。
ステップ3:クライアントアプリケーションが応答をポーリングする
Authentication APIまたはAuth0のSDKを使用して/token
エンドポイントを呼び出し、urn:openid:params:grant-type:ciba
の付与タイプと/bc-authorize
エンドポイントから受け取ったauth_req_id
を渡します。
curl --location 'https://[TENANT].auth0.com/oauth/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=[CLIENT ID]' \
--data-urlencode 'client_secret=[CLIENT SECRET]' \
--data-urlencode 'auth_req_id=[FROM THE BC-AUTHORIZE RESPONSE]' \
--data-urlencode 'grant_type=urn:openid:params:grant-type:ciba'
Was this helpful?
var token = await authenticationApiClient.GetTokenAsync(
new ClientInitiatedBackchannelAuthorizationTokenRequest()
{
AuthRequestId = response.AuthRequestId,
ClientId = "your-client-id",
ClientSecret = "your-client-secret"
}
);
Was this helpful?
token, err := authAPI.OAuth.LoginWithGrant(context.Background(),
"urn:openid:params:grant-type:ciba",
url.Values{
"auth_req_id": []string{resp.AuthReqID},
"client_id": []string{clientID},
"client_secret": []string{clientSecret},
},
oauth.IDTokenValidationOptions{})
Was this helpful?
Request<BackChannelTokenResponse> tokenRequest = auth.getBackChannelLoginStatus(authReqId, "grant-type");
BackChannelTokenResponse tokenResponse = tokenRequest.execute().getBody();
Was this helpful?
認可しているユーザーがトランザクションを承認するまでは、以下の応答を受け取ります。
{
"error": "authorization_pending",
"error_description": "The end-user authorization is pending"
}
Was this helpful?
ポーリングの間隔は約5秒です。ポーリングが頻繁すぎると、以下の応答を受け取ります。その内容はバックオフ間隔によって異なります。
{
"error": "slow_down",
"error_description": "You are polling faster than allowed. Try again in 10 seconds."
"interval": 10
}
Was this helpful?
エラーを解消するには、次の間隔(秒単位)まで待ってから、/token
エンドポイントをポーリングします。
ステップ4:モバイルアプリケーションがプッシュ通知を受け取る
Auth0はプッシュ通知をユーザーの登録済みのモバイルアプリまたはモバイルデバイスに送信します。Guardian SDKにはプッシュ通知で受け取ったデータを解析するメソッドが備わっているため、即座に使えるNotification
インスタンスを返します。Notification
インスタンスにはトランザクションリンクIDまたはtxlinkid
が含まれており、モバイルアプリケーションはAuth0から同意の詳細を取得するためにそれを使用します。
以下のサンプルコードはGuardian SDKを使用して、iOSとAndroidのモバイルプッシュ通知を実装する例です。
//implementing UNUserNotificationCenterDelegate
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: (UNNotificationPresentationOptions) -> Void) {
let userInfo = notification.request.content.userInfo
if let notification = Guardian.notification(from: userInfo) {
handleGuardianNotification(notification: notification)
}
}
Was this helpful?
// at the FCM listener you receive a RemoteMessage
@Override
public void onMessageReceived(RemoteMessage message) {
Notification notification = Guardian.parseNotification(message.getData());
if (notification != null) {
// you received a Guardian notification, handle it
handleGuardianNotification(notification);
return;
}
/* handle other push notifications you might be using ... */
}
Was this helpful?
ステップ5:モバイルアプリケーションが同意の詳細を取得する
モバイルアプリケーションからGuardian SDKを呼び出して、同意の詳細であるbinding_message
の内容をAuth0 Consent APIから取得します。
以下のサンプルコードは、Auth0 Consent APIからのデータ取得をiOSとAndroidに実装する例です。
let device: AuthenticationDevice = // the object you obtained when enrolling
if let consentId = notification.transactionLinkingId {
Guardian
.consent(forDomain: {yourTenantDomain}, device: device)
.fetch(consentId: consentId, notificationToken: notification.transactionToken)
.start{result in
switch result {
case .success(let payload):
// present consent details to the user
case .failure(let cause):
// something went wrong
}
}
}
Was this helpful?
Enrollment enrollment = // the object you obtained when enrolling
if (notification.getTransactionLinkingId() != null) {
guardian
.fetchConsent(notification, enrollment)
.start(new Callback<Enrollment> {
@Override
void onSuccess(RichConsent consentDetails) {
// present consent details to the user
}
@Override
void onFailure(Throwable exception) {
// something went wrong
}
});
}
Was this helpful?
ステップ6:モバイルアプリケーションが同意の詳細をユーザーに表示する
Auth0 Consent APIは、同意の詳細であるbinding_message
を応答に含めてモバイルアプリケーションに送信します。モバイルアプリケーションは認証要求や同意の詳細をユーザーに表示します。
以下のサンプルコードはAuth0 Consent APIからの応答の例です。
{
id: string,
requestedDetails: {
audience: string,
scope: string,
binding_message: string
},
created_at: unix timestamp
expires_at: unix timestamp
}
Was this helpful?
ユーザーはこの時点で認証要求を受け入れるか拒否できます。
ステップ7:モバイルアプリケーションがユーザーの応答をAuth0に送信する
ユーザーによる認証要求の受け入れまたは拒否に応じて、モバイルアプリケーションがユーザーの応答をAuth0に返します。
以下のサンプルコードは、ユーザー応答の処理をiOSとAndroidに実装する例です。
ユーザーが認証要求を受け入れる
Guardian
.authentication(forDomain: "{yourTenantDomain}", device: device)
.reject(notification: notification)
// or reject(notification: notification, withReason: "hacked")
.start { result in
switch result {
case .success:
// the auth request was successfully rejected
case .failure(let cause):
// something failed, check cause to see what went wrong
}
}
Was this helpful?
guardian
.allow(notification, enrollment)
.execute(); // or start(new Callback<> ...)
Was this helpful?
ユーザーが認証要求を拒否する
Guardian
.authentication(forDomain: "{yourTenantDomain}", device: device)
.reject(notification: notification)
// or reject(notification: notification, withReason: "hacked")
.start { result in
switch result {
case .success:
// the auth request was successfully rejected
case .failure(let cause):
// something failed, check cause to see what went wrong
}
}
Was this helpful?
guardian
.reject(notification, enrollment) // or reject(notification, enrollment, reason)
.execute(); // or start(new Callback<> ...)
Was this helpful?
ステップ8:フローが完了した後でAuth0がユーザーの応答を受け取る
クライアントアプリケーションは/token
エンドポイントから応答を受け取ったら、ポーリングを完了します。承認や拒否にかかわらず、CIBAフローには認可しているユーザーからの応答が常に必要です。既存の付与は確認されません。
ユーザーがプッシュ要求を拒否した場合は、以下の応答を受け取ります。
{
"error": "access_denied",
"error_description": "The end-user denied the authorization request or it has been expired"
}
Was this helpful?
ユーザーがプッシュ要求を承認した場合は、以下の応答を受け取ります。
{
"access_token": "eyJh...",
"id_token": "eyJh...",
"expires_in": 86400,
"scope": "openid"
}
Was this helpful?