Skip to main content

Backchannel Authentication (CIBA)

Client-Initiated Backchannel Authentication (CIBA) (CIBA Core 1.0) is an OpenID Connect extension that lets a client application trigger user authentication on a separate device, without any browser redirect.

In every traditional OpenID Connect flow, the same device that initiates the request also completes the sign-in. CIBA breaks that assumption. A consumption device (for example, a call center terminal or a point-of-sale terminal) starts the request. The user authenticates on an authentication device (for example, their phone). The two devices share no direct connection: ThunderID coordinates between them.

ThunderID supports CIBA in poll mode only. The login_hint_token hint type is defined in the specification but is not supported; use login_hint or id_token_hint instead.

Typical use cases include:

  • A call center agent verifying a caller's identity, with the caller approving on their phone.
  • A bank teller initiating a payment authorization, with the customer approving on their mobile banking app.
  • A point-of-sale terminal requesting payment authentication, with the customer approving on their phone.

How It Works

The flow proceeds in three phases:

Phase 1: Initiation

  1. The client sends POST /oauth2/bc-authorize with a user hint (for example, login_hint), the requested scopes, and an optional resource that binds the request to a single resource server.
  2. ThunderID validates the request and sends a notification to the user's authentication device.
  3. ThunderID returns an auth_req_id, a polling interval, and an expiry time.

Phase 2: User Authentication

  1. The user reviews the request on their authentication device and approves or denies it.
  2. ThunderID records the decision and marks the auth_req_id accordingly.

Phase 3: Token Retrieval

  1. The client polls POST /oauth2/token with grant_type=urn:openid:params:grant-type:ciba until the user has acted.
  2. ThunderID returns an access token and, when openid is in the scope, an ID token.
How ThunderID Implements It
AspectBehavior
Backchannel authentication endpointPOST /oauth2/bc-authorize
Token endpointPOST /oauth2/token
Grant typeurn:openid:params:grant-type:ciba
Client typeConfidential clients only
User hintExactly one of login_hint or id_token_hint must be provided. The specification also defines login_hint_token, but it is not yet supported; the server returns invalid_request when provided.
Poll modeOnly poll mode is supported; push mode is not implemented
Default expires_in120 seconds
Maximum expires_in600 seconds; ThunderID clamps any requested_expiry value above this limit
Default polling interval5 seconds
slow_downReturned when the client polls faster than the current interval; the client must permanently increase the interval by 5 seconds
Scope requirementMust include openid
Resource binding (RFC 8707)An optional resource binds the request to one resource server at initiation. When a permission scope is requested without resource, the configured defaultResourceServer applies; with no default, the request is rejected with invalid_target. The access token's aud is the bound resource server identifier, and its permissions are limited to that server. OIDC-only requests without resource use the application's token.accessToken.defaultAudience, falling back to client_id. A resource supplied when polling must match the binding
binding_messageOptional; maximum 256 printable characters; ThunderID generates a default message when omitted
Token issuanceAccess token always issued; ID token issued when openid is in the scope; refresh token issued when refresh_token grant is configured on the client
One-time useThunderID atomically marks the auth_req_id as consumed on the first successful token exchange; subsequent polls return invalid_grant
Discoverybackchannel_authentication_endpoint is advertised in the OIDC discovery document

Enable CIBA on a Client

  1. Open Applications or Agents in the ThunderID Console and select your client.
  2. Open the Advanced Settings tab.
  3. Under Grant Types, select urn:openid:params:grant-type:ciba.
  4. Choose a confidential Token Endpoint Authentication method. See Client Authentication Methods.
  5. Save.

Run the Flow

Step 1: Initiate Backchannel Authentication

curl -X POST https://thunderid.example.com/oauth2/bc-authorize \
-u "$CLIENT_ID:$CLIENT_SECRET" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "scope=openid profile" \
-d "login_hint=user@example.com" \
-d "binding_message=Approve login from call center"

Response:

{
"auth_req_id": "a1b2c3d4-...",
"expires_in": 120,
"interval": 5
}

Step 2: Poll the Token Endpoint

Poll until the user approves, the request expires, or an error is returned.

curl -X POST https://thunderid.example.com/oauth2/token \
-u "$CLIENT_ID:$CLIENT_SECRET" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=urn:openid:params:grant-type:ciba" \
-d "auth_req_id=a1b2c3d4-..."

While the user has not yet authenticated, the server returns:

{
"error": "authorization_pending",
"error_description": "The user has not yet completed authentication"
}

Wait for the interval (or a longer interval after a slow_down response), then retry.

When the user authenticates, the server returns:

{
"access_token": "eyJhbGciOiJSUzI1NiI...",
"id_token": "eyJhbGciOiJSUzI1NiI...",
"token_type": "Bearer",
"expires_in": 3600
}

Polling Error Reference

ErrorMeaningAction
authorization_pendingUser has not yet acted.Retry after the current interval.
slow_downClient is polling too frequently.Increase the interval permanently by 5 seconds, then retry.
expired_tokenThe auth_req_id has expired.Stop polling; the request cannot be recovered.
access_deniedThe user denied the request.Stop polling; restart the flow if appropriate.
invalid_grantThe auth_req_id has already been consumed.Stop polling; the flow is complete.

Explore with AI

ThunderID LogoThunderID Logo

Product

DocsAPIsSDKs
© Copyright Linux Foundation Europe.For web site terms of use, trademark policy and other project policies please see https://linuxfoundation.eu/en/policies.