Introduction

It is easy to integrate Truid, and we guarantee a secure and user-friendly authentication process. Truid integration is, as of today, based on OAuth 2.0 and OpenID Connect - but the underlying architecture allows us to add support for additional protocols and standards down the road.

Truid is here mainly to allow users to prove their identity and authenticate themselves towards Services on the Internet. In order to follow these integration guidelines, we need to define the fundamental terms and concepts

  • User: represents the party that need to authenticate themselves - corresponds to OIDC/SAML “End User” and the OAuth “Resource Owner”

  • Client: represents the service to whom the User needs to authenticate - corresponds to OIDC "Relying Party" and the SAML "Service Provider". We use Client here to align with OAuth.

  • Truid: is the system that will allow Users to authenticate at Clients - represents the OAuth "Authorization Server", OIDC "OpenID Provider" and SAML "Identity Provider".

This section does not cover much about how the actual authentication process works. This is technically carried out between the User and Truid.

How To Integrate

Clients integrate Truid over the established standards OAuth 2.0 and OpenID Connect (OIDC). There are a wide selection of libraries and tools to get an OAuth 2.0 integration in place, supporting any language, technology and platform. OIDC adds a simple identity layer on top of the OAuth 2.0.

Truid applies OAuth 2.0 Authorization Code flow for all integrations. This flow allows Clients to have one backend integration with Truid that is close to identical when authentication is triggered by web (i.e. from “other device”) and on app (i.e. on “same device”). Further, it ensures that secrets and sensitive information are transferred over the back channel - to stay secure and respect user privacy.

There are some front-end related differences between when Users requests to authenticate themselves on the same device as where the truid app is installed - and when Users triggers authentication on another device, such as on a web page on their PC.

Service Enrollment

In order for a Service to integrate with Truid, it has to be registered. Currently, the registration process is managed by Truid, self-service support will be available later. It covers the following parts:

  • Customised look-and-feel - in order to show the Service name and logo in the Truid App

  • Identity data - what data to share in which scenario and for what purposes it is needed, see Data

  • Assurance levels - expected assurance levels to require on identity, authenticators and attributes

Specifications:

  • The Service Logo should be a 128x128 pixel sized PNG image

When the service is configured, a client_id and a client_secret is created. The secret must be kept secure, if it is leaked an attacker will be able to use it to access protected resources.

For each function a Service needs to perform, it must also configure a function specific consent template, containing settings such as what data points to request and what flows to activate.

Functions

The main purpose behind enabling a Service for Truid is to authenticate and identify users. Regardless of which function to perform, Truid will always provide a few fundamental features:

  • Authenticating the user, with the assurance level of choice

  • Providing a Unique Persistent Identifier for the subject, that allows a service provider to follow the user over any interactions for any of the connected Services

Truid provides a few different functions, each targeting a specific purpose. These functions can be triggered and realized through different flows, as described in later sections.

User Onboarding to a Service

Many services / service providers have an onboarding process, where they enter an engagement with users, often as customers or members. Truid can manage significant parts of this onboarding flow:

  • Authentication, unique persistent identifier and just-in-time data, as already mentioned.

  • Collecting and presenting the data about the user needed for onboarding, e.g. Name, email-address, phone number

  • Monitoring changes of data for as long as the engagement remains

  • Just-in-time access to all sensitive data - a service provider never needs to store any sensitive data, only an identifier and the tokens used to access the data.

Details

This function is triggered by an OAuth 2.0 Authorization Request to the /oauth2/v1/authorize/confirm-signup endpoint, and results in both an Access Token and a Refresh Token from the OAuth 2.0 Token Response from the /oauth2/v1/token endpoint.

The Access Token can be used to get Claims from for example the /oidc/v1/user-info endpoint. The Refresh Token is used to get a new Access Token upon expiry via the /oauth2/v1/token endpoint.

The service will be granted access to Claims during the lifetime of the engagement.

The Service Backend is supposed to store the returned refresh token in persistent storage and associated with the user. The refresh token can be used to request a new access token when the service performs an operation that requires fetching data from the Truid REST API.

The expiry time of the access token will be quite short, and the service should not store the access token after it has completed processing.

The tokens must be kept secure, if any token is leaked an attacker will be able to use it to access user data.

User Login to a Service

Most services / service providers that need user authentication allow a user to log in, hence stay authenticated as long as the user is present. This is typically represented by a session that terminates based on inactivity or that a user explicitly logs out. Truid can manage major parts of this login flow:

  • Authentication, unique persistent identifier and just-in-time data, as already mentioned.

  • Collecting and presenting the data about the user needed for login

  • Monitoring changes of data for during a session

  • Managing the lifecycle of a session

Details

This function is triggered by a OAuth 2.0 Authorization Request to the /oauth2/v1/authorize/login-session endpoint, and results in both an Access Token and a Refresh Token from the OAuth 2.0 Token Response from the /oauth2/v1/token endpoint.

The Access Token can be used to get Claims from for example the /oidc/v1/user-info endpoint. The Refresh Token is used to get a new Access Token upon expiry via the /oauth2/v1/token endpoint.

A valid access token is also a guarantee that the user is still present and that the session was not hijacked by an attacker, and the Service must always ensure that it holds a valid access token whenever it is performing any action on behalf of the logged in user, even if it does not use the access token in any interaction with the Truid REST API.

The service will be granted access to Claims during the lifetime of the session, until the user is logged out.

The Service Backend is supposed to store the refresh token, the access token, and the access token expiry time, all associated with the user session.

The tokens must be kept secure, if any token is leaked an attacker will be able to use it to access user data.

User needs to verify its Identity

Many services / service providers already have session management and user accounts but need to perform a strong Identity Verification in their process. This could be required during a qualification process (such as KYC), verify the identity of an existing user or as part of a multi-factor login. This flow is a one-time verification without a session that fulfills:

  • Authentication, unique persistent identifier and just-in-time data, as already mentioned.

  • Collecting and presenting the data about the user needed for verification

Details

This function is triggered by a OAuth 2.0 Authorization Request to the /oauth2/v1/authorize/idv endpoint, and results in both an Access Token and a Refresh Token from the OAuth 2.0 Token Response from the /oauth2/v1/token endpoint.

The Access Token can be used to get Claims from for example the /oidc/v1/user-info endpoint. The Refresh Token is used to get a new Access Token upon expiry via the /oauth2/v1/token endpoint.

The service will be granted access to Claims during a limited time, but long enough for the Service to consume and verify the User data, not necessarily directly after completing the flow.

The Service Backend does not need to store the Access Token or Refresh Token if the User Data is consumed directly after completing the flow.

If tokens are stored, the tokens must be kept secure, if any token is leaked an attacker will be able to use it to access user data.

User Signing a Document

Most services / service providers close some kind of agreements with their users, often of a soft nature that doesn’t add any heavy conclusive legal bearing. Some services manage legally binding signatures of documents - where the user has to be verified/authenticated and the actual signature must cryptographically tie the user with the actual signed document. Truid can manage major parts of this signature flow:

  • Authentication and unique persistent identifier, as already mentioned.

  • Collecting and presenting the data about the user that signed

  • Requesting the user to sign the document, displaying a message that identifies the document and any counterparts.

  • Constructing and delivering an Advanced Electronic Signature (AES/JAdES) as signed by the user.

Digital Signatures

A Signature consist of two parts. Authentication (“I am me!”) and Consent (“I agree!”). A signature aims to fulfil three promises:

  • Authenticity protection - A record of who signed

  • Integrity protection - Not possible to tamper with or falsify the signature, also known as sealing

  • Non-repudiation - Not possible to dispute the authorship or the validity of an action

An Electronic Signature is a digital form of a “wet ink signature” which is legally binding but without any requirement to incorporate specific codings or standards. A Digital Signature is a secured e-signature that rely on PKI (public key infrastructure), and an AdES signature is a Digital Signature that follows the AdES standard (ETSI Advanced Electronic Signature).

Truid offers JAdES Digital Signatures, which allows signing arbitrary data as an extension to JWS (JSON Web Signature). JAdES signatures is based on PKI (Public Key Infrastructure), where a payload is cryptographically signed with a private key that later can be verified by anyone in possession of the corresponding public key. An X.509 certificate binds the identity to a public key, and trust is managed through certificate chaining.

  • JWS is a standard by IETF (as part of the JOSE series) based on JWT (JSON Web Token) for signing arbitrary data.

  • JAdES is a standard by ETSI (as part of the AdES series) that extends JWS with additional controls that meet EU/eIDAS regulations

  • X.509 is a standard by ITU-T (as part of the X.500 series) defining the format on public key certificates.

Feature Highlights:

  • AdES Signature Levels: Truid currently supports B-B (Basic Signature).
    Other levels are B-T, B-LT and B-LTA, each being an extension of the previous with the purpose to further strengthen verification, durability and preservation.

  • eIDAS Signature Assurance Levels: Truid currently supports AES (Advanced Electronic Signatures).
    Other assurance levels are QES (Qualified Electronic Signature), which is not supported by Truid yet, and SES (Simple Electronic Signature), which Truid has no intention to deliver.

  • Signature Serialization: Truid currently delivers signatures with Compact Serialization
    Other options like JSON Encoded may be supported in the future.

  • Signature Packaging: Truid currently delivers signatures with Detached payload.
    Other options like Enveloping may be supported in the future.

  • X.509 Certificates: Truid issues a new unique certificate for each signature, used only once and with a very narrow validity period.

  • Personal Data: Truid currently delivers additional data about the subject in a presentation, separated from the signature. The X.509 certificate identifies the subject with a persistent pairwise pseudonymous persistent identifier. This eliminates some privacy concerns regarding how the signature can be handled, stored and distributed.
    The option to include additional personal data in the X.509 certificate may be supported in the future.

Resources:
The following resources are good starting points that in turn references additional relevant standards and guidelines.

Signature Validation

Truid provides JAdES signatures Level B-B (Basic) - it is important that all signatures are validated by the integrated services. There are many aspects of a signature, hence different parts of the signature need their own validation measures and the result of a validation must be interpreted correctly and consistently.

DSS Demonstration WebApp

The European Commission has provided a web-tool, DSS Demonstration WebApp that is capable of validating JAdES signatures on different levels. It is a good tool to use during integration of Truid to ensure that the signatures are correct and compliant end-to-end. Link to DSS

Truid signatures are delivered with detached payload, hence the actual document that the signature belongs to must be explicitly provided to the DSS validation tool. Also, Validation level needs to be “Validation process for Basic Signatures” (Level B-B).

Understanding the Report

This is how an expected validation report for a Truid signature will look like in the DSS Demonstration WebApp

example dss report jades baseline b b

The DSS tool validates with an AdES-QC validation policy, which represents AdES that is based on a qualified certificate. Since Truid signatures are pure AdES (not AdES-QC), the validation report will contain a remark “Unable to build certificate chain up to a trusted list”.

The underlying remark (sub-indication) is NO_CERTIFICATE_CHAIN_FOUND “The certificate chain for signature is not trusted, it does not contain a trust anchor”. This is the cause of the overall remark (indication) INDETERMINATE “The signature/seal is an Indeterminate AdES digital signature”.

Truid provides a valid certificate chain where Truid is the trust anchor, but the DSS tool and the AdES-QC policy requires all trust anchors to be on the EU Trusted List of QTSPs: https://eidas.ec.europa.eu/efda/tl-browser/#/screen/home

In order for the DSS tool to validate with a pure AdES validation policy, the tool has support for uploading additional policies; however there are no officially published policies for pure AdES.

Integration Details

This function is triggered by a OAuth 2.0 Authorization Request to the /oauth2/v1/authorize/sign endpoint, and results in an Access Token and a Refresh Token from the OAuth 2.0 Token Response from the /oauth2/v1/token endpoint.

The Access Token can be used to get Claims from for example the /oidc/v1/user-info endpoint, and to fetch the resulting digital signature from the /exchange/v1/signature endpoint. The Refresh Token is used to get a new Access Token upon expiry via the /oauth2/v1/token endpoint.

The service will be granted access to the Signature and the shared Claims during a session of 30 days.

The Service Backend is supposed to store the returned refresh token in persistent storage and associated with the user. The refresh token can be used to request a new access token when the service performs an operation that requires fetching data from the Truid REST API.

The expiry time of the access token will be quite short, and the service should not store the access token after it has completed processing.

The tokens must be kept secure, if any token is leaked an attacker will be able to use it to access user data.

UX Guidelines

Truid places great value in its trademark being used in a way that protects and preserves trust and reputation.

This guide contains guidelines and requirements that apply for all use of the Truid trademark.

Word mark

The word mark “Truid” must be spelled as one word with an upper case T and ruid in lower case.

The word mark “Truid” must always be displayed in the same font as the surrounding body text.

Never add any prefixes, suffixes or other additions to the word mark “Truid”. It is always just Truid, no variations are allowed.

Logotype

The logo must not be skewed, scaled, cropped, retouched, rotated or otherwise altered in regards to shape, colors or proportions.

The logo must always be displayed with a minimum distance to other graphics, text, images or borders.

There should always be an information-free zone around the logo corresponding to at least 50% of the height of the logo. The purpose of the patch is to display the logo clearly and keep it separate from text, images or other graphic elements.

Black

White

Copy

The text for buttons depends on what function you are implementing, choose what fits your implementation best.

  • Register to a service / onboarding - “Continue with Truid”.

  • Login to a service - “Login with Truid”.

  • Sign a document or transaction - “Sign with Truid”.

Buttons

The Truid service button should always contain a logo (to the left) and text matching the use case. The button should also match surrounding styling such as size and font.

Truid service buttons should be either white, black or Truid theme color, see below examples.

White - button color #FFFFFF, text color #000000.

White

Black - button color #000000, text color #FFFFFF.

Black

Truid theme - button color #3A277F, text color #FFFFFF

Truid

Avoid to style Truid service buttons in wrong color and misusing the Truid word mark.

Dont

ArtWork

Download Logos here.

Session Creation

This section describes the different ways to integrate to Truid, for different types of apps or web pages.

All functions that create any type of session between the Service and the User should use one of these flows to create the session. The initial authorization URL decides which specific function to trigger.

Client App with Backend

Overview

The goal of this integration flow is to give a service backend access to user data from Truid. The user is interacting with the service using an app.

This flow uses the OAuth2 Authorization Code Grant with the PKCE extension to allow the user to authorize the backend to access the Truid API to fetch data about the user.

This flow is used to create a session for both the functions User Onboarding and User Login.

Standards:

Flow

This sequence diagram gives an overview of the flow.

app with backend flow
Legend

    C-N denotes service specific messages

    O-N denotes OAuth2 standard messages

Steps

    C-1: The app is initiating the flow by asking the backend for a URL to use for starting the flow towards Truid.

    C-2: Return authorization URL

    O-3: The app is requesting access from Truid. This request is opening the Truid App which is used for authenticating the user.

    O-4: The Truid App is redirecting back to the app with a code that can be used to get an access token

    C-5: The app is completing the flow by sending the code to the backend

    O-6: The backend is using the code to get an access token from Truid

    O-7: The Truid API is returning an access token

    C-8: The backend is returning a response to the app, confirming that the flow is complete

    O-9: The backend uses the access token to fetch data from the Truid API

    O-10: The Truid API returns data about the user

Integration

This section describes the steps needed to integrate a service with Truid.

1. Configure Service in Truid

Currently, the process of configuring a service in Truid requires contacting the Truid support and ask for a service to be registered. Eventually this process will be replaced with a self-service UI.

For a service to be activated for one of these functions, a function specific consent template must be configured. The information needed to configure a consent template is:

Links:

2. Create endpoint for authorization URL

Add an endpoint in the backend which has the purpose of creating an Authorization Request URL, and redirect the app to this URL. This corresponds to the steps C-1 and C-2 in the flow above. The returned Authorization Request URL will then be used in step O-3 in the flow above.

The Authorization Request URL follows the OAuth2 standard for an Authorization Request. The URL will point to different endpoints in the Truid API depending on which Truid Authorization Flow that should be started.

The Authorization Request URL should contain a scope parameter, which should be the list of Data Points to request access to. The available Data Points are listed here.

To initiate a User Onboarding, the Authorization Request URL should point to https://api.truid.app/oauth2/v1/authorize/confirm-signup, see API Reference.

To initiate a User Login, the Authorization Request URL should point to https://api.truid.app/oauth2/v1/authorize/login-session, see API Reference.

To initiate a Sign Operation, the Authorization Request URL should point to https://api.truid.app/oauth2/v1/authorize/sign, see API Reference.

Notes:

The redirect_uri parameter is where the client will be redirected with an authorization code. This URL must match exactly what is configured in Truid.

The scope parameter must be a subset of the data points that were given when configuring the service in Truid.

The state parameter must be used to prevent cross-site request forgery, see RFC-6749 Section 10.12.

The PKCE extension must be used, see RFC 7636 - Proof Key for Code Exchange by OAuth Public Clients (PKCE). The only supported code challenge method is S256.

Some clients, such as react-native based apps, have problems with manual handling of redirection responses, and in those cases it might make sense to return the authorization URL in a 2xx response instead of 302. See code example.

Example:

https://api.truid.app/oauth2/v1/authorize/confirm-signup?response_type=code&client_id=abcdef&scope=truid.app%2Fdata-point%2Femail&redirect_uri=https%3A%2F%2Fexample.com%2Fcomplete-signup&state=123456&code_challenge=CH12345&code_challenge_method=S256

Links:

3. Fetch authorization URL and redirect to Truid

Start the Authorization Flow from the app, by sending a request to the endpoint created in step 2 and fetch the Authorization Request URL. The app should open this URL, which should trigger the Truid App to be opened. This corresponds to steps C-1, C-2, and O-3 in the flow above.

Links:

4. Add Deep Linking for redirect URI

Once the Truid App has authenticated the user and the user has given consent to share data with the service, the Truid App will redirect back to the app using the redirect URI. This is the URI given in the redirect_uri parameter in the Authorization Request created in step 2, and must match exactly the redirect URI that is configured in step 1. This corresponds to step O-4 in the flow above.

This URI must be an https URL, and the app must be associated with the domain. On Android the URL should work as an Android App Link to open the app, and on iOS it should work as a Universal Link to open the app.

When the app is opened by the redirect URI deep link, it should send a request to the backend endpoint, described in step 5, to complete the authorization process. This corresponds to step C-5 in the flow above. It must pass on all parameters from the received redirect URI. This URI will contain a number of parameters, for example an authorization code that the backend should use to request an access token from the Truid API.

Links:

5. Add endpoint for completing authorization

Add an endpoint for completing the authorization. This corresponds to step C-5 in the flow above.

The service should invoke the Truid API token endpoint to complete the authorization flow, and to exchange the code into an access token and a refresh token. This corresponds to step O-6 and O-7 in the flow above.

The returned access token can be used to request user data from the Truid API.

Notes:

The backend must authenticate the request to identify the logged in user that sent the request. The state parameter can not be used to identify the user, since it could be faked. How the service chooses to authenticate users is up to the service to decide.

The service must verify that the state parameter is correct and matches the logged in user, to prevent cross-site request forgery, see RFC-6749 Section 10.12.

If the user cancels the authorization request, or if there is any other error during the authorization flow, the redirect will contain an error parameter that identifies the error. The service should return a 403 response from this endpoint in that case.

The backend must include the PKCE code verifier in the request to get an access token.

The redirect_uri parameter in the token request must match exactly what is configured in Truid.

The code received in the endpoint has a short expiry, 60 seconds, and the call to exchange the code for an access token need to be done within that time frame.

Examples:

Example authorization response:

GET https://example.com/complete-signup?code=XYZ&state=123

Example authorization response when user declined:

GET https://example.com/complete-signup?error=access_denied&state=123

Example token request:

POST https://api.truid.app/oauth2/v1/token

grant_type=authorization_code
code=XYZ
redirect_uri=https://example.com/complete-signup
client_id=123
client_secret=ABC
code_verifier=VR1234

Links:

6. Access the Truid User Info endpoint

When the service want to use user data from Truid it should use the stored refresh token to get a new access token, and then use the access token to fetch the user data from the Truid API. This corresponds to the steps O-9 and O-10 in the flow above.

The Truid API has several endpoints that support multiple formats to fetch user data. There is an endpoint that returns user data in a proprietary format, which contains complete information about each claim. See a list of all available claims here.

There are other endpoints that produce data in standard formats, such as the OIDC user-info format.

Examples:

Example OIDC user-info request:

GET https://api.truid.app/oidc/v1/user-info

Example presentation request:

GET https://api.truid.app/exchange/v2/presentation?claims=truid.app%2Fclaim%2Femail%2Fv1,truid.app%2Fclaim%2Fphone-number%2Fv1

Notes:

Data can be fetched multiple times and at any time, not necessarily at the same time that the authorization flow is completed and the access token is first fetched.

The service is not required to persist any user data that is retrieved from the Truid API except the refresh token. The data will be available to fetch from the Truid API for as long as the user has a connection to the service.

Links:

Client Webapp with Backend

Overview

The goal of this integration flow is to give a service backend access to user data from Truid. The user is interacting with the service using a webapp.

This flow uses the OAuth2 Authorization Code Grant with the PKCE extension to allow the user to authorize the backend to access the Truid API to fetch data about the user.

This flow is used to create a session for both the functions User Onboarding and User Login.

Standards:

Flow

This sequence diagram gives an overview of the flow.

webapp with backend flow
Legend

    ◼︎ denotes Truid Web

    ◼︎ denotes Service Web

    C-N denotes service specific messages

    O-N denotes OAuth2 standard messages

    T-N denotes Truid specific messages

Steps

    C-1: The webapp is initiating the flow by asking the backend for a URL to use for starting the flow towards Truid

    C-2: Return authorization URL

    O-3: The browser is redirected to a Truid authorization page

    T-4: The Truid API returns a page containing a QR code for authentication

    O-5: After completing authorization in the Truid App, the browser is redirected back to the Service

    O-6: The backend is using the code to get an access token from Truid

    O-7: The Truid API is returning an access token

    C-8: The backend is returning a response. Usually this is a redirect back to the Service frontend.

    C-9: Fetching the frontend web, triggered by the redirect in C-8.

    C-10: Returning the frontend web page.

    O-11: The backend uses the access token to fetch data from the Truid API

    O-12: The Truid API returns data about the user

Integration

This section describes the steps needed to integrate a service with Truid.

1. Configure Service in Truid

Currently, the process of configuring a service in Truid requires contacting the Truid support and ask for a service to be registered. Eventually this process will be replaced with a self-service UI.

For a service to be activated for one of these functions, a function specific consent template must be configured. The information needed to configure a consent template is:

Links:

2. Create endpoint for authorization URL

Add an endpoint in the backend which has the purpose of creating an Authorization Request URL, and redirect the app to this URL. This corresponds to the steps C-1 and C-2 in the flow above. The returned Authorization Request URL will then be used in step O-3 in the flow above.

The Authorization Request URL follows the OAuth2 standard for an Authorization Request. The URL will point to different endpoints in the Truid API depending on which Truid Authorization Flow that should be started.

The Authorization Request URL should contain a scope parameter, which should be the list of Data Points to request access to. The available Data Points are listed here.

To initiate a User Onboarding, the Authorization Request URL should point to https://api.truid.app/oauth2/v1/authorize/confirm-signup, see API Reference.

To initiate a User Login, the Authorization Request URL should point to https://api.truid.app/oauth2/v1/authorize/login-session, see API Reference.

To initiate a Sign Operation, the Authorization Request URL should point to https://api.truid.app/oauth2/v1/authorize/sign, see API Reference.

Notes:

The redirect_uri parameter is where the client will be redirected with an authorization code. This URL must match exactly what is configured in Truid.

The scope parameter must be a subset of the data points that were given when configuring the service in Truid.

The state parameter must be used to prevent cross-site request forgery, see RFC-6749 Section 10.12.

The PKCE extension must be used, see RFC 7636 - Proof Key for Code Exchange by OAuth Public Clients (PKCE). The only supported code challenge method is S256.

Some clients, such as react-native based apps, have problems with manual handling of redirection responses, and in those cases it might make sense to return the authorization URL in a 2xx response instead of 302. See code example

Example:

https://api.truid.app/oauth2/v1/authorize/confirm-signup?response_type=code&client_id=abcdef&scope=truid.app%2Fdata-point%2Femail&redirect_uri=https%3A%2F%2Fexample.com%2Fcomplete-signup&state=123456&code_challenge=CH12345&code_challenge_method=S256

Links:

3. Open authorization URL

Start the Authorization Flow from the webapp, by directing the browser to the endpoint created in step 2 and then to be redirected to the Authorization Request URL. This corresponds to steps C-1, C-2, and O-3 in the flow above.

Notes:

The authorization URL can be opened in a new window to keep the webapp while doing the authorization.

See below for notes on using IFrames.

Links:

Notes on IFrames

It is possible to start the Authorization Flow in an IFrame, except on a mobile device where the flow must be opened using a regular link.

Size:

The IFrame content is designed to fit in an IFrame of size 400x500 pixels.

It is possible to use the iframe-resizer library to automatically adjust the size of the IFrame to the content. The Truid login page implements a subset of the functionality of the iframe-resizer content window. It will respond to an init message and reply with the desired size of the IFrame.

A service does not need to implement the full iframe-resizer API. It is enough to send the message [iFrameSizer]truid:1:true once to the IFrame, and listen for a message on the form [iFrameSizer]truid:<height>:<width>:init.

4. Add endpoint for completing authorization

Add an endpoint for completing the authorization. This corresponds to step O-5 in the flow above, and is the redirect URI that the browser will be directed to at the end of the authorization flow.

The service should invoke the Truid API token endpoint to complete the authorization flow, and to exchange the code into an access token and a refresh token. This corresponds to step O-6 and O-7 in the flow above.

The returned access token can be used to request user data from the Truid API.

Usually this endpoint will return an HTTP 302 redirect to the browser, redirecting it back to the frontend.

Notes:

The backend must authenticate the request to identify the logged in user that sent the request. The state parameter can not be used to identify the user, since it could be faked. How the service chooses to authenticate users is up to the service to decide.

The service must verify that the state parameter is correct and matches the logged in user, to prevent cross-site request forgery, see RFC-6749 Section 10.12.

If the user cancels the authorization request, or if there is any other error during the authorization flow, the redirect will contain an error parameter that identifies the error. The service should return a 403 response from this endpoint in that case.

The backend must include the PKCE code verifier in the request to get an access token.

The redirect_uri parameter in the token request must match exactly what is configured in Truid.

The code received in the endpoint has a short expiry, 60 seconds, and the call to exchange the code for an access token need to be done within that time frame.

Examples:

Example authorization response:

GET https://example.com/complete-signup?code=XYZ&state=123

Example authorization response when user declined:

GET https://example.com/complete-signup?error=access_denied&state=123

Example token request:

POST https://api.truid.app/oauth2/v1/token

grant_type=authorization_code
code=XYZ
redirect_uri=https://example.com/complete-signup
client_id=123
client_secret=ABC
code_verifier=VR1234

Links:

5. Access the Truid User Info endpoint

When the service want to use user data from Truid it should use the stored refresh token to get a new access token, and then use the access token to fetch the user data from the Truid API. This corresponds to the steps O-11 and O-12 in the flow above.

The Truid API has several endpoints that support multiple formats to fetch user data. There is an endpoint that returns user data in a proprietary format, which contains complete information about each claim. See a list of all available claims here.

There are other endpoints that produce data in standard formats, such as the OIDC user-info format.

Examples:

Example OIDC user-info request:

GET https://api.truid.app/oidc/v1/user-info

Example presentation request:

GET https://api.truid.app/exchange/v2/presentation?claims=truid.app%2Fclaim%2Femail%2Fv1,truid.app%2Fclaim%2Fphone-number%2Fv1

Notes:

Data can be fetched multiple times and at any time, not necessarily at the same time that the authorization flow is completed and the access token is first fetched.

The service is not required to persist any user data that is retrieved from the Truid API except the refresh token. The data will be available to fetch from the Truid API for as long as the user has a connection to the service.

Links:

Pushed Authorization Request

Overview

Pushed Authorization Request (PAR) is an extension to the OAuth2 Authorization code flow to mitigate some security flaws in the standard flow.

The PAR flow can be used with any of the regular authorization flows, and is almost identical to a regular authentication flow. The only difference is that instead of putting all authorization parameters in the URL, such as for example scope and state, these parameters are first pushed to the Truid backend using a POST request. Then the regular authorization flow starts, and only refers to the pushed authorization request using a request_uri parameter.

The PAR flow is more secure because the authorization parameters are passed directly to the Truid backend, and never go via the users browser like they do in the regular flow. This means that the authorization parameters cannot be changed by a malicious user agent, and that they will not be logged in any access logs.

See Session Creation for details about standard OAuth2 authorization flow.

Standards:

Flows

The PAR flow is initiated by the Service Backend making a POST request against the PAR endpoint with a application/x-www-form-urlencoded body. The body contains all parameters usually included as query paameters in an OAuth2 authorization GET request.

The following sequence illustrates the flow for an Onboarding Session:

par flow
Legend

    C-N denotes service specific messages

    P-N denotes OAuth2 PAR messages

    O-N denotes OAuth2 standard messages

Steps

    C-1: The Frontend initiates a request on behalf of a User, that should be authenticated in the Backend.

    P-2: The Backend initiates the flow by making an authenticated request against the Truid PAR endpoint including all OAuth2 parameters.

    P-3: The response contains a request_uri which is valid for a short period of time.

    C-4: The Backend redirects the End-User to the standard OAuth2 authorization endpoint with the received request_uri as query param.

    O-5: The User-Agent initiates the standard OAuth2 flow by making a GET.

Links:

Session Management

Login Session

A login session starts when the user is logging in and ends either with the user explicitly logging out or when the user has been idle for some time. The user may explicitly log out through the Service or through the Truid App.

This section describes how to validate a session and how to handle logout. Creating a session is covered in Session Creation.

Flows

login session expiry
Legend

    C-N denotes service specific messages

    O-N denotes OAuth2 standard messages

Steps

    C-1: The Frontend initiates a request on behalf of a User, that should be authenticated in the Backend.

    O-2: The Backend validates that the access token that it holds for the User. This is done by checking that the access token is not expired.

    O-3: If the access token is expired, the Backend must request a new access token by performing a token refresh.

    O-4: A new access token and refresh token is received.

    C-5: The Backend has successfully validated that the user session is still active, and can return a successful response.

Integration

1. Ensure active session

The Service Backend must always make sure to have a valid Truid login session when it serves a request from the User, not only when it needs to access information from the Truid REST API.

The main purpose of this is to validate the session and to protect the data that the Service exposes to the User. It is not only to protect the data that Truid exposes to the Service.

A valid login session is represented by a valid access token. As long as the access token is not expired the session is valid. If the access token is expired the Service must issue a refresh token request towards the Truid REST API to obtain a valid access token.

Access tokens have an expiry time set in the response from the token endpoint in the Truid REST API. This expiry time will not always be the same. It will typically be very short at the start of the session, where the risk of fraud is greater, and then gradually increase in time.

The Service Backend is supposed to store the refresh token, the access token, and the access token expiry time, all associated with the user session.

Examples:

Example token refresh request:

POST https://api.truid.app/oauth2/v1/token

grant_type=refresh_token
refresh_token=XYZ123
client_id=123
client_secret=ABC

Links:

Signatures

This section describes how to create cryptographic signatures. The data to be signed (DTBS) is usually a Document but could be any arbitrary data.

The Sign Operation function should be used to initiate the process. The initial authorization URL will share all common request params with other Truid functions but with additional params specific for the Sign Operation.

JAdES Level Baseline-B signature detached

Overview

This section describes in details how to sign a binary data object producing a JAdES Level Baseline-B signature with detached payload using reference method ObjectIdByURIHash according to 5.2.8.3.3 in ETSI TS 119 182-1.

The flow uses the OAuth2 authorization code flow with Pushed Authorization Request (PAR) extension and additional parameters. See Pushed Authorization Request.

Flow

1. Prepare sign operation request
Data object

The binary data that is signed is referred to as “data object”. The data object can be of any type and source but is typically a Document (pdf, doc, xml) containing the agreement the End-User commits to. The following parameters in the Truid API are used:

data_object_id

The identifier that references the data object should be a URI and to be fully compliant with ETSI JAdES Baseline-B signatures it should be a URI classified as a locator. Example of such a URI is a URL. Truid does not enforce the format of the data_object_id nor mandates that the URI is resolvable. It will be included in the JWS protected header sigD.pars array as the only entry.

See 5.2.8.3.1 General requirements in ETSI TS 119 182-1.

data_object_digest

To avoid the need to send the data object to Truid and include it in clear text in the signature a digest is calculated over the binary data using a standard algorithm like SHA-256. The digest value should be Base64Url encoded and will be included in the JWS protected header sigD.hashV array as the only entry and will thus contribute to the integrity of the signature.

data_object_digest_algorithm

The algorithm used to calculate the data_object_digest value. Must be S256. Will be included in the JWS protected header sigD.hashM.

data_object_b64

The digest is either calculated directly on the binary data or after Base64Url encoding the binary data. In most situations where the binary data is a document there is no need to Base64Url encode the data prior to digest. The parameter data_object_b64 must be set to true or false accordingly. The value will be included in the JWS protected header value b64. See IETF RFC 7797.

Example digest without Base64Url encoded data object
BASE64URL-ENCODE(SHA256( data object ) )
Example digest with Base64Url encoded data object
BASE64URL-ENCODE(SHA256( BASE64URL-ENCODE( data object ) ) )
Note
Base64Url encoding should be done without padding.
data_object_content_type

Mime type of the data object according to Json Web signatures - 4.1.10. Example application/pdf. It will be included in the JWS protected header value sigD.ctys array as the only entry.

Links
User message

The user message is what Truid will display to the End-User when asked to sign the data object. It should be clear to the End-User what is being signed and the user message should be on the preferred language of the End-User.

The user message is identified by:

  • user_message

2. Push authorization request

Before redirecting the End-User to the OAuth2 sign operation authorization endpoint all input parameters are pushed to Truid backend using a POST request with a application/x-www-form-urlencoded body.

Example pushed authorization request
POST https://api.truid.app/oauth2/v1/par/sign

response_type=code
client_id=client-123
client_secret=ABC
scope=truid.app/data-point/name
redirect_uri=https://example.com/complete-sign
state=S-123
code_challenge=CH123
code_challenge_method=S256
signature_profile=aes_jades_baseline_b-b
jws_serialization=compact
jws_packaging=detached
data_object_id=https://example.com/docs/example-document-v1.pdf
data_object_digest=DXYZ
data_object_digest_algorithm=S256
data_object_b64=false
data_object_content_type=application/pdf
user_message=I sign the document 'Example Document - v1'
Example pushed authorization response
{
  "request_uri": "R-123",
  "expires_in": 60
}
Note
The request_uri will have a short expiry that should be just long enough for the Service backend to redirect the End-User to Truid Sign operation endpoint.
3. Initiate OAuth2 authorization

The Service backend directs the User-Agent to the Sign operation endpoint.

Example OAuth authorization request
GET https://api.truid.app/oauth2/v1/authorize/sign?client_id=client-123&request_uri=R-123
4. Receive authorization response

When the Sign operation completes the User-Agent will be redirected to the redirect_uri with the authorization code as query param.

Example authorization response
GET https://example.com/complete-sign?code=XYZ&state=S-123
Example authorization response when user declined
GET https://example.com/complete-sign?error=access_denied&state=S-123

The code is then exchanged against an access_token and refresh_token at the token endpoint.

Example token request
POST https://api.truid.app/oauth2/v1/token

grant_type=authorization_code
code=XYZ
redirect_uri=https://example.com/complete-sign
client_id=123
client_secret=ABC
code_verifier=VR1234
5. Fetch signature

The access_token is used to fetch the signature.

GET https://api.truid.app/exchange/v1/signature
Note
The signature can be fetched multiple times, not necessarily at the same time that the authorization flow is completed and the access token is first fetched.
Note
The content type of the signature response is application/jose (i.e. JWS). Either make the call without Accept header, or set it to: Accept: application/jose.

The compact and detached format of the JWS will be <Base64 encoded protected header>..<signature>. As seen the payload (the part between the dots) is empty.

Example JWS
eyJhbGciOiJFUzI1NiIsInR5cCI6Impvc2UiLCJjcml0IjpbInNpZ1QiLCJzaWdEIiwiYjY0Il0sInNpZ1QiOiIyMDIzLTExLTIzVDEzOjQ0OjU5WiIsInNpZ0QiOnsibUlkIjoiaHR0cDovL3VyaS5ldHNpLm9yZy8xOTE4Mi9PYmplY3RJZEJ5VVJJSGFzaCIsInBhcnMiOlsiaHR0cHM6Ly9leGFtcGxlLmNvbS9kb2NzL2V4YW1wbGUtZG9jdW1lbnQtdjEucGRmIl0sImhhc2hNIjoiUzI1NiIsImhhc2hWIjpbIlpBWDNyamRYLXRncDNPb0Zac1F5SGcwUlE0ZXNuWFU4b1BNMHU0WXc5YlEiXSwiY3R5cyI6WyJwZGYiXX0sImI2NCI6ZmFsc2UsIng1YyI6WyJNSUlDS0RDQ0FjNmdBd0lCQWdJSFIzbmp0RzYza1RBS0JnZ3Foa2pPUFFRREFqQkxNUXN3Q1FZRFZRUUdFd0pUUlRFWU1CWUdBMVVFQ2d3UFZISjFhV1FnUVVJZ0xTQlVSVk5VTVNJd0lBWURWUVFEREJsVVJWTlVJQzBnU1c1MFpYSnRaV1JwWVhSbElFTkJJSFl4TUI0WERUSXpNVEV5TXpFek5EUXdNRm9YRFRJek1USXlNekV6TkRRd01Gb3dOREV5TURBR0ExVUVBd3dwY0hCcFpEMWtaak0xTnpnME15MDJZVE00TFRSbFptTXRPVFpqTkMwNU5UazNaakE1WlRjME5Ua3dXVEFUQmdjcWhrak9QUUlCQmdncWhrak9QUU1CQndOQ0FBVEFqbWNOMjF6MGc1N3FpRjlpREJMZzVVUzBaRWdlRlVmUlhuM1lQams3MlErNmg5bUNQcG80NGFTZkJsSGpyUWVJTWE1Nmh1MVNCNk5mdlhZdnZLdDhvNEd6TUlHd01IRUdBMVVkSXdScU1HaUFGUERWd1Aza1l0SWRBRzNuUU10SVJWK0lUMDJvb1Vla1JUQkRNUXN3Q1FZRFZRUUdFd0pUUlRFWU1CWUdBMVVFQ2d3UFZISjFhV1FnUVVJZ0xTQlVSVk5VTVJvd0dBWURWUVFEREJGVVJWTlVJQzBnVW05dmRDQkRRU0IyTVlJSFIwRlRuL3E0Z2pBZEJnTlZIUTRFRmdRVUtDQm5Ra3lQUnkxdjN0Uk1JZll2UWxsR0lpQXdEQVlEVlIwVEFRSC9CQUl3QURBT0JnTlZIUThCQWY4RUJBTUNCc0F3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQU15QjFTV1NxcXRGL2JiVTl4RWhhMWpzRzd5TVR3OWdrd3NCbERoWTJBT2RBaUFtcmo0andpb0lOV3JSS1pRcUJRSlNnZTZJRUVNN0pnaS9wcUxuME9Ebk1nPT0iLCJNSUlDZURDQ0FoMmdBd0lCQWdJSFIwRlRuL3E0Z2pBS0JnZ3Foa2pPUFFRREFqQkRNUXN3Q1FZRFZRUUdFd0pUUlRFWU1CWUdBMVVFQ2d3UFZISjFhV1FnUVVJZ0xTQlVSVk5VTVJvd0dBWURWUVFEREJGVVJWTlVJQzBnVW05dmRDQkRRU0IyTVRBZUZ3MHlNekE1TVRJd01EQXdNREJhRncweU5EQTVNVEl3TURBd01EQmFNRXN4Q3pBSkJnTlZCQVlUQWxORk1SZ3dGZ1lEVlFRS0RBOVVjblZwWkNCQlFpQXRJRlJGVTFReElqQWdCZ05WQkFNTUdWUkZVMVFnTFNCSmJuUmxjbTFsWkdsaGRHVWdRMEVnZGpFd1dUQVRCZ2NxaGtqT1BRSUJCZ2dxaGtqT1BRTUJCd05DQUFTelF0Q2dFcDdMRmgyMm52YUhiU0JNVUszMEJObkp4NEp2Tm1zWGJEWGwxUWJKVHF2bjBrRUhWajMyTHVVS2xWNkJ4cVNkb2d2UHBKMVlJYzg4WkNNSW80SHpNSUh3TUhFR0ExVWRJd1JxTUdpQUZKV0ZGSUJUS3JJd0FpTVNuR1R4bzlMQkRtR1FvVWVrUlRCRE1Rc3dDUVlEVlFRR0V3SlRSVEVZTUJZR0ExVUVDZ3dQVkhKMWFXUWdRVUlnTFNCVVJWTlVNUm93R0FZRFZRUUREQkZVUlZOVUlDMGdVbTl2ZENCRFFTQjJNWUlIUjBGVFdQcEg4ekFkQmdOVkhRNEVGZ1FVOE5YQS9lUmkwaDBBYmVkQXkwaEZYNGhQVGFnd0VnWURWUjBUQVFIL0JBZ3dCZ0VCL3dJQkFEQU9CZ05WSFE4QkFmOEVCQU1DQWNZd09BWURWUjBmQkRFd0x6QXRvQ3VnS1lZbmFIUjBjRG92TDNCcmFTNTBjblZwWkM1a1pYWXZZM0pzTDNKdmIzUXRZMkV0ZGpFdVkzSnNNQW9HQ0NxR1NNNDlCQU1DQTBrQU1FWUNJUURINnkrYndmcnhnR0dkZDBPOHZ5ZGNlTS96bGFCZXNSczhxVG9TRXhteHJBSWhBTWk2T2pjQTlReEpWcXpaeGRZTE5raE1uMG5WZ2NmS1JIbFBFUUc3VVdvOSIsIk1JSUIzakNDQVlTZ0F3SUJBZ0lIUjBGVFdQcEg4ekFLQmdncWhrak9QUVFEQWpCRE1Rc3dDUVlEVlFRR0V3SlRSVEVZTUJZR0ExVUVDZ3dQVkhKMWFXUWdRVUlnTFNCVVJWTlVNUm93R0FZRFZRUUREQkZVUlZOVUlDMGdVbTl2ZENCRFFTQjJNVEFlRncweU16QTVNVEl3TURBd01EQmFGdzB5TkRBNU1USXdNREF3TURCYU1FTXhDekFKQmdOVkJBWVRBbE5GTVJnd0ZnWURWUVFLREE5VWNuVnBaQ0JCUWlBdElGUkZVMVF4R2pBWUJnTlZCQU1NRVZSRlUxUWdMU0JTYjI5MElFTkJJSFl4TUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFRnozaVFoRVJVb1JwMHJFVmljZzRlQSsvekQ4TmZhcDhkZlBJV2wxbnlWN1RHb3N5d0wrWnZNYzJWMWM5VkZ6Q2JJcXA5QThSMzloSDA2aTUxejhLZEtOak1HRXdId1lEVlIwakJCZ3dGb0FVbFlVVWdGTXFzakFDSXhLY1pQR2owc0VPWVpBd0hRWURWUjBPQkJZRUZKV0ZGSUJUS3JJd0FpTVNuR1R4bzlMQkRtR1FNQThHQTFVZEV3RUIvd1FGTUFNQkFmOHdEZ1lEVlIwUEFRSC9CQVFEQWdIR01Bb0dDQ3FHU000OUJBTUNBMGdBTUVVQ0lFRmtUMFBIZURvM2EvaGxTSWMzQmJ0RE16enhxVk9xSzd2Y1BwZ1hoWU9OQWlFQWhaaGZRdHMvWm1rN2NIWndkK0ZTTE9PZU41TzZ4WW5hWUthU3hEaGNodFk9Il0sInRydWlkLmFwcC91c2VyX21lc3NhZ2UvdjEiOiJJIHNpZ24gdGhlIGRvY3VtZW50ICdFeGFtcGxlIERvY3VtZW50IC0gdjEnIn0..uBL5emJiZBVCyURgvoCZVa8u8yQ04wM4Kf0H_f9k1GGzL04g7cZvK_1Bk6Zi_EZkw3Frj8Rmof2vNU9z7SWEKw
Example decoded protected header
{
  "alg": "ES256",
  "typ": "jose",
  "crit": [
    "sigT",
    "sigD",
    "b64"
  ],
  "sigT": "2023-11-23T13:44:59Z",
  "sigD": {
    "mId": "http://uri.etsi.org/19182/ObjectIdByURIHash",
    "pars": [
      "https://example.com/docs/example-document-v1.pdf"
    ],
    "hashM": "S256",
    "hashV": [
      "ZAX3rjdX-tgp3OoFZsQyHg0RQ4esnXU8oPM0u4Yw9bQ"
    ],
    "ctys": [
      "application/pdf"
    ]
  },
  "b64": false,
  "x5c": [
    "MIICKDCCAc6gAwIBAgIHR3njtG63kTAKBggqhkjOPQQDAjBLMQswCQYDVQQGEwJTRTEYMBYGA1UECgwPVHJ1aWQgQUIgLSBURVNUMSIwIAYDVQQDDBlURVNUIC0gSW50ZXJtZWRpYXRlIENBIHYxMB4XDTIzMTEyMzEzNDQwMFoXDTIzMTIyMzEzNDQwMFowNDEyMDAGA1UEAwwpcHBpZD1kZjM1Nzg0My02YTM4LTRlZmMtOTZjNC05NTk3ZjA5ZTc0NTkwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATAjmcN21z0g57qiF9iDBLg5US0ZEgeFUfRXn3YPjk72Q+6h9mCPpo44aSfBlHjrQeIMa56hu1SB6NfvXYvvKt8o4GzMIGwMHEGA1UdIwRqMGiAFPDVwP3kYtIdAG3nQMtIRV+IT02ooUekRTBDMQswCQYDVQQGEwJTRTEYMBYGA1UECgwPVHJ1aWQgQUIgLSBURVNUMRowGAYDVQQDDBFURVNUIC0gUm9vdCBDQSB2MYIHR0FTn/q4gjAdBgNVHQ4EFgQUKCBnQkyPRy1v3tRMIfYvQllGIiAwDAYDVR0TAQH/BAIwADAOBgNVHQ8BAf8EBAMCBsAwCgYIKoZIzj0EAwIDSAAwRQIhAMyB1SWSqqtF/bbU9xEha1jsG7yMTw9gkwsBlDhY2AOdAiAmrj4jwioINWrRKZQqBQJSge6IEEM7Jgi/pqLn0ODnMg==",
    "MIICeDCCAh2gAwIBAgIHR0FTn/q4gjAKBggqhkjOPQQDAjBDMQswCQYDVQQGEwJTRTEYMBYGA1UECgwPVHJ1aWQgQUIgLSBURVNUMRowGAYDVQQDDBFURVNUIC0gUm9vdCBDQSB2MTAeFw0yMzA5MTIwMDAwMDBaFw0yNDA5MTIwMDAwMDBaMEsxCzAJBgNVBAYTAlNFMRgwFgYDVQQKDA9UcnVpZCBBQiAtIFRFU1QxIjAgBgNVBAMMGVRFU1QgLSBJbnRlcm1lZGlhdGUgQ0EgdjEwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASzQtCgEp7LFh22nvaHbSBMUK30BNnJx4JvNmsXbDXl1QbJTqvn0kEHVj32LuUKlV6BxqSdogvPpJ1YIc88ZCMIo4HzMIHwMHEGA1UdIwRqMGiAFJWFFIBTKrIwAiMSnGTxo9LBDmGQoUekRTBDMQswCQYDVQQGEwJTRTEYMBYGA1UECgwPVHJ1aWQgQUIgLSBURVNUMRowGAYDVQQDDBFURVNUIC0gUm9vdCBDQSB2MYIHR0FTWPpH8zAdBgNVHQ4EFgQU8NXA/eRi0h0AbedAy0hFX4hPTagwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAcYwOAYDVR0fBDEwLzAtoCugKYYnaHR0cDovL3BraS50cnVpZC5kZXYvY3JsL3Jvb3QtY2EtdjEuY3JsMAoGCCqGSM49BAMCA0kAMEYCIQDH6y+bwfrxgGGdd0O8vydceM/zlaBesRs8qToSExmxrAIhAMi6OjcA9QxJVqzZxdYLNkhMn0nVgcfKRHlPEQG7UWo9",
    "MIIB3jCCAYSgAwIBAgIHR0FTWPpH8zAKBggqhkjOPQQDAjBDMQswCQYDVQQGEwJTRTEYMBYGA1UECgwPVHJ1aWQgQUIgLSBURVNUMRowGAYDVQQDDBFURVNUIC0gUm9vdCBDQSB2MTAeFw0yMzA5MTIwMDAwMDBaFw0yNDA5MTIwMDAwMDBaMEMxCzAJBgNVBAYTAlNFMRgwFgYDVQQKDA9UcnVpZCBBQiAtIFRFU1QxGjAYBgNVBAMMEVRFU1QgLSBSb290IENBIHYxMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFz3iQhERUoRp0rEVicg4eA+/zD8Nfap8dfPIWl1nyV7TGosywL+ZvMc2V1c9VFzCbIqp9A8R39hH06i51z8KdKNjMGEwHwYDVR0jBBgwFoAUlYUUgFMqsjACIxKcZPGj0sEOYZAwHQYDVR0OBBYEFJWFFIBTKrIwAiMSnGTxo9LBDmGQMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgHGMAoGCCqGSM49BAMCA0gAMEUCIEFkT0PHeDo3a/hlSIc3BbtDMzzxqVOqK7vcPpgXhYONAiEAhZhfQts/Zmk7cHZwd+FSLOOeN5O6xYnaYKaSxDhchtY="
  ],
  "truid.app/user_message/v1": "I sign the document 'Example Document - v1'"
}
Details
  • crit - Critical header that the verifier needs to understand to verify the signature.

  • x5c - The certificate chain will be self-contained with: [<signing cert>,<intermediate cert>, <root cert>].

  • sigT - Time when the signature was created.

  • sigD.mId - The method used to reference the data object.

  • sigD.pars[0] - The data object identifier.

  • sigD.hashM - The hashing algorithm.

  • sigD.hashV[0] - The digest value.

  • sigD.ctys[0] Content type of the data object.

  • truid.app/user_message/v1 - Truid header with the user message.

6. Validate Signature

Validating the Signature is done in multiple steps:

  1. Validate the JWS format (<protected header>..<signature>)

  2. Validate certificate chain (x5c header + root certificate from Truid)

  3. Validate supported algorithm (alg header)

  4. Signature is cryptographically signed by End-User certificate (x5c header + signature)

  5. Validate JWS critical headers (crit header)

  6. Data object digest matches (sigD header)

  7. User message is correct (truid.app/user_message/v1 header)

  8. Signature time is valid (sigT header)

The Certificate Chain header x5c contains all certificates and are thus self-contained to cryptographically validate the signature as well as the certificate chain. However, the Service needs to verify that the Root cert is issued by Truid.

Truid publishes Root certificates on https://pki.truid.app/certs/<cert name>.pem and the <cert name> is the Common Name in the certificate in lowercase and space replaced with dash (-). The Service needs to download it and either store the certificate or a thumbprint of the certificate.

Current Truid Root certificate: Root CA v1

For general details about signature validation see Signature Validation

Note
There are libraries available that can validate JAdES signatures as well as JWS signatures. It is important to note that a standard library for JWS validation will not be able to fully validate a JAdES signature. One reason is that a JWS validator should fail if it encounters any entries in the crit header that it does not know how to validate.
Additional data is fetched

If any data points has been requested via the scope parameter, they will be returned from the presentation endpoint.

GET https://api.truid.app/exchange/v1/presentation?claims=truid.app%2Fclaim%2Femail%2Fv1,truid.app%2Fclaim%2Fphone-number%2Fv1
Note
Data can be fetched multiple times, not necessarily at the same time that the authorization flow is completed and the access token is first fetched.

Data

Users will always identify themselves by a pairwise pseudonymous persistent identifier which is unique over time for all interactions over the same user/service connection.

Additional attributes are shared as Claims which constitutes anything that can be extracted or derived from documents and other assertions that the user are able to provide evidences for.

No data is ever shared without the user’s explicit consent. Services need to specify which Data Points that are requested in order to acquire this consent - hence to be granted access to the corresponding Claims.

The consent collected is limited to Sharing Purposes declaring what data processing activities that the corresponding claims are entitled for.

Data Points

A Data Point represents data that a User is sharing, without regard to any specific format. Sharing a Data Point gives a Service access to that data in any format available, as represented by corresponding Claims.

For example, a phone number may be represented either in international or local format, but the Data Point represents the phone number, not any particular formatting.

Address

Collection of information that describes the location of a building, apartment, or other structure.

Characteristics

Key

truid.app/data-point/address

Date of Birth

Explicit date, i.e., the day, month and year, on which an individual was born.

Characteristics

Key

truid.app/data-point/birthdate

E-mail Address

Virtual address that defines an electronic messaging endpoint to which email messages can be delivered, typically via an Simple Mail Transfer Protocol (SMTP) based communications system.

Characteristics

Key

truid.app/data-point/email

Gender

The gender of a person, typically but not necessarily 'male' or 'female'.

Characteristics

Key

truid.app/data-point/gender

Indicates the complete name of a person, as confirmed by an authority.

Characteristics

Key

truid.app/data-point/legal-name

Name

Designation by which someone is known in some context.

Characteristics

Key

truid.app/data-point/name

Nationality

A country that recognizes the subject as its citizen.

Characteristics

Key

truid.app/data-point/nationality

Passport

Formal identity document, issued by a national government, which certifies the identity and nationality of its holder for the purpose of international travel.

Characteristics

Key

truid.app/data-point/passport

Passport Number

Document number associated with a passport.

Characteristics

Key

truid.app/data-point/passport-number

Phone Number

Virtual address that may be assigned to a fixed-line telephone subscriber station connected to a telephone line or to a wireless electronic telephony device, such as a radio telephone or a mobile telephone, or to other devices or services for data transmission via the public switched telephone network (PSTN) or other public and private networks.

Characteristics

Key

truid.app/data-point/phone-number

Portrait Image

A pictorial representation of a person usually showing the face.

Characteristics

Key

truid.app/data-point/portrait-image

Swedish Personal Number

National identification number associated with an individual (personnummer).

Characteristics

Key

truid.app/data-point/personal-number/swe

Claims

A claim represents the data that a Service may access, in a particular format, after a User has shared the data with the Service.

Each claim has a key that identifies the claim, and a reference to the Data Point that must be shared for the claim to be available.

Note: String values are generally not meant to be parsed, unless they specify an explicit pattern. For example, it is not a good idea to try to parse out given and family name from a string, it is then better to request another claim that contains the name structured into given and family name parts.

Address

Human-readable postal address, with no guaranteed format.

Characteristics

Key

truid.app/claim/address/v1

Data Point

truid.app/data-point/address

Format

value

Type

string

Human-readable postal address, with no guaranteed format.

Example
"221B Baker St, London NW1 6XE, UK"

Date of Birth

Date of birth.

Characteristics

Key

truid.app/claim/birthdate/v1

Data Point

truid.app/data-point/birthdate

Format

value

Type

string

Format

yyyy-MM-dd

Date of birth.

Example
"1990-12-24"

E-mail Address

E-mail address, formatted as <local part>@<domain part> according to addr-spec in [RFC 5322](https://www.rfc-editor.org/rfc/rfc5322#section-3.4.1).

Characteristics

Key

truid.app/claim/email/v1

Data Point

truid.app/data-point/email

Format

value

Type

string

E-mail address, formatted as <local part>@<domain part> according to addr-spec in [RFC 5322](https://www.rfc-editor.org/rfc/rfc5322#section-3.4.1).

Example
"jsmith@example.com"

Family Names

Indicates the name shared in common to identify the members of a family, as distinguished from each member’s given name. May be one or more names, with no guaranteed format. This claim might not be available, depending on the available data in the documents that the user has provided. For example, some documents only include a field for full name.

Characteristics

Key

truid.app/claim/family-name/v1

Data Point

truid.app/data-point/name

Format

value

Type

string

May be one or more names, with no guaranteed format.

Gender

Typically M(ale) or F(emale), or X non-binary classification.

Characteristics

Key

truid.app/claim/gender/v1

Data Point

truid.app/data-point/gender

Format

value

Type

string

Values

M, F, X

Typically M(ale) or F(emale), or X non-binary classification.

Example
"M"

Given Names

Indicates the given name or first name of a person, that is, the name chosen for them at birth or changed by them subsequently from the name given at birth. May be one or more names, with no guaranteed format. This claim might not be available, depending on the available data in the documents that the user has provided. For example, some documents only include a field for full name.

Characteristics

Key

truid.app/claim/given-name/v1

Data Point

truid.app/data-point/name

Format

value

Type

string

May be one or more names, with no guaranteed format.

The full legal name of a person.

Characteristics

Key

truid.app/claim/legal-name/v1

Data Point

truid.app/data-point/legal-name

Format

value

Type

string

The full legal name of a person.

Example
"John Smith"

Name

Full name of a person, with no guaranteed format.

Characteristics

Key

truid.app/claim/name/v1

Data Point

truid.app/data-point/name

Format

value

Type

string

Name of a person, with no guaranteed format.

Example
"John Smith"

Nationality

ISO-3166 Alpha-3 Country Code.

Characteristics

Key

truid.app/claim/nationality/v1

Data Point

truid.app/data-point/nationality

Format

value

Type

string

ISO-3166 Alpha-3 Country Code.

Example
"DEU"

Passport Number

Passport number. May contain any alphanumeric character.

Characteristics

Key

truid.app/claim/passport-number/v1

Data Point

truid.app/data-point/passport-number

Format

value

Type

string

Passport number. May contain any alphanumeric character.

Example
"J12393496"

Phone Number

Telephone number, in international format +<country code><subscriber number incl. area code> according to [E.164](https://www.itu.int/rec/T-REC-E.164-201011-I/en)

Characteristics

Key

truid.app/claim/phone-number/v1

Data Point

truid.app/data-point/phone-number

Format

value

Type

string

Telephone number, in international format +<country code><subscriber number incl. area code> according to [E.164](https://www.itu.int/rec/T-REC-E.164-201011-I/en)

Example
"+14151231234"

Portrait Image

Portrait image.

Characteristics

Key

truid.app/claim/portrait-image/v1

Data Point

truid.app/data-point/portrait-image

Format

value

Type

object

Portrait image.

value.format

Type

string

Media Type as defined in [IANA registry](https://www.iana.org/assignments/media-types/media-types.xhtml#image), e.g. image/png.

value.image_data

Type

string

Format

byte

Base64 encoded image data.

Example
{
    "format": "image/png",
    "image-data": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVR4nGNgAAIAAAUAAXpeqz8="
}

Structured Name

Structured name of a person, typically contains given and family names, and the full name field.

Note that not all countries are displaying given and family name in the same order. Some countries write the given name first and some countries write the family name first. For display purposes it is better to use the full name, which will always be correct order.

Characteristics

Key

truid.app/claim/structured-name/v1

Data Point

truid.app/data-point/name

Format

value

Type

object

Structured name of a person, typically contains given and family names.

value.full_name

Type

string

Full name of a person, with no guaranteed format.

value.given_names

Type

string

Indicates the given name or first name of a person, that is, the name chosen for them at birth or changed by them subsequently from the name given at birth. This claim might not be available, depending on the available data in the documents that the user has provided. For example, some documents only include a field for full name.

value.family_names

Type

string

Indicates the name shared in common to identify the members of a family, as distinguished from each member’s given name. This claim might not be available, depending on the available data in the documents that the user has provided. For example, some documents only include a field for full name.

Swedish Personal Number

Swedish Personal Number (personnummer).

Characteristics

Key

truid.app/claim/personal-number/swe-10/v1

Data Point

truid.app/data-point/personal-number/swe

Format

value

Type

string

Pattern

\d{10}

10 digit Swedish Personal Number (personnummer).

Example
"9012241234"

Sharing Purpose

Whenever a User shares data with a Service, it does so by a signed consent. This consent does not only cover WHAT data to share, but also WHY the data is shared. That "why" is the Sharing Purpose.

With Truid, the user is in full control of everything - hence it is not allowed for a service to process the data collected from a user for any other purpose than what the user has given explicit consent to. This is further enforced by many data privacy regulations such as GDPR.

Sharing Purposes must be described according to following rules:

  • Specified: Detailed enough to determine what kind of processing is applied.

  • Explicit: No vagueness or ambiguity as to their meaning or intent, i.e. never allow function creep.

  • Legitimate: Be "in accordance with the law" in the broadest sense, including non-discrimination, reasonable expectations etc.

In order to protect the user’s rights and help services to stay compliant, Truid fully handles governance around sharing purposes. What purposes to apply is agreed upon between Truid and the service provider during service enrollment. Here follows a list of a few fundamental purposes that captures common aspects for many service provider with similar needs.

  • Identity verification “<service_name> uses your personal data to verify your legal identity in reference to the supporting documentation that you have uploaded to the Truid vault.”

  • Delivery of service “<service_name> uses your personal data to ensure that you get the correct service delivery as per the offered terms and conditions.”

  • Identity verification of the signatory “<service_name> stores your personal data to allow verification of your legal identity in reference to a legally binding signature.”

Example Code

Example Backend

This is an example project showing how to access the Truid REST API from a backend service to read data. This example is written using Kotlin and spring-boot, but should be easy enough to understand to know how to access the Truid REST API using any language and technology.

Example App

This is an example project that shows how to start a Truid flow from an app, running on the same device as the Truid App. The app is written in react-native for iOS and Android, but should be easy enough to understand to know how to start a flow using any language and technology.

Example Web

This is an example project that shows how to start a Truid flow from a webapp, running in a browser either on the same device as the Truid App, or on a separate device.

API Reference

Authentication API

Truid is a standards-compliant OpenID Connect provider. OpenID Connect extends OAuth 2.0 with a layer of identity, allowing clients to perform authentication and identification of End Users. OAuth 2.0 provides API security via scoped access tokens and OpenID Connect provides user authentication and identification. This API specification contains detailed information about the Truid endpoints for authentication over OAuth 2.0 and OpenID Connect.

Identification APIs

Identity data that the User has given consent to share during authentication is presented to the user either in an ID Token or via an API endpoint, protected by an access token. There are two different API endpoints available that presents identity data to a service

OpenID Connect User Info API

This API specification encompass the Truid user-info endpoint for OpenID Connect identification.

Truid Identity Presentation API

This API specification encompass the Truid proprietary presentation endpoint, containing a higher breadth and depth in data and an additional meta-data trail that certifies the identity assurance level.

Troubleshooting

Authorization Endpoint

Error invalid_redirect_uri

The given redirect_uri argument is wrong. It must match exactly the redirect URI that is configured in the service. It is not allowed to add anything to it, such as query parameters or fragments.

Token Endpoint

Error invalid_grant on authorization code request

This error is caused by the client providing incorrect information, for example, but not limited to:

  • The code is invalid or has expired. The expiry time for the code is quite short, around 30 seconds, and must be used immediately when received.

  • The code was already used once. A code can only be used once.

  • The redirect_uri parameter is not matching the one passed in the authorization request.

See RFC-6749

Error invalid_grant on token refresh request

This error is caused by the client providing incorrect information. For example, but not limited to:

  • The refresh_token is invalid or has expired.

  • The refresh_token was already used once. A refresh_token can only be used once.

See RFC-6749

App Integration

Error There seems to be a problem with the link used to open the app, please update the app or try again later

This error occurs when the Truid App is opened by a URL it cannot recognize. It might be because the app is outdated, but when building an integration it is more likely that the URL used to open the app contains a typo.

Contact

If you want to get in touch with us to ask a question or report a bug, use any of these channels: