Iframes support (🚧 private preview)¶
Info
Iframes support is currently in private preview.
Overview¶
While iframes have various security challenges and are not supported for regular BankID, it is part of the 3d secure standard and has become an expectation in ecommerce to preserve context to avoid losing the customer in case of errors.
Providing a dedicated iframes solution is a controlled way of moving user interaction from the iframe to other more secure channels while we balance security and usability concerns along the way.
Steps¶
- Register a client with BankID OIDC
- Get an access token from BankID OIDC
- Get the BankID with Biometrics OIDC configuration
- Register the permission upfront
- Get iframe URL
- Pass permission to redirect flow
- Get the signed permission (optional)
1. Register a client with BankID OIDC¶
If you don't have a client registered with BankID OIDC
yet, you'll need to register one. Follow the instructions
here to register your
application and obtain the necessary client credentials (client_id
and client_secret
).
Info
Ensure that your client has the permissions/client
and permissions/iframe
scope available.
2. Get an access token from BankID OIDC¶
To obtain an access token from OIDC, follow these steps:
-
Call the token endpoint with your client credentials. You can find more detailed information about access tokens in the BankID OIDC documentation.
-
In the scope field, include the following permissions:
openid
,permissions/client
, andpermissions/iframe
. These permissions specify the scope of access granted to the token.
Here’s an example of a valid request:
POST /auth/realms/current/protocol/openid-connect/token HTTP/1.1
Host: auth.current.bankid.no
Content-Type: application/x-www-form-urlencoded
Authorization: Basic <Base64-encoded client id:client secret>
grant_type=client_credentials&scope=openid%20permissions%2Fclient%20permissions%2Fiframe
Make sure to replace the
3. Get the BankID with Biometrics OIDC configuration¶
To ensure seamless integration and avoid hardcoding specific endpoints in you application, follow these steps to dynamically fetch the OpenID Connect configuration:
- Determine the appropriate configuration URL based on the environment:
Environment | Url |
---|---|
Production | https://app.bankid.no/.well-known/openid-configuration |
Current (public test environment) | https://current.aletheia-test.idtech.no/.well-known/openid-configuration |
- Send an HTTP GET request to the respective configuration URL using your preferred programming language or API tool.
- Capture the response which will contain a JSON document with the configuration. By dynamically fetching the OIDC configuration, your application remains flexible, allowing for future changes or updates to the endpoints without requiring modifications to your code.
- To enhance the reliability and performance of your integration, we strongly advise implementing response caching for the OIDC configuration.
4. Register the permission upfront¶
To register a permission, follow these steps:
-
Construct a permission statement. See the permissions API for detailed information of how to construct the different permissions. Encode the permission statement using URL safe Base64 encoding. Below is an example of a permission statement for a payment:
const permissionStatement = { "nonce": "dW5pcXVlIHZhbHVl", // Must be unique "id": "YmFza2V0IGlk", // Your reference "payments": [ { "paymentId": "cGF5bWVudCBpZA", // Your reference "amount": "123.45", "currency": "NOK", "creditorName": "Scrooge McDuck" } ] } // Example implementation of a b64 URL Safe Encoder function b64URLSafeEncode(stringData) { return btoa(stringData) .replace(/\+/g, "-") .replace(/\//g, "_") .replace(/=/g, ""); } b64URLSafeEncode( JSON.stringify( permissionStatement ) ); // -> "eyJub25jZSI6ImRXNXBjWFZsSUhaaGJIVmwiLCJpZCI6IlltRnphMlYwSUdsayIsInBheW1lbnRzIjpbeyJwYXltZW50SWQiOiJjR0Y1YldWdWRDQnBaQSIsImFtb3VudCI6IjEyMy40NSIsImN1cnJlbmN5IjoiTk9LIiwiY3JlZGl0b3JOYW1lIjoiU2Nyb29nZSBNY0R1Y2sifV19"
Note
- The
nonce
must be a unique value for each permission you register. - Use
id
(basket ID) andpaymentId
as references to the payment(s) in your systems. These will not be shown to the end user. - The
amount
is a decimal amount represented as a string and must use the dot as the decimal separator.
-
Send a POST request to the permissions endpoint, providing the access token received in the first step as a bearer token. Include the permission, which is the URL safe Base64 encoding of the permission statement object.
Login hint is optional but highly recommended to simplify user interaction in the iframe.
POST /permissions/v1/ HTTP/1.1 Host: api.current.aletheia-test.idtech.no Content-Type: application/json Authorization: Bearer <access token from step 1> { "type": "payment.v1", "loa": "sub", "iat": 1617091752, "exp": 1617092652, "permission": < URL safe b64 encoded permission statement from step 2a >, "loginHint": [ { "scheme": "nnin", "value": "string" } ] }
Note
iat
and exp
are timestamps in seconds since the UNIX epoch. iat
can be at most 1 minute
into the past. exp
sets the maximum time by which the permission must be granted and should
normally be set just a few minutes into the future.
-
On a successful request, you will receive a response body containing a permission ID, a permission token and a binding message:
{ "id": "1.BY.MEKrA-00GVtmvWOCDYQko_fSg93LO5n2rBnlj-X4MQg.BiDEl_CgfakqahcXjLrFet_GGpEkR_W8D-RK4hORBO0", "permissionToken": "eyJhbGciOiJIUzI1NiIsImtpZCI6IjB5Z3hDX3UzQlpPWXlKZ0Y3eDJ0eWtQaTRCTml2cG9KMDBmYjFzTGliUVUiLCJ0eXAiOiJKV1QifQ.eyJleHAiOjE2MTcwOTU3NDQsImlhdCI6MTYxNzA5MjE0NCwicyI6IjA6LTEjOTIzIiwicCI6IkJpREVsX0NnZmFrcWFoY1hqTHJGZXRfR0dwRWtSX1c4RC1SSzRoT1JCTzAiLCJuYmYiOjE2MTcwOTIxNDh9.39GWvNjNMSKKhKOF4t4HcDnZGNJmLmPT3f612z1VKko", "bindingMessage":"Farlig frakk" }
5. Get iframe URL¶
- Make a POST request to the iframe-authorize endpoint.
- Include the
permissionToken
from step 4 as thelogin_hint_token
in the iframe-authorize endpoint. - In the scope, include
openid permissions/iframe
. - Provide
redirect_url
as the URL to which the user will be redirected after the authentication is completed. - Provide
state
to maintain state between the request and the callback. - Include a list of
frame-ancestors
to specify which domains are allowed to embed the iframe. This is a security measure to prevent clickjacking.
Below is an example of a request to the iframe-authorize endpoint:
POST /iframe-authorize HTTP/1.1
Host: api.current.aletheia-test.idtech.no
Content-Type: application/x-www-form-urlencoded
Authorization: Bearer <access token from step 1>
{
"login_hint_token": "string",
"scope": "openid permissions/iframe",
"state": "string",
"redirect_url": "https://example.com/callback",
"frame_ancestors": [
"https://example.com",
"https://example2.com"
]
}
Note: Replace string with the actual login_hint_token
and state
and provide appropriate values for other fields.
After calling the iframe-authorize endpoint, you will receive the following response:
The iframe-authorize endpoint returns authorize_uri
which you will redirect to in the iframe to start an auth code flow.
6. Pass permission to redirect flow¶
Redirect to authorize_uri
in the iframe to start the auth code flow. The authorize_uri
will redirect to the redirect_url
you provided in the iframe-authorize request.
Event notification to the containing page using postMessage
is planned but not yet specified in detail. The intention is to allow insights into the funnel and to allow the containing page to take action on errors.
7. Get the signed permission (optional)¶
To get the signed permission you can send in a GET request to the permissionId/grant
endpoint. The permissionId
you use is the one that you
got from your permissions POST request. Be aware that it can return a 404 error code
(permission not yet granted) but as mentioned in the api specification you can set up a polling request on the permissionId/grant
endpoint until your initial permission has been signed.
If your permission has been successfully granted you will receive this response:
{
"gv": 1,
"pt": "string",
"type": "string",
"rpId": "bankid-app",
"sv": "2020-10-30@deadbeef",
"iat": 1800000000,
"iss": "string",
"nonce": "string",
"proofKeyId": "string",
"sub": "nnin:010112345",
"permissionId": "string",
"digest": "string"
}
The grant is a JWT token that can be validated as follows:
- In the BankID with Biometrics OIDC configuration (as mentioned here) get the Grant JWK set from the URI pointed to by the
jwks_uri_grants
property in this document. - Check that the JWT token is signed by one of the keys in the Grant JWK set. You can find a suitable library for performing this verification at https://jwt.io/libraries.
- Check that the
nonce
claim inside the token payload is equal to thenonce
in the permission statement created in step 2.