Skip to main content
To use Client-Initiated Backchannel Authentication (CIBA) features, you must have an Enterprise Plan or an appropriate add-on. Refer to Auth0 Pricing for details.
When you use email notifications with CIBA, the user receives an email with a link that redirects them to authenticate or authorize a request in the browser. When using email notifications with CIBA, the user logs in on the consumption device but completes authentication by clicking a link sent to their verified email address. When the user clicks the verification link, they are redirected to their browser, creating a session that Auth0 uses to track the authentication process and confirm the user’s identity. This session is necessary to bridge the gap between the authentication device, in this case, the browser, and the consumption device, such as a Smart TV. The following diagram explains the end-to-end CIBA with email notifications flow:
The following sections dive step-by-step into how user authentication works with CIBA using email notifications.

Prerequisites

To initiate a CIBA email request using Auth0, you must:

Step 1: Client application initiates a CIBA request

Use the User Search APIs to find the authorizing user for whom you’d like to initiate a CIBA request and obtain their user ID. Once you have a user ID for the authorizing user, use the Authentication API or our SDKs to send a CIBA request to the /bc-authorize endpoint:
  • cURL
  • C#
  • Go
  • Java
curl --location 'https://{yourDomain}.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://{yourDomain}.auth0.com/", "sub": "<USER_ID>" }' \
  --data-urlencode 'scope=<SCOPES>' \
  --data-urlencode 'binding_message=<BINDING_MESSAGE>'
ParametersDescription
tenantTenant name. It can also be a custom domain. If the iss_sub format is used, then the tenant is passed within the iss claim.
client_idClient application identifier.
client_secretClient authentication method used for user authentication with CIBA, such as Client Secret, Private Key JWT, or mTLS Authentication. If you’re using Private Key JWT or mTLS, you don’t need to include the client secret.
scopeMust include openid.

The scope can optionally include offline_access to request a refresh token. However, for one-time authorization of a transaction with the CIBA Flow, a refresh token is not needed and does not have any meaning in this context.
user_idUser ID for the authorizing user that is passed within the login_hint structure. If iss_sub format is used, then the user ID is passed within the sub claim.

The user ID for a federated connection may have a different format.
requested_expiryThe maximum duration, in seconds, for which the CIBA session should be valid. The CIBA flow’s requested expiry is between 1 and 259200 seconds (72 hours), and it defaults to 300 seconds. Include the requested_expiry parameter to set a custom expiry for the CIBA flow.

The requested_expiry parameter helps determine which notification channel CIBA uses:
  • If you set your requested_expiry to a value of 300 or lower in seconds, CIBA uses the mobile push notification channel if enabled. If you have not configured MFA for your tenant, the CIBA request fails.
  • If you set your requested_expiry to a value between 301 to 259200 seconds (72 hours), CIBA uses the email notification channel if enabled.
binding_messageHuman-readable message used to bind the CIBA flow across the authentication and consumption devices. The binding message is required and up to 64 characters. Use only alphanumeric and +-_.,:# characters.
There is a user-specific rate limit where the authorizing user will not be sent more than 5 requests per minute.

Step 2: Auth0 tenant acknowledges the CIBA request

If the Auth0 tenant successfully receives the POST request, you should receive a response containing an auth-req-id that references the request:
{
    "auth_req_id": "eyJh...",
    "expires_in": 300,
    "interval": 5
}
The auth_req_id value is passed to the /token endpoint to poll for the completion of the CIBA flow.

Step 3: Client application polls for a response

Use the Authentication API or our SDKs to call the /token endpoint using the urn:openid:params:grant-type:ciba grant type and the auth_req_id you received from the /bc-authorize endpoint:
  • cURL
  • C#
  • Go
  • Java
curl --location 'https://{yourDomain}.auth0.com/oauth/token' \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'client_id=<CLIEND_ID>' \
  --data-urlencode 'client_secret=<CLIENT_SECRET>' \
  --data-urlencode 'auth_req_id=<AUTH_REQ_ID>' \
  --data-urlencode 'grant_type=urn:openid:params:grant-type:ciba'
Until the authorizing user approves the transaction, you should receive the following response:
{
    "error": "authorization_pending",
    "error_description": "The end-user authorization is pending"
}
There is approximately a five-second wait interval for polling. If you poll too frequently, you will receive the following response, where the description varies depending on the backoff interval:
{
"error": "slow_down",
"error_description": "You are polling faster than allowed. Try again in 10 seconds."
"interval": 10
}
To resolve the error, wait until the next interval (in seconds) to poll the /token endpoint. The Auth0 Authorization Server uses the login_hint, which contains the user ID for the authorizing user, to initiate user authentication on the authentication device:
  • The Auth0 Authorization Server sends an email to the user’s verified email address.
  • The email contains a verification link that the user must click to authenticate. The binding_message shows up as the request code.
  • The link directs the user to the browser through a request to the /bc-verify endpoint, where the consent query parameter references the CIBA request awaiting consent.
Auth0 sends email to user's verified email address

Step 5: User authenticates in the browser

If no active session is found, the verification link will ask the user to authenticate. The user clicks the link to proceed with user authentication. To authenticate, the user enters their verified email address and password. The user must use the credentials provided to the login_hint parameter sent to the /bc-authorize endpoint when the client application initiates a CIBA request. Otherwise, the user is prompted with an error message and needs to log out and try again.
User authenticates in the browser
Once authenticated, the browser presents the consent details to the user from the Auth0 Consent API, which includes the binding_message, scope, and audience. The scopes are filtered according to your RBAC policy. To learn more, read Role-Based Access Control. The following code sample is an example response from the Auth0 Consent API:
{
  "id": "cns_abc123",
  "requested_details": {
    "audience": "https://$tenant.auth0.com/userinfo",
    "scope": ["openid"],
    "binding_message": "21-49-38"
  },
  "created_at": 1746693720
  "expires_at": 1746693750
}
The user can accept or decline the authentication request at this point.

Step 6: Browser sends the user response back to Auth0

The browser sends the user response back to Auth0. Depending on whether the user accepts or rejects the authentication request, Auth0 displays the following consent screens, which you need to customize by setting the consent prompts:

User accepts the authentication request

User accepts the authentication request

User rejects the authentication request

User accepts the authentication request

Step 7: Auth0 receives user response after the flow completes

The client application completes the polling upon receiving a response from the /token endpoint. A CIBA flow always requires a response, either an approval or decline, from the authorizing user, and existing grants are not checked.

Step 8: Auth0 returns access token to client application

If the user rejects the email request, Auth0 returns an error response like the following to the client application:
{
    "error": "access_denied",
    "error_description": "The end-user denied the authorization request or it has been expired"
}
If the user approves the email request, Auth0 returns an like the following to the client application:
{
    "access_token": "eyJh...",
    "id_token": "eyJh...",
    "expires_in": 86400,
    "scope": "openid",
    "token_type": "Bearer"
}
Note: The refresh_token will only be present if the offline_access scope was included in the initial /bc-authorize request.

Learn more