Criipto Verify is integrated through the authentcation API which follows the OpenID Connect and OAuth2 specifications.
Criipto Verify supports the OAuth2 authorization code flow, the PKCE flow and the (obsolete) implicit flow as described below. The code flow is used for traditional, server based, web applications which can keep a secret and are able to make back-channel calls to the Criipto Verify service. The PKCE (pronounced pixy) flow can be used by public clients such as single page applications, SPAs, and native applications that cannot keep a secret. Support for the traditional implicit flow is being discontinued, although it will continue to function on test domains for the foreseable future for simpler debugging during development.
The following describes the two flows and introduces the parameters to configure the authentication and subsequent user information retrieval.
Please beware that you don't have to go through the below motions manually. Most often it will be handled by configuring an OpenID Connect package on your platform of choice.
To begin the login flow, you will need to authenticate the user at the identity source indicated in your request.
To authenticate the user, your app must send the user to the OAuth2 authorization endpoint with the appropriate set of parameters.
You can find the URL for the OAuth2 authorization endpoint in the OpenID Connect Discovery Document exposed on your Criipto Verify Domain:
The response from this endpoint is a JSON document, with an
authorization_endpoint property. The corresponding property value is the URL of the OAuth2 authorization endpoint.
The following initiates the authentication through an OAuth2 authorization request:
GET https://YOUR_SUBDOMAIN.criipto.id/oauth2/authorize? response_type=code|id_token& client_id=CLIENT_ID& redirect_uri=YOUR_RETURN_URL& acr_values=CHOSEN_IDENTITY_SERVICE& scope=openid& state=YOUR_STATE
Note that providing
response_type=code specifies that you want either the traditional back-channel authorization code flow or the PKCE flow. If you specify
response_type=id_token you indicate that you want the implicit flow. In the implicit flow you receive the issued token in a query parameter on the return URL.
If you want to receive the response in another way you must specify the
response_mode parameter, see below.
|Denotes the kind of credential that Criipto will return (|
|Your application's Client ID. You can find this value in the Criipto Verify UI in the settings for actual application.|
|The URL to which Criipto will redirect the browser after authentication has been completed. The authorization code and the |
Warning: Per the OAuth 2.0 Specification, Criipto removes everything after the hash and does not honor any fragments.
|For applications configured with a |
For applications configured with a
You can read more about this parameter here
|Identifies which e-ID identity service you want to use. You can only specify one value, and it must identify the exact type of identity service, as some countries have, for example, both a mobile and web based service. Possible values can be found in the authorize request builder.|
|(optional) Specifies how you want your result delivered via the |
Default values are
|(optional but recommended) An opaque arbitrary alphanumeric string your app adds to the initial request that Criipto includes when redirecting back to your application.|
|(optional) Various use cases leverage this parameter. You can read more about them here.|
As an example, your HTML snippet for your authorization URL when adding login to your app might look like:
<a href="https://acme-corp.criipto.id/oauth2/authorize? response_type=id_token& client_id=urn:debug:jwt.io& acr_values=urn:grn:authn:no:bankid& redirect_uri=https://jwt.io& scope=openid& state=etats"> Sign in with Norwegian BankID </a>
For more about how to handle the implicit flow, see below.
For the code flow, when you used
response_type=code, you will receive an
HTTP 302 response which redirects your browser to your specified
redirect_uri with the authorization code included at the end of the URL:
HTTP/1.1 302 Found Location: YOUR_RETURN_URL?code=AUTHORIZATION_CODE&state=YOUR_STATE
For the code flow you will need to exchange the returned code for an actual token. This is done by posting the authorization code received from the previous step to the token endpoint.
For PKCE-enabled clients, this exchange is based on a one-time secret created by the OIDC library you use to handle the flow, and the exchange will also be handled by the same library.
For traditional back-channel flows, note that you must use a HTML-form-style HTTP POST here, and preferably send the credentials in the
Authorization HTTP header. You must also x-www-form-urlencode the values of the
CLIENT_SECRET, respectively, before constructing the
Authorization header in
HTTP POST https://YOUR_SUBDOMAIN.criipto.id/oauth2/token Content-Type: application/x-www-form-urlencoded Authorization: Basic <BASE64(xWwwFormUrlEncode(CLIENT_ID):xWwwFormUrlEncode(CLIENT_SECRET))> grant_type=authorization_code&code=AUTHORIZATION_CODE&client_id=CLIENT_ID&redirect_uri=YOUR_RETURN_URL
Note We do also support receiving the client credentials in the payload, but this usage is discouraged by the OAuth2 specification, and we strongly recommend that you send the credentials in the
Authorization: Basic ... HTTP header value as described above.
The client id and secret are retrieved from the Criipto Verify management UI and the
redirect_uri must be exactly the same you used in the authorization request in the previous step.
Note that the back-channel exchange of the authorization code requires the use of the client secret, which is basically just a password, and therefore must always be made via a back-channel - server to server - and never from a public client like a browser or native appliction. Never include the secret in the frontend code.
For PKCE-enabled clients, the secret is generated on-the-fly, and no special handling of it is required by you.
In the implicit flow, when you asked for
response_type=id_token, the token is returned directly to the application on a URL query parameter. If you are building a Single-Page Application, you can specify
response_mode=fragment to get the
id_token returned on the
# part of the URL. This will ensure that the
You can now proceed with validating the returned
JWT and access the contained end-user information. The validation step is required - if you do not validate the signature, you cannot trust the contained end-user information. We strongly recommend that you find a battle-hardened library for you specific platfrom to do this heavy lifting. The sample applications you can find here all adhere to this recommendation. If we do not have a sample for your particular technology stack, you can find an extensive list of libraries on jwt.io (scroll down to the
Libraries for Token Signing/Verification section).
You can use the
scope query parameter to specify which user data you want on a per-authorize request basis.
You must explicitly enable this feature per application.
By default, Criipto Verify uses the configured settings per e-ID (thus effectively ignoring any other
scope values than
Activate the "Enable dynamic scopes" toggle on an application to start using this feature.
Once you do that, Criipto Verify will switch from using the per e-ID configured scope options to the ones you specify in the authorize request.
scope query parameter can contain multiple values. Each value is separated by a single blank character (
' ' / ASCII
32 / Unicode
scope value must always contain the value
openid, and it may also contain any of the following additional values:
You can see which values are supported for the various e-IDs in the authorize URL builder or in the individual e-ID articles.
The quirks-mode variant of sending the same instructions via the
login_hint is fully supported.
Consult the authorize URL builder for details.
Just as for the
scope parameter, the
login_hint parameter can contain multiple values. Each value here must also separated by a single blank character.
Criipto Verify supports controlling the runtime behavior in quite a few aspects by values sent in this parameter. We chose this approach as it is most often possible to send them through intermediaries if your architecture has such components (other OpenID Providers such as Azure AD or Auth0).
Also, we use it as a fallback for cases where intermediaries do not let you pass values via otherwise standardized OpenID Connect query parameters (most notably
Go to these specific use cases where
login_hint is used to specify behaviour or get around limitations:
For DK and the SE another-device flows, you can add the following values to the
login_hint query parameter to change the default wording used during login/signing.
action:login(the default, mostly present for completeness)
action:approve will change "Login at ..." worded elements to "Approve at ...".
Note that specifically for Danish MitID, you may also send a base64-url-encoded message via
message:<BASE64-URL ENCODED TEXT>, which will be shown to the end user in the MitID app.
For example, if you want to show a Transfer EUR 100 to IBAN DK123456781234 message to the user, add a
message:VHJhbnNmZXIgRVVSIDEwMCB0byBJQkFOIERLMTIzNDU2NzgxMjM0 value to the