1. Introduction
itsme® is a trusted identity provider allowing partners to use verified identities for authentication and authorization on web desktop, mobile web or mobile applications.
The objective of this document is to provide all the information needed to integrate the Identification service using the OpenID Connect Core 1.0 specifications.
2. Prerequisite
Before you start integrating itsme®, you MUST create an organisation on the following url: https://partner-support.itsme.be/hc/en-us/requests/new?ticket_form_id=360004640194.
Once there, you will need to fill out a basic form with the following questions:
- Contact details such as your email, name, phone number.
- Organisation details as shown on the company register for your jurisdiction.
- Information about the project you want to set-up and the use case you have in mind.
- itsme® terms and conditions. If you require a copy of this please contact onboarding@itsme.be.
Our onboarding team will review your project and get in touch within 3 days with a "client_id" and a "service_code" which need to be added in your configuration. Meanwhile, this should not prevent you from starting your integration.
3. Integration guide
Our itsme® app can be seamlessly be integrated with your web desktop, mobile web or mobile application so you can perform secure identity checks.
Technical overview
itsme® integration is based on the Authorization Code Flow of OpenID Connect 1.0. The Authorization Code Flow goes through the steps as defined in OpenID Connect Core Authorization Code Flow Steps, depicted in the following diagram:
How it works
- The User indicates on your end he wishes to authenticate with itsme®
- Your web desktop, mobile web or mobile application (aka 'Relying Party' in the OpenID Connect specification) sends a request to itsme® (aka 'OpenID Provider' in the OpenID Connect specification) to authenticate the User. This request will redirect the User to the itsme® Front-End. itsme® then authenticates the User by asking him
- to enter his phone number on the itsme® OpenID web page
- authorize the release of some information’s to your application
- to provide his credentials (itsme® code or fingerprint or FaceID)
- Once the User has authorized the request and has been authenticated, itsme® will return an Authorization Code to the Service Provider Front-End, redirecting the user to your mobile or web application.
- The Service Provider Back-End calls the itsme® Token Endpoint and exchanges the Authorization Code for an ID Token identifying the User and an Access Token.
- The Service Provider Back-End MAY request the additional User information from the itsme® userInfo Endpoint by presenting the Access Token obtained in the previous step.
- At this stage you are able to confirm the success of the operation and display a success message.
If a user doesn't have the itsme® app, they'll be redirected to a mobile website with more information and download links.
3.1. Check itsme® OpenID Provider configuration
To simplify implementations and increase flexibility, OpenID Connect allows the use of a Discovery Document, a JSON document containing key-value pairs which provide details about itsme® configuration, such as the URIs of the
- Authorization, Token and userInfo Endpoints
- supported claims
- JWKSet URL
- ...
The Discovery document for itsme® can be retrieved from:
Environment | URL |
---|---|
SANDBOX | https://idp.e2e.itsme.services/v2/.well-known/openid-configuration |
PRODUCTION | https://idp.prd.itsme.services/v2/.well-known/openid-configuration |
3.2. Create a itsme® button on your application
First, you will need to create a button to allow your users to authenticate with itsme®. See the Button design guide before you start the integration.
Upon clicking this button, we will open a modal view which contains a field that need to be filled by the end user with it’s phone number. Note that mobile web users will skip the phone number step, as they use the itsme® mobile app directly to authenticate.
3.3. Crafting your client authentication method
Some itsme® endpoints require client authentication in order to protect entitlement information between interested parties.
The OpenID Connect Core specifications support multiple authentication methods, but itsme® only supports "private_key_jwt" : it requires that each party exposes its public keys as a simple JWK Set document on a URI accessible to all, and keep its private set for itself. For itsme®, this URI can be retrieved from the itsme® Discovery document, using the "jwks_uri" key.
Your private and public keys can be generated via Yeoman. To get started, install Yeoman and generator-itsme with NPM:
$ npm install -g yo generator-itsme
After installation, run the generator:
$ yo itsme
3.4. Build an Authentication Request and request attributes
Composing your base URL
First, you will forg a HTTPS GET request that MUST be sent to the itsme® Authorization Endpoint. The itsme® Authorization Endpoint can be retrieved from the itsme® Discovery document, using the key "authorization_endpoint".
The OpenID Connect Core specification defines a number of parameters to integrate in the HTTPS GET query string :
Parameter | Required | Description |
---|---|---|
client_id | Required | This is the client ID you received after sharing your organisation details with us. |
response_type | Required | This defines the processing flow to be used when forming the response. Because itsme® uses the Authorization Code Flow as described above, this value MUST be "code". |
scope | Required | The scope parameter allows the application to express the desired scope of the access request. It MUST contain the value "openid" and "service:TEST_code", by replacing "TEST_code" with the service code you received when registering your project in the itsme® B2B portal. You MAY also specify additional scopes, separated by spaces, to request more information about the User. See the list below for more information. An HTTP ERROR "not_implemented" will be returned if the required values are not specified. Unrecognised values will be ignored. |
redirect_uri | Required | This is the URI to which the authentication response will be sent. The Redirection URI MUST use the "https" scheme. The Redirection URI MAY NOT use the "http" or an alternate scheme, such as one that is intended to identify a callback into a native application. Note :
|
state | Strongly RECOMMENDED | An opaque value used in the Authentication Request, which will be returned unchanged in the Authorization Code. This parameter SHOULD be used for preventing cross-site request forgery (XRSF). When deciding how to implement this, one suggestion is to use a private key together with some easily verifiable variables, for example, your client ID and a session cookie, to compute a hashed value. This will result in a byte value that will be infeasibility difficult to guess without the private key. After computing such an HMAC, base-64 encode it and pass it to the Authorization Server as "state" parameter. Another suggestion is to hash the current date and time. This requires your application to save the time of transmission in order to verify it or to allow a sliding period of validity. |
nonce | Strongly RECOMMENDED | A string value used to associate a session with an ID Token, and to mitigate replay attacks. The value is passed through unmodified from the Authentication Request to the ID Token. Sufficient entropy MUST be present in the "nonce" values used to prevent attackers from guessing values. See OpenID Connect Core specifications for more information. |
display | Optional | ASCII string value that specifies how the Authorization Server displays the authentication and consent User interface pages to the User. MUST be "page" if provided. Other values will yield an HTTP ERROR "not_implemented". |
prompt | Optional | Space delimited, case sensitive list of ASCII string values that specifies whether the Authorization Server prompts the User for reauthentication and consent. MUST be "consent" if provided. |
ui_locales | Optional | User's preferred languages and scripts for the User interface (e.g.: OpenID web page). Supported values are: "fr", "nl", "en" and "de". Any other value will be ignored. |
acr_values | Optional | Space-separated string that specifies the acr values that the Authorization Server is being requested to use for processing this Authentication Request, with the values appearing in order of preference. 2 values are supported:
|
max_age | Not supported | Any supplied value will be ignored. As itsme® does not maintain a session mechanism, an active authentication is always required. |
response_mode | Not supported | Any supplied value will be ignored. |
id_token_hint | Not supported | Any supplied value will be ignored. |
claims_locales | Not supported | Any supplied value will be ignored. |
registration | Not supported | Any supplied value will be ignored. |
claims | Optional | This parameter is used to request specific claims. The value is a JSON object listing the requested claims. See the list below for more information. |
request_uri | Optional | This parameter enables OpenID Connect parameters to be passed by reference. The "request_uri" value is a URL using the https scheme referencing a resource containing a Request Object value, which is a JWT containing the request parameters. When the "request_uri" parameter is used, the OpenID Connect request parameter values contained in the referenced JWT supersede those passed using the OAuth 2.0 request syntax. The following validations should be done when using the "request_uri" parameter:
Don't forget to send share this URI by email to onboarding@itsme.be and we’ll make sure to complete the configuration for you in no time! If the "request" parameters is used, this parameter MUST NOT be used in the same request. |
request | Optional | If the "request_uri" parameters is used, this parameter MUST NOT be used in the same request. |
The following is a non-normative example of a request that would be sent to the Authorization Server :
GET ${baseUrl}/v2/authorization
&response_type=code
&client_id=MY_PARTNER_CODE
&scope=openid service:TEST_code profile email
&redirect_uri=https://test.istme.be
&request_uri=https://test.istme.be:443/p/test
&acr_values=http://itsme.services/V2/claim/acr_basic
&nonce=A_VALID_NONCE
With some parameters passed as a JWT in the "request_uri", before base64url encoding, signing and encrypting :
{
"response_type":"code",
"client_id":"MY_PARTNER_CODE",
"scope": "openid service:TEST_code profile email",
"redirect_uri": "https://test.istme.be",
"state":"A_VALID_STATE",
"aud": "${baseUrl}/v2/authorization",
"iss":"MY_PARTNER_CODE",
"claims":{
"userinfo":{
"http://itsme.services/V2/claim/BEeidSN":null,
"http://itsme.services/v2/claim/place_of_birth":null
}
}
}
Requesting claims about the User and the Authentication event
The OpenID Connect Core specification defines a sets of claims that MAY be requested via the "scope" and/or "claims" request parameter.
Below, you will find the list of claims that MAY be requested via the "scope" request parameter :
Value | Returned claim | Remarks | Example |
---|---|---|---|
profile | family_name | Smith | |
given_name | For BE citizen, we do share the two complete first names and the intimal of the third name if any. For other ID templates this might differ. |
John Matthew A | |
name | John Matthew A Smith | ||
gender | male | ||
birthdate | 1959-06-03 | ||
Rule for email validity are the following: [a-zA-Z0-9][-_\w.+]{0,30}@([-\w+]{1,30}[.]){1,4}[a-zA-Z]{2,12} Max length: 255 |
john.smith@company.lu | ||
email_verified | false | ||
phone | phone_number | This attribute is stored as an object with 2 fields in our database:
|
+32 495162995 |
phone_number_verified | Supported values are "true" or "false".But, it is always "true" as we perform a SMS OTP verification during the enrollment. | true | |
address | formatted | Place Victor Horta 79, 1348 Louvain-la-Neuve BE | |
street_address | Place Victor Horta 79 | ||
postal_code | 1348 | ||
locality | Louvain-la-Neuve | ||
country | BE |
Typically, the values returned via the "scope" parameter only contain claims about the identity of the User. Via the "claims" parameter you MAY request the same claims as in the ones available via the "scope" request parameter, as well as information about the specific ID documents, the device and the app version used by the user. These claims are specified below :
Value | Returned claim | Remarks | Example |
---|---|---|---|
name | name | John Matthew A Smith | |
given_name | given_name | For BE citizen, we do share the two complete first names and the intimal of the third name if any. For other ID templates this might differ. |
John Matthew A |
family_name | family_name | Smith | |
birthdate | birthdate | 1959-06-03 | |
http://itsme.services/v2/ claim/birthdate_as_string | http://itsme.services/v2/ claim/birthdate_as_string | 10 MAY 1988 | |
gender | gender | male | |
Rule for email validity are the following: [a-zA-Z0-9][-_\w.+]{0,30}@([-\w+]{1,30}[.]){1,4}[a-zA-Z]{2,12} Max length: 255 |
john.smith@company.lu | ||
email_verified | email_verified | false | |
phone_number | phone_number | This attribute is stored as an object with 2 fields in our database:
|
+32 428656565 |
phone_number_verified | phone_number_verifie | Supported values are "true" or "false".But, it is always "true" as we perform a SMS OTP verification during the enrollment. | true |
address | formatted | Place Victor Horta 79, 1348 Louvain-la-Neuve BE | |
street_address | Place Victor Horta 79 | ||
postal_code | 1348 | ||
locality | Louvain-la-Neuve | ||
country | BE | ||
http://itsme.services/v2/ claim/claim_citizenship | http://itsme.services/v2/ claim/claim_citizenship | Belg | |
http://itsme.services/v2/ claim/place_of_birth | formatted | bruxelles Belgium | |
city | bruxelles | ||
country | BE | ||
http://itsme.services/v2/ claim/physical_person_photo | http://itsme.services/v2/ claim/physical_person_photo | /9j/4AA[...]n | |
http://itsme.services/v2/ claim/BEeidSn | http://itsme.services/v2/ claim/BEeidSn | 12 digits in the form xxx-xxxxxxx-yy. The check-number yy is the remainder of the division of xxxxxxxxxx by 97 | xxx-xxxxxxx-yy |
http://itsme.services/v2/ claim/BENationalNumber | http://itsme.services/v2/ claim/BENationalNumber | The value has 11 digits. | 88041827591 |
http://itsme.services/v2/ claim/claim_nl_bsn | http://itsme.services/v2/ claim/claim_nl_bsn | Returns the citizen service number, a unique registration number for everyone who lives in the Netherlands. This number consists of 8 to 9 digits. | |
http://itsme.services/v2/ claim/claim_device | os | ||
appName | |||
appRelease | |||
deviceLabel | |||
debugEnabled | |||
deviceID | |||
osRelease | |||
manufacturer | |||
hasSimEnabled | |||
deviceLockLevel | |||
smsEnabled | |||
rooted | |||
imei | |||
deviceModel | |||
sdkRelease | |||
http://itsme.services/v2/ claim/transaction_info | securityLevel | It tells you whether or not the SIM was successfully contacted during the transaction. The returned values could be "SOFT_ONLY", "SIM_ONLY" or "SIM_AND_SOFT". No value is returned for the moment. |
|
bindLevel | It tells you if the User account is bound to a SIM card or not, at the time the transaction occurred. The returned values could be "SOFT_ONLY", "SIM_ONLY" or "SIM_AND_SOFT". No value is returned for the moment. |
||
appRelease | The Mobile Country Code. The returned value is an Integer (three digits) representing the mobile network country. itsme(r) does not possess this information for every account. No value is returned for the moment. |
3.5. Capturing an Authorization Code
Capturing a successful Authorization Code
If the User is successfully authenticated and authorizes access to the data requested, itsme® will return an Authorization Code to your server component. This is achieved by returning an Authentication Response, which is a HTTP 302 redirect request to the "redirect_uri" specified previously in the Authentication Request. The following is a non-normative example of a successful Authentication Response:
HTTP/1.1 302 Found
Location: https://client.example.org/cb?
code=SplxlOBeZQQYbYS6WxSbIA&
state=af0ifjsldkj
The response will contain:
Values | Returned | Description |
---|---|---|
code | Always | The "code" parameter holds the Authorization Code which is a string value. The content of Authorization Code is opaque for you. This code has a lifetime of 3 minutes. |
state | If requested | The "state" parameter will be returned if you provided a value in the Authentication Request. You should validate that the value returned matches the one supplied in the Authentication Request. The state value can additionally be used to mitigate against XSRF attacks by cryptographically binding the value of this parameter with a browser cookie. If a wrong/unknown "state" is received, you should take it into account and refuse the related "code" or from a security detection/prevention point of view, monitor if it is a recurring pattern or not. |
Handling Authentication Error Response
If the request fails due to a missing, invalid, or mismatching redirection URI, or if the client identifier is missing or invalid, the Authorization Server SHOULD inform the User of the error and MUST NOT automatically redirect him to the invalid redirection URI.
If the User denies the Authentication Request or if the request fails for reasons other than a missing or invalid redirection URI, itsme® will return an error response to your application. As for a successful response this is achieved by returning a HTTPS 302 redirect request to the redirection_uri specified in the Authentication Request. The error response parameters are the following:
Values | Returned | Description |
---|---|---|
error | Always | Error type. |
error_description | Optional | Indicating the nature of the error. |
state | If requested | Set to the value defined in the Authorisation Request, if any. |
The following is a non-normative example of an error response:
HTTP/1.1 302 Found
Location: https://client.example.org/cb?
error=invalid_request
&error_description=Unsupported%20response_type%20value
&state=af0ifjsldkj
The following table describes the various error codes that can be returned in the "error" parameter of the error response:
Error | Description |
---|---|
interaction_required | The Authorization Server requires User interaction of some form to proceed. |
invalid_request_object | The "request" parameter contains an invalid Request Object. |
registration_not_supported | This error is returned because itsme® does not support use of the "registration" parameter. |
All other HTTPS errors unrelated to OpenID Connect Core will be returned to the User using the appropriate HTTPS status code.
3.6. Exchanging the Authorization Code
Once your server component has received an Authorization Code, your server can exchange it for an Access Token and an ID Token.
Your server makes this exchange by sending an HTTPS POST request to the itsme® Token Endpoint URI. This URI can be retrieved from the itsme® Discovery document, using the key "token_endpoint".
The request MUST include the following parameters in the POST body:
Parameter | Required | Description |
---|---|---|
grant_type | Required | This MUST be set to "authorization_code". |
code | Required | The Authorization Code received in response to the Authentication Request. |
redirect_uri | Required | The redirection URI supplied in the original Authentication Request. This is the URL to which you want the User to be redirected after the authorization is complete. |
client_assertion | Required | To ensure that the request is genuine and that the tokens are not returned to a third party, you will be authenticated when making the Token Request. The OpenID Connect Core specifications support multiple authentication methods, but itsme® only supports "private_key_jwt". The JWT Payload in the "client_assertion" parameter MUST be signed then encrypted, with the result being a Nested JWT, as defined in the JSON Web Token (JWT) section. See the JOSE specifications for more information. |
client_assertion_type | Required | This MUST be set to "urn:ietf:params:oauth:client-assertion-type:jwt-bearer". |
The following is a non-normative example of a request to obtain an ID Token and Access Token:
POST /token HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=i1WsRn1uB1
&redirect_uri=https://test.istme.be
&client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer
&client_assertion=PHNhbWxwOl ... ZT
According to the "private_key_jwt" client authentication method, the "client_assertion" contains the following parameters in the JWT Payload:
Parameter | Required | Description |
---|---|---|
iss | Required | The issuer of the "private_key_jwt". This MUST contain the "client_id". This is the client identifier you received after sharing your organisation details with us.. |
sub | Required | The subject of the "private_key_jwt". This MUST contain the "client_id". This is the client identifier you received after sharing your organisation details with us.. |
aud | Required | Value that identifies the Authorization Server as an intended audience. This MUST be the itsme® Token Endpoint URL: "https://idp.prd.itsme.services/v2/token". |
jti | Required | The "jti" (JWT ID) claim provides a unique identifier for the JWT. The identifier value MUST be assigned by the you in a manner that ensures that there is a negligible probability that the same value will be accidentally assigned to a different data object; if the application uses multiple issuers, collisions MUST be prevented among values produced by different issuers as well. The "jti" claim can be used to prevent the JWT from being replayed. The "jti" value is a case-sensitive string. |
exp | Required | The "exp" (expiration time) claim identifies the expiration time on or after which the JWT MUST NOT be accepted for processing. The processing of the "exp" claim requires that the current date/time MUST be before the expiration date/time listed in the "exp" claim. Implementers MAY provide for some small leeway, usually no more than a few minutes, to account for clock skew. Its value is a JSON number representing the number of seconds from 1970-01-01T0:0:0Z as measured in UTC until the date/time. |
3.7. Managing Token Response
Extracting a successful Token Response
If the Token Request has been sucessfully validated we will return an HTTP 200 OK response including ID and Access Tokens as in the example below:
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache
{
"access_token": "SlAV32hkKG",
"token_type": "Bearer",
"expires_in": 3600,
"id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjFlOWdkazcifQ.ewogImlzc
yI6ICJodHRwOi8vc2VydmVyLmV4YW1wbGUuY29tIiwKICJzdWIiOiAiMjQ4Mjg5
NzYxMDAxIiwKICJhdWQiOiAiczZCaGRSa3F0MyIsCiAibm9uY2UiOiAibi0wUzZ
fV3pBMk1qIiwKICJleHAiOiAxMzExMjgxOTcwLAogImlhdCI6IDEzMTEyODA5Nz
AKfQ.ggW8hZ1EuVLuxNuuIJKX_V8a_OMXzR0EHR9R6jgdqrOOF4daGU96Sr_P6q
Jp6IcmD3HP99Obi1PRs-cwh3LO-p146waJ8IhehcwL7F09JdijmBqkvPeB2T9CJ
NqeGpe-gccMg4vfKjkM8FcGvnzZUN4_KSP0aAp1tOJ1zZwgjxqGByKHiOtX7Tpd
QyHE5lcMiKPXfEIQILVq0pc_E2DzL7emopWoaoZTF_m0_N0YzFC6g6EJbOEoRoS
K5hoDalrcvRYLSrQAZZKflyuVCyixEoV9GfNQC3_osjzw2PAithfubEEBLuVVk4
XUVrWOLrLl0nx7RkKU8NXNHq-rvKMzqg"
}
The response body will include the following values:
Values | Returned | Description |
---|---|---|
access_token | Always | The Access Token which may be used to access the userInfo Endpoint. |
token_type | Always | Set to "Bearer". |
id_token | Always | The ID Token is a JSON Web Token (JWT) that contains User profile information (like the User's name, email, and so forth), represented in the form of claims. |
at_hash | Not supported | itsme® does not provide any value for this parameter. |
refresh_token | Not supported | itsme® does not provide any value for this parameter as it only maintains short-lived session to enforce re-authentication. |
With the following values returned in the "id_token":
Values | Returned | Description |
---|---|---|
iss | Always | Identifier of the issuer of the ID Token. |
sub | Always | An identifier for the User, unique among all itsme® accounts and never reused. Use "sub" in the application as the unique-identifier key for the User. It has 36 characters. |
aud | Always | Audience of the ID Token. This will contain the "client_id". This is the client identifier (e.g. : Project ID) you received when registering your project in the itsme® B2B portal. |
exp | Always | Expiration time on or after which the ID Token MUST NOT be accepted for processing. |
iat | Always | The time the ID Token was issued, represented in Unix time (integer seconds). |
auth_time | Always | The time the User authentication occurred, represented in Unix time (integer seconds). |
nonce | If requested | String value used to associate a session with an ID Token, and to mitigate replay attacks. The value is passed through unmodified from the Authentication Request to the ID Token. Sufficient entropy MUST be present in the "nonce" values used to prevent attackers from guessing values. See the OpenID Connect Core specifications for more information. |
acr | If requested | Could be "http://itsme.services/V2/claim/acr_basic" or "http://itsme.services/V2/claim/acr_advanced" depending on the value entered in the "acr_values" Authorisation Request parameter. If no value is provided in the "acr_values" parameter, the "acr" will contain "http://itsme.services/V2/claim/acr_basic". |
amr | Never | |
azp | Never |
However, before being able to store and use the returned values from "id_token", you will first need to validate it by following the the ID Token validation rules described in the section below.
ID Token validation
You MUST validate the ID Token in the Token Response in the following manner:
- As the ID Token is a Nested JWT object, you will have to decrypt and verify it using the keys and algorithms that you specified when registering your project in the itsme® B2B portal. The process of decryption and signature validation is described in on.
If the ID Token is not encrypted, you SHOULD reject it. - The Issuer identifier for itsme® (which is obtained by using the key "issuer" in the itsme® Discovery document) MUST exactly match the value of the "iss" claim.
- You MUST validate that the "aud" claim contains your "client_id" value registered in the itsme® B2B portal. The ID Token MUST be rejected if the ID Token does not list the "client_id" as a valid audience.
- The current time MUST be before the time represented by the "exp" claim.
If all the above verifications are successful, you can use the subject ("sub") of the ID Token as the unique identifier of the corresponding User.
Handling token error response
If the Token Request is invalid or unauthorized an HTTP 400 response will be returned as in the example:
HTTP/1.1 400 Bad Request
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache
{
"error": "invalid_request"
}
The response will contain an error parameter and optionally "error_description" parameter.
3.8. Retrieving User attributes or device/transaction specific claims
Creating the userInfo Request
OpenID Connect Core specifications also allow your application to obtain basic profile information about a specific User in a interoperable way. This is achieved by sending a HTTPS GET request to the itsme® userInfo Endpoint, passing the Access Token value in the Authorization header using the Bearer authentication scheme. The itsme userInfo Endpoint URI can be retrieved from the itsme® Discovery document, using the key "userinfo_endpoint".
GET https://idp.prd.itsme.services/v2/userinfo HTTP/1.1
Authorization: Bearer
Managing the userInfo Response
The itsme® userInfo Endpoint will return a HTTP 200 OK response and the User claims in a Nested JWT format. The following is a non-normative example of a UserInfo Response:
HTTP/1.1 200 OK
Content-Type: application/json
{
"sub": "2i9rk3cg6mkt3v1dn9a1akwr6u4kp1zvj2oo",
"name": "Jane Doe",
"given_name": "Jane",
"family_name": "Doe",
"email": "janedoe@example.com",
"picture": "[base64 encoded picture]"
}
However, before being able to consume the claims from the userInfo response, you will first need to validate it by following the userInfo response validation rules described in the section below.
UserInfo response validation
You MUST validate the userInfo reponse in the following manner:
- As the userInfo response is a Nested JWT object, you will have to decrypt and verify it using the keys and algorithms that the you specified when registering your project in the [itsme® B2B portal](#Onboarding). The process of decryption and signature validation is described in section 4.3 of the JOSE specifications.
If the userInfo response is not encrypted, the you SHOULD reject it. - The "sub" claim will always be included in the response and this should be verified by you to mitigate against token substitution attacks. The "sub" claim in the userInfo response MUST be verified to exactly match the "sub" claim in the "id_token"; if they do not match, the userInfo response values MUST NOT be used.
When an error condition occurs an error response as defined in the OAuth 2.0 Bearer Token Usage specification will be returned.
4. Mapping the User
To sign in successfully in your web desktop, mobile web or mobile application, a given user must be provisioned in OpenID Connect and then mapped to a user account in your database. By default, your application Server will use the subject identifier, or "sub" claim, in the ID Token to identify and verify a user account. Typically, the "sub" claim is a unique string that identifies a given user account. The benefit of using a "sub" claim is that it will not change, even if other user attributes (email, phone number, etc) associated with that account are updated.
The "sub" claim value must be mapped to the corresponding user in your application Server. If you already mapped this "sub" to an account in your application repository, you should start an application session for that User.
If no user record is storing the "sub" claim value, then you should allow the User to associate his new or existing account during the first sign-in session.
All these flows are depicted in the itsme® B2B portal.
In a limited number of cases (e.g. technical issue,…) a user could ask itsme® to ‘delete’ his account. As a result the specific account will be ‘archived’ (for compliancy reasons) and thus also the unique identifier(s) (e.g. "sub"), used to interact with the different Service Providers the specific users is active with, will be automatically deleted in our database.
If the same user would opt to (re)create an itsme® afterwards, he will need to re-bind his itsme® account with your application server (as the initial identifier is no longer valid as explained before). To re-bind his itsme® account one of the above scenario should be used. After successful (re)binding you will need to overwrite the initial reference with the new ‘sub’ claim value in your database.
5. Appendixes
5.1. Universal Links on iOS
{
"applinks": {
"apps": [],
"details": [
{
"appID": “JHGFJHHYX.com.facebook.ios",
"paths": [
"*"
]
}
]
}
}
Integration is going to be pretty straightforward, all details can be found in below steps (as documented on Universal Links official documentation):
- Register your app at developer.apple.com.
- Enable ‘Associated Domains’ on your app identifier.
- Enable ‘Associated Domain’ on in your Xcode project.
- Add the proper domain entitlement and make sure the entitlements file is included at build: Xcode will do it automatically by itself.
- Create the ‘apple-app-site-association’ file (AASA). The AASA file contains a JSON object with a list of apps and the URL paths on the domain that should be included or excluded as Universal Links.
The JSON object will contain:
Parameter | Description |
---|---|
appID | Built by combining your app’s Team ID (it should be retrieved from https://developer.apple.com/account/#/membership/) and the Bundle Identifier. In the example attached, JHGFJHHYX is the Team ID and com.facebook.ios is the Bundle ID. |
paths | Array of strings that specify which paths are included or excluded from association. Note: these strings are case sensitive and that query strings and fragment identifiers are ignored. |
- Upload the ‘apple-app-site-association’ file to your HTTPS web server for the redirection URI communicated in the Authentication Request. The file can be placed at the root of your server or in the .well-known subdirectory.
- Check if the AASA file is valid and is accessible by using the following link.
- Add an entitlement to all redirect URI that the your app need to supports. In Xcode, open the Associated Domains section in the Capabilities tab and add an entry for each Redirect URI that your app supports, prefixed with `applinks`.
To match all subdomains of an associated redirect URI, you can specify a wildcard by prefixing `*.` before the beginning of a specific Redirect URI (the period is required). Redirect URI matching is based on the longest substring in the `applinks` entries. For example, if you specify the entries `applinks:*.mywebsite.com` and `applinks:*.users.mywebsite.com`, matching for the redirect URI `emily.users.mywebsite.com` is performed against the longer `*.users.mywebsite.com` entry. Note that an entry for `*.mywebsite.com` does not match `mywebsite.com` because of the period after the asterisk. To enable matching for both `*.mywebsite.com` and `mywebsite.com`, you need to provide a separate `applinks` entry for each.
- Update the app delegate to respond appropriately when it receives the `NSUserActivity` object. After all above steps are completed perfectly, when the User click a universal link, the app will open up and the method "application:continueUserActivity:restorationHandler" will get called in "Appdelegate". When iOS launches the the app after a User taps a universal link, you receive an "NSUserActivity" object with an "activityType" value of "NSUserActivityTypeBrowsingWeb". The activity object’s "webpageURL" property contains the redirect URI that the user is accessing. The webpage URL property always contains an HTTPS URL, and you can use "NSURLComponents" APIs to manipulate the components of the URL.
For getting the URL parameters, use the function aside.
Also if you want to check if the app had opened by clicking a universal link or not in the `didFinishLaunchingWithOptions` method below.
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([Any]?) -> Void) -> Bool {
print("Continue User Activity called: ")
if userActivity.activityType == NSUserActivityTypeBrowsingWeb {
let url = userActivity.webpageURL!
print(url.absoluteString)
//handle url and open whatever page you want to open.
}
return true
}
//playground code..
var str = “https://google.com/contents/someotherpath?category=series&contentid=1562167825"
let url = URL(string: str)
func queryParameters(from url: URL) -> [String: String] {
let urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false)
var queryParams = String: String
for queryItem: URLQueryItem in (urlComponents?.queryItems)! {
if queryItem.value == nil {
continue
}
queryParams[queryItem.name] = queryItem.value
}
return queryParams
}
// print the url parameters dictionary
print(queryParameters(from: url!))
//It will print [“category”: “series”, “contentid”: “1562167825”]
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
var isUniversalLinkClick: Bool = false
if launchOptions[UIApplicationLaunchOptionsUserActivityDictionaryKey] {
let activityDictionary = launchOptions[UIApplicationLaunchOptionsUserActivityDictionaryKey] as? [AnyHashable: Any] ?? AnyHashable: Any
let activity = activityDictionary[“UIApplicationLaunchOptionsUserActivityKey”] as? NSUserActivity ?? NSUserActivity()
if activity != nil {
isUniversalLinkClick = true
}
}
if isUniversalLinkClick {
// app opened via clicking a universal link.
} else {
// set the initial viewcontroller
}
return true
}
5.2. App Links on Android
The App Links Assistant in Android Studio can help you create intent filters in your manifest and map existing URLs from your website to activities in your app. Follow below steps to configure the App links (as documented on App Links official documentation):
- Add the intent filters to your manifest. Go through the your manifest and select Tools > App Links Assistant. Click Open URL Mapping Editor and then click Add at the bottom of the URL Mapping list to add a new URL mapping.
- Add details for the new URL mapping:
- Entering your redirect URI in the "host" field.
- Add a "path", "pathPrefix", or "pathPattern" for the redirect URIs you want to map. For example, if you have a recipe-sharing app, with all the recipes available in the same activity, and your corresponding website's recipes are all in the same "/recipe directory", use "pathPrefix" and enter "/recipe". This way, the redirect URI http://www.recipe-app.com/recipe/grilled-potato-salad maps to the activity you select in the following step.
- Select the Activity the redirect URI should take Users to.
- Click OK.
- The App Links Assistant adds intent filters based on your URL mapping to the "AndroidManifest.xml" file, and highlights it in the "Preview" field. If the you would like to make any changes, click Open "AndroidManifest.xml" to edit the intent filter.
- To verify the URL mapping works properly, enter a URL in the Check URL Mapping field and click Check Mapping. If it's working correctly, the success message shows that the URL entered maps to the activity you selected.
- Handle incoming links. Once you have verified that the URL mapping is working correctly, you MUST add the logic to handle the intent he created.
- Click Select Activity from the App Links Assistant.
- Select an activity from the list and click Insert Code.
The App Links Assistant adds code to the activity's Java file, similar to the one aside.
However, this code isn't complete on its own. You MUST now take an action based on the URI in, such as display the corresponding content. For example, for the recipe-sharing app, the code might look like the sample aside.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
handleIntent(getIntent());
}
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
handleIntent(intent);
}
private void handleIntent(Intent intent) {
String appLinkAction = intent.getAction();
Uri appLinkData = intent.getData();
if (Intent.ACTION_VIEW.equals(appLinkAction) && appLinkData != null){
String recipeId = appLinkData.getLastPathSegment();
Uri appData = Uri.parse("content://com.recipe_app/recipe/").buildUpon()
.appendPath(recipeId).build();
showRecipe(appData);
}
}
- Associate the app with the redirect URI. After setting up URL support for your app, the App Links Assistant generates a Digital Asset Links file you can use to associate his website with your app. As an alternative to using the Digital Asset Links file, you can associate your site and app in Search Console. To associate the app and the website using the App Links Assistant, click Open the Digital Asset Links File Generator from the App Links Assistant:
- Enter your Site domain and Application ID.
- To include support in your Digital Asset Links file for Smart Lock for Passwords, select Support sharing credentials between the app and the website and enter your site's login URL. This adds the following string to your Digital Asset Links file declaring that your app and website share sign-in credentials: "delegate_permission/common.get_login_creds".
- Specify the signing config or select a keystore file. Make sure to select the right config or keystore file for either the release build or debug build of your app. If you want to set up his production build, use the release config. If you want to test his build, use the debug config.
- Click "Generate Digital Asset Links" file.
- Once Android Studio generates the file, click "Save file" to download it.
- Upload the "assetlinks.json" file to redirect URI site, with read-access for everyone, at "https://
/.well-known/assetlinks.json" . - Click "Link and Verify" to confirm that you've uploaded the correct Digital Asset Links file to the correct location.