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.
Credentials
Service credentials will be delivered in an encrypted file, and the passphrase for decrypting the file will be delivered over a different channel.
The credentials file can either be decrypted using the GnuPG
tool, or it can be decrypted using our online decryption tool.
Links:
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.
-
See Session Creation for how start a user onboarding.
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.
-
See Session Creation for how initiate a login.
-
See Login Session for how to ensure that the session is active.
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.
-
See Session Creation for how initiate an Identity Verification.
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.
-
ETSI TR 119 000: The framework for standardization of signatures: overview
https://www.etsi.org/deliver/etsi_tr/119000_119099/119000/01.03.01_60/tr_119000v010301p.pdf -
ETSI TS 119 182-1: JAdES digital signatures; Part 1: Building blocks and JAdES baseline signatures
https://www.etsi.org/deliver/etsi_ts/119100_119199/11918201/01.01.01_60/ts_11918201v010101p.pdf -
RFC7575: JSON Web Signature (JWS)
https://www.ietf.org/rfc/rfc7515.txt -
RFC2459: Internet X.509 Public Key Infrastructure Certificate and CRL Profile
https://www.ietf.org/rfc/rfc2459.txt -
EU/eIDAS DSS (Digital Signature Service)
https://ec.europa.eu/digital-building-blocks/DSS/webapp-demo/doc/dss-documentation.html
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
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.
-
See Signatures for how to sign a document
-
See Session Creation for how to initiate a sign operation.
-
See Truid Identity Presentation API for documentation on the
/exchange/v1/signature
endpoint to fetch the signature.
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.
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
.
Black - button color #000000
, text color #FFFFFF
.
Truid theme - button color #3A277F
, text color #FFFFFF
Avoid to style Truid service buttons in wrong color and misusing the Truid word mark.
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.
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:
-
The type of function to perform
-
Redirect URI, to redirect back to the app, for example
https://example.com/truid/v1/complete-signup
-
A set of data points that the service should be allowed to request
Links:
-
Available Functions
-
Available Data Points
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.
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:
-
The type of function to perform
-
Redirect URI, to redirect back to the app, for example
https://example.com/truid/v1/complete-signup
-
A set of data points that the service should be allowed to request
Links:
-
Available Functions
-
Available Data Points
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:
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
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.
BASE64URL-ENCODE(SHA256( 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.
-
5.2.8.3.3
in ETSI for the definition ofsigD
header.
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.
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'
{ "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.
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.
GET https://example.com/complete-sign?code=XYZ&state=S-123
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.
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'"
}
-
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:
-
Validate the JWS format (<protected header>..<signature>)
-
Validate certificate chain (x5c header + trust anchor containing only root certificate from Truid)
-
Validate supported algorithm (alg header)
-
Signature is cryptographically signed by End-User certificate (x5c header + signature)
-
Validate JWS critical headers (crit header)
-
Data object digest matches (sigD header)
-
User message is correct (truid.app/user_message/v1 header)
-
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.
Note
|
Even though a root certificate is included in the signature, the Service needs to verify that the root certificate is one of the certificates published by Truid. No other certificates can be trusted as the root of the certificate chain in the signature. The service must also check Certificate Revocation Lists (CRL). |
Truid publishes root certificates on https://pki.truid.app/certs/. These root certificates must be installed in the Service in a trust store used to validate signatures. No other certificates should be trusted. Truid will notify when there is a new root certificate available.
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 |
|
Date of Birth
Explicit date, i.e., the day, month and year, on which an individual was born.
Characteristics | |
---|---|
Key |
|
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 |
|
Gender
The gender of a person, typically but not necessarily 'male' or 'female'.
Characteristics | |
---|---|
Key |
|
Id document issuing country
The country code of the country where the id-document was issued.
Characteristics | |
---|---|
Key |
|
Legal Name
Indicates the complete name of a person, as confirmed by an authority.
Characteristics | |
---|---|
Key |
|
Name
Designation by which someone is known in some context.
Characteristics | |
---|---|
Key |
|
Nationality
A country that recognizes the subject as its citizen.
Characteristics | |
---|---|
Key |
|
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 |
|
Passport Number
Document number associated with a passport.
Characteristics | |
---|---|
Key |
|
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 |
|
Portrait Image
A pictorial representation of a person usually showing the face.
Characteristics | |
---|---|
Key |
|
Swedish Personal Number
National identification number associated with an individual (personnummer).
Characteristics | |
---|---|
Key |
|
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 |
|
Data Point |
|
Format | ||
---|---|---|
|
Type |
|
Human-readable postal address, with no guaranteed format. |
Example |
---|
"221B Baker St, London NW1 6XE, UK" |
Date of Birth
Date of birth.
Characteristics | |
---|---|
Key |
|
Data Point |
|
Format | ||
---|---|---|
|
Type |
|
Format |
|
|
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 |
|
Data Point |
|
Format | ||
---|---|---|
|
Type |
|
E-mail address, formatted as |
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 |
|
Data Point |
|
Format | ||
---|---|---|
|
Type |
|
May be one or more names, with no guaranteed format. |
Gender
Typically M(ale) or F(emale), or X non-binary classification.
Characteristics | |
---|---|
Key |
|
Data Point |
|
Format | ||
---|---|---|
|
Type |
|
Values |
|
|
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 |
|
Data Point |
|
Format | ||
---|---|---|
|
Type |
|
May be one or more names, with no guaranteed format. |
Id document issuing country
ISO-3166 Alpha-3 Country Code.
Characteristics | |
---|---|
Key |
|
Data Point |
|
Format | ||
---|---|---|
|
Type |
|
Pattern |
|
|
ISO-3166 Alpha-3 Country Code. |
Example |
---|
"SWE" |
Legal Name
The full legal name of a person.
Characteristics | |
---|---|
Key |
|
Data Point |
|
Format | ||
---|---|---|
|
Type |
|
The full legal name of a person. |
Example |
---|
"John Smith" |
Name
Full name of a person, with no guaranteed format.
Characteristics | |
---|---|
Key |
|
Data Point |
|
Format | ||
---|---|---|
|
Type |
|
Name of a person, with no guaranteed format. |
Example |
---|
"John Smith" |
Nationality
ISO-3166 Alpha-3 Country Code.
Characteristics | |
---|---|
Key |
|
Data Point |
|
Format | ||
---|---|---|
|
Type |
|
ISO-3166 Alpha-3 Country Code. |
Example |
---|
"DEU" |
Passport Number
Passport number. May contain any alphanumeric character.
Characteristics | |
---|---|
Key |
|
Data Point |
|
Format | ||
---|---|---|
|
Type |
|
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 |
|
Data Point |
|
Format | ||
---|---|---|
|
Type |
|
Telephone number, in international format |
Example |
---|
"+14151231234" |
Portrait Image
Portrait image.
Characteristics | |
---|---|
Key |
|
Data Point |
|
Format | ||
---|---|---|
|
Type |
|
Portrait image. |
||
|
Type |
|
Media Type as defined in
[IANA registry](https://www.iana.org/assignments/media-types/media-types.xhtml#image),
e.g. |
||
|
Type |
|
Format |
|
|
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 |
|
Data Point |
|
Format | ||
---|---|---|
|
Type |
|
Structured name of a person, typically contains given and family names. |
||
|
Type |
|
Full name of a person, with no guaranteed format. |
||
|
Type |
|
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. |
||
|
Type |
|
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 |
|
Data Point |
|
Format | ||
---|---|---|
|
Type |
|
Pattern |
|
|
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 thecode
is quite short, around 30 seconds, and must be used immediately when received. -
The
code
was already used once. Acode
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. Arefresh_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:
-
Join the community on Slack and chat with the Truid developers
-
Check open bugs or report new on Github
-
Send us an email on developer@truid.app