Age Verification using CIBA
Official CIBA docs: https://openid.net/specs/openid-client-initiated-backchannel-authentication-core-1_0.html.
Example CIBA request
The following example demonstrates a standard initialization of an AV flow using our CIBA interface.
curl --location 'https://pp.idbroker.eu/op/connect/ciba' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=urn:openid:params:grant-type:ciba' \
--data-urlencode 'scope=openid av:18' \
--data-urlencode 'client_id=[your-client-id]' \
--data-urlencode 'client_secret=[your-secret]' \
--data-urlencode 'reference_id=[your-reference-id]'
Note that you can use client assertion signed JWTs instead of posting client secret directly - any OIDC/CIBA supported mechanics for client secret is supported.
Example initialization response (poll mode):
{
"auth_req_id": "9384B..-1",
"expires_in": 300,
"interval": 3,
"authentication_uri": "https://pp.idbroker.eu/op/connect/authorize?client_id=b.7&request_uri=urn:ietf:params:oauth:request_uri:4BEE..2",
}
The authentication_uri contain the URL which is used to initiate the end-user flow. This URL can be https:// or av:// (direct EU AV integration) depending on configuration on client - handle this the same way, no matter format. This URL can be converted into a QR code, which allows for cross device initiation and completion via smartphone camera scanning - helper methods for generating QR code is also available.
Initiating the user experience (UX)
After CIBA initialization the received result can be used to setup the desired AV integration. There is a number of options:
- URL based redirect (browser and appswitch)
- Scan of QR code with mobile device
- Browserbased iframe integration
URL based redirect
A flow can always be started by redirecting the user to the authentication_uri. If done via a browserbased interaction with the user ensure to trigger this redirect in a “click event” (user interaction) in order to trigger appswitch handling by the OS, if applicable.
A common way to enable the flow cross device, is to display a QR code. This can be generated by by encoding the authentication_uri response value. It is possible to have the initialization response values include a pre-generated QR code that can be utilized.
Scan of QR code with mobile device
If the setup only supports cross-device QR code scanning, then the flow is setup and restricted to displaying a QR code of the authentication_uri response value. It is possible to have the initialization response values include a pre-generated QR code that can be utilized.
A pre-generated QR code can be requested by setting the qr_code_response initialization parameter, here examplified by setting qr_code_response=png:
Example initialization response with qr_code_response=png:
{
"auth_req_id": "9384B..-1",
"expires_in": 300,
"interval": 3,
"authentication_uri": "https://pp.idbroker.eu/op/connect/authorize?client_id=b.7&request_uri=urn:ietf:params:oauth:request_uri:4BEE..2",
"qr_b64": "iVBORw0KGg...",
}
Browserbased iframe integration
If the flow is initiated inside a browser on a user-controlled device, the iframe variant offers an easy and adaptable integration, which automatically adapts to same-device and cross-device flows and which is more dynamic in nature, as the content of the iframe is rendered by Signaturgruppen Broker. The iframe will inform the parent website when done via Web Messaging, but the result is still returned via the CIBA interface.
The iframe flow is initialized by specifying the flow_type=iframe parameter, which returns the iframe_src parameter in the initialization response:
{
"auth_req_id": "9384B..-1",
"expires_in": 300,
"interval": 3,
"iframe_src": "https://pp.idbroker.eu/op/iframe/av/?client_id=b.7&request_uri=urn:ietf:params:oauth:request_uri:4BEE..2",
}
Age scope(s) (av:age)
The requested age verification, is requested via the scope parameter age:[age]. Requesting a credential proving that the user is 18 or older is done with the age:18 scope value. Multiple age verification credentials can be requested simultaneously, such as setting both age:16 and age:18 in the scope value. This will result both credentials in the result.
Optional initialization parameters
| Name | Description |
|---|---|
| reference_id | Optional but recommended. Use reference_id to bind the AV flow to some internal identifier. The reference_id will be included in the signed ID token. |
| client_notification_token | Required for ping and push modes, see official docs. |
| redirect_uri | Specifies a redirect for the end-user when the flow has completed. Not all AV flows support this, as some wallets might not support redirecting the end-user when done. |
| redirect_state | When a redirect_uri parameter is specified and the end-user is redirected, the redirect_state will be appended as query/post parameter |
| redirect_type | Specifies redirect type. Values: get (default) or post. |
| qr_code_response | Specifies if a pregenerated QR code is returned in the initialization response, default disabled. Values: png or svg. Sets the qr_b64 response value, encoding the QR in specified format as Base64. |
| flow_type | Specifies the flow type, default redirect type authentication uri. Values: authentication_uri (default) and iframe. The iframe option enables the CIBA flow to run inside an iframe, which offers an easy integration for browser-based flows. Redirect+QR type flows is not compatible with iframe based flows. |
CIBA Poll, Ping, and Push Modes
For reference, see the official documentation for response modes here.
The client is default configured for poll mode, but can be set for ping or push mode in the admin UI. Please reach out if you are interested in the ping or push mode.
Example ID token (CIBA)
A successful flow will result in an ID token, which contains the relevant claims issued for the flow.
{
"iss": "https://pp.idbroker.eu/op",
"nbf": 1725009225,
"iat": 1725009225,
"exp": 1725009525,
"aud": "[your client id]",
"reference_id": "[your-reference-id]",
"sub": "[random sub]",
"auth_time": 1725009225,
"idp": "eu_av",
"transaction_id": "90..32",
"idtoken_type": "av",
"av:18": "true"
}