Skip to main content
Version: Latest (4.0.6)

Implementing the CIBA Flow

CIBA (Client-Initiated Backchannel Authentication), also known as Transactional Authentication, is a modern OAuth 2.0 authentication flow that enables secure, device-to-device authentication. It allows users to authenticate on one device (like their mobile phone) while logging into an application on a completely different device (like a Smart TV, kiosk, or terminal).

Why use CIBA?

See Standards & Security Extensions for when backchannel auth (including Ping mode) fits your use case.

This flow is ideal for scenarios where users need to authenticate on devices with limited input capabilities or where enhanced security is required. CIBA enables transaction-based authentication where each authentication is a secure transaction between devices.

How it works?​

Before we step into the mechanics of working lets us understand some useful parameters.

Parameter NameDescription
client_idclient which represents the business-App in cidaas, where the Resource Owner wants to have access
Client authenticationRequired for a confidential OAuth client. Same methods as the token endpoint, based on the app's token_endpoint_auth_method: client_secret_basic (HTTP Basic), client_secret_post (body), private_key_jwt / client_secret_jwt (client_assertion in the body), or mTLS when enabled for the tenant. Public clients (none) fail client authentication. See Initiate CIBA Authentication.
scopeSpace-separated scopes. Must include openid. Scopes not allowed for the app are dropped silently; after filtering, openid must remain.
login_hintUser identifier (email, phone number, or username) to identify the user for authentication
binding_messageOptional message displayed to the user during authentication to provide context. After a successful CIBA grant, the same value is included in the issued access token and ID token so relying parties can correlate the transaction (not on later refresh tokens).
requested_expiryOptional requested expiration time in seconds for the authentication request (default 120 if omitted or invalid)
client_notification_tokenRequired when the app uses CIBA ping delivery. Bearer token cidaas sends to your notification endpoint. Max 1024 characters.
requestOptional signed CIBA request object (JWT). When valid, its claims replace the other body parameters.
resourceOptional list of resource URIs (RFC 8707 resource indicators). Applied only when Resource Indicators is enabled for your instance.
grant_typeurn:openid:params:grant-type:ciba needs to be mentioned in token request to get a token
auth_req_idUnique transaction identifier returned from the CIBA initiation request, used to poll for tokens
backchannel_token_delivery_modeApplication setting: poll (client polls the token endpoint) or ping (cidaas notifies the client when the user completes authentication). See CIBA Ping delivery.
backchannel_client_notification_endpointRequired for ping mode. HTTPS URL on your client that receives the ping notification.

CIBA Ping delivery​

With poll (default in many setups), the requesting device repeatedly calls POST /token-srv/token with grant_type=urn:openid:params:grant-type:ciba and auth_req_id until tokens are ready.

With ping, configure the application for CIBA backchannel delivery mode ping and set backchannel_client_notification_endpoint. On initiation, send client_notification_token in the CIBA request. After the user approves on the authenticator, cidaas POSTs a JSON body containing only auth_req_id to that endpoint (Authorization: Bearer with the client notification token). Your client should then call the token endpoint once with that auth_req_id (same grant as poll). Expect HTTP 200 or 204 from your notification endpoint; redirects are not followed.

Ping does not replace the token request — it only tells you when to call the token endpoint instead of polling on an interval. Push delivery mode is not supported on the initiation endpoint.

Let's take up the scenario of a user who wants to get access to the business app on a Smart TV.

Step 1: The requesting device (Smart TV) initiates authentication by making a POST call to /authz-srv/ciba with client authentication plus client_id, scope, login_hint, and optionally binding_message and requested_expiry. The body may be JSON or application/x-www-form-urlencoded.

Step 2: cidaas validates the request (tenant CIBA feature, client auth, scopes, user) and creates a unique auth_req_id (transaction ID). The system starts verification on the user's registered authenticator using a completed MFA-relevant method (priority: Face → Touch ID → Pattern).

Step 3: The user receives a notification on their mobile device and reviews the authentication request.

Step 4: The user reviews and approves the authentication request on their mobile device using Face, Touch ID, or Pattern.

Step 5: The requesting device (Smart TV) polls the token endpoint using the auth_req_id at the recommended interval (interval in the initiation response, typically 5 seconds). The application makes a POST call to /token-srv/token with grant_type=urn:openid:params:grant-type:ciba and the auth_req_id. (With ping delivery, wait for the notification instead of polling on an interval, then call the token endpoint once.)

Step 6: Once the user has approved the request, cidaas returns the access tokens to the requesting device. The application will receive a response with access_token, id_token, refresh_token (optional), token_type, and expires_in. When a binding_message was sent in Step 1, that value is carried in both the access token and the ID token claims so your application can verify it matches the message shown to the user.

Step 7: The business app can use the access_token via the authorization header to get a resource.

Step 8: Resource server checks for the authorization token with

  • A: Introspect call to cidaas.

The introspect call is a request made by the resource server to validate the token's authenticity and obtain information about the associated user or client

  • B: Offline check: Valid signature, Expired-Time in the Future.

Step 9: If valid, the resource server responds with the resource.

Note

CIBA requires the tenant CIBA feature to be enabled. Users need the cidaas Authenticator app with at least one completed MFA-relevant verification method (Face, Touch ID, or Pattern). Configure the application in Admin UI with the CIBA grant type (urn:openid:params:grant-type:ciba) and, for ping mode, ciba_config (delivery mode and notification endpoint). The initiation API enforces the tenant feature and client authentication; it does not check that the CIBA grant type is enabled on the app. The token endpoint enforces the grant type when you exchange auth_req_id for tokens.

Technical integration​

APIDescriptionLink to API
Initiate CIBA AuthenticationThis call initiates the CIBA authentication flow and returns an auth_req_id for polling or pingLink to API
Obtain Tokens (poll or after ping)Call with auth_req_id and grant_type=urn:openid:params:grant-type:ciba to retrieve access tokensLink to API

Token endpoint (poll or after ping)​

Use the same client authentication as other token requests. Poll at the interval from the initiation response (typically 5 seconds) until the user completes verification on the authenticator.

Token responseMeaning
authorization_pendingUser has not finished verification yet; wait at least interval seconds and call again.
access_deniedUser rejected or cancelled the request.
invalid_grant / expired token errorsauth_req_id is unknown, expired, already used, or was created by a different client_id.
Success (access_token, id_token, …)User authenticated; use tokens as in other OAuth flows.

The token endpoint requires the CIBA grant type (urn:openid:params:grant-type:ciba) to be enabled on the application. See the CIBA examples on Generate Token.

Example Request​

Initiate CIBA Authentication (JSON + Basic auth):

curl --location '{{domain}}/authz-srv/ciba' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic <base64(client_id:client_secret)>' \
--data '{
"client_id": "your_client_id",
"scope": "openid profile email",
"login_hint": "[email protected]",
"binding_message": "Login to Smart TV",
"requested_expiry": 120
}'

Initiate CIBA Authentication (form-urlencoded + client_secret_post):

curl --location '{{domain}}/authz-srv/ciba' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=your_client_id' \
--data-urlencode 'client_secret=your_client_secret' \
--data-urlencode 'scope=openid profile email' \
--data-urlencode '[email protected]' \
--data-urlencode 'binding_message=Login to Smart TV' \
--data-urlencode 'requested_expiry=120'

Initiate CIBA Authentication (ping mode — include notification token):

curl --location '{{domain}}/authz-srv/ciba' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic <base64(client_id:client_secret)>' \
--data '{
"client_id": "your_client_id",
"scope": "openid profile email",
"login_hint": "[email protected]",
"binding_message": "Login to Smart TV",
"client_notification_token": "your_high_entropy_bearer_token",
"requested_expiry": 120
}'

Response:

{
"auth_req_id": "331be2c8-f664-4d49-a8a6-764fea6a53e3",
"expires_in": 120,
"interval": 5
}

Poll for Tokens:

curl --location '{{domain}}/token-srv/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Authorization: Basic <base64(client_id:client_secret)>' \
--data-urlencode 'grant_type=urn:openid:params:grant-type:ciba' \
--data-urlencode 'auth_req_id=331be2c8-f664-4d49-a8a6-764fea6a53e3' \
--data-urlencode 'client_id=your_client_id'

Response (when pending):

{
"error": "authorization_pending",
"error_description": "The authorization request is still pending"
}

Response (when approved):

{
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"id_token": "eyJhbGciOiJSUzI1NiIs...",
"refresh_token": "def50200...",
"token_type": "Bearer",
"expires_in": 3600
}

The JWT access token and ID token include the binding_message claim when it was provided on the CIBA request (for example "Login to Smart TV"). Decode the tokens (or use token introspection) to read it. The claim is approval-scoped and does not appear on tokens issued via later refresh.

info
Need Support?

Please contact us directly on our support page or reach out to cidaas support at [email protected].