OpenID Connect for Identity Assurance, explained by an implementer

Takahiko Kawasaki
13 min readMay 3, 2022

Introduction

OpenID Connect for Identity Assurance 1.0 (OIDC4IDA or IDA) is a technical specification that the eKYC-IDA Working Group of OpenID Foundation has developed. It uses OAuth 2.0 and OpenID Connect (OIDC) as its base and defines a JSON structure that conveys verified claims of a natural person.

OpenID Foundation Working Groups and OIDC4IDA Stack

Claim” here is a technical term that means a user attribute such as given name, birthday, address, and so on.

Verified” here means that the authenticity of the claim has been verified with evidence such as passport, driver’s license, and so on.

In the Internet, there are many web services that users can sign up. They often require users to register user attributes, but the attributes are only self-asserted by users. Such unverified attributes cannot be used in legal contexts. Here OIDC4IDA comes in.

History

Implementer’s Draft 1 — The initial version of the specification was published in November, 2019 (announcement). The version is called Implementer’s Draft 1 (ID1).

Implementer’s Draft 2 — The second version was published in May, 2020 (announcement). The version is called Implementer’s Draft 2 (ID2).

Implementer’s Draft 3 — The third version was published in November, 2021 (annoucement). The version is called Implementer’s Draft 3 (ID3). As of this writing (in May, 2022), ID3 is the lastest version among officially-published drafts.

Next Draft — The past Implementer’s Drafts repeated to introduce breaking changes. And again, it is certain that the next version will contain breaking changes because breaking changes have already been merged into the master branch of the eKYC-IDA Git repository (e.g. PR 87). Considering the amount of breaking changes and addition of new properties, it is highly likely that the Implementer’s Draft 4 will be published before the future final version.

History of OpenID Connect for Identity Assurance 1.0

This article is written based on the latest specification in the eKYC-IDA Git repository as the author of this article (me) attends weekly meetings of the eKYC-IDA WG and can share information about the latest status of the specification with you readers.

verified_claims

The specification defines a JSON structure that conveys verified claims. It is intended that the JSON structure is embedded in other JSON structures such as payloads of ID Token (OIDC Core, Section 2) and responses from UserInfo Endpoint (OIDC Core, Section 5.3).

When the JSON structure appears in other JSON structures, it is labeled with "verified_claims". The following figure illustrates how it is embedded in the payload of an ID Token.

“verified_claims” in Payload of ID Token

The JSON schema file, verified_claims.json, describes the structure of "verified_claims". The file is maintained in the schema directory of the eKYC-IDA Git repository.

verification and claims

The "verified_claims" JSON object contains "verification" and "claims" as top-level properties.

The "verification" JSON object describes pieces of information about the verification process such as “based on what regulation?”, “with what evidence?”, “when?” and “by whom?”

The "claims" JSON object contains pairs of name and value of verified claims.

“verification” and “claims”

verified_claims request

To request an authorization server to embed "verified_claims" in ID Token and/or UserInfo responses, client applications use the claims request parameter of an authorization request that is defined in the Section 5.5 of OpenID Connect Core 1.0.

The format of the claims request parameter is JSON. The JSON contains either or both of "id_token" and "userinfo" as top-level properties. A client application lists names of claims it requests to be embedded in ID Token in the "id_token" JSON object and likewise lists names of claims it requests to be embedded in UserInfo responses in the "userinfo" JSON object. This rule is written in the OIDC Core specification.

The claims request parameter

When a client application wants to get verified claims, it includes "verified_claims" in the "id_token" JSON object and/or the "userinfo" JSON object like the figure below shows.

“verified_claims” in the claims request parameter

The JSON schema file, verified_claims_request.json, describes the structure of "verified_claims" request. The file is maintained in the schema directory of the eKYC-IDA Git repository.

Data Minimization

The specification requires that servers not return data that are not explicitly requested. This policy is called data minimization. Therefore, for a simple verified_claims request like below:

the server returns only "trust_framework" and "given_name" as follows.

If a client application wants more information, it must construct a complex verified_claims request. The following is an example value of the claims parameter that includes a complex verified_claims request (excerpted from the specification).

Filtering

Constraints by value, values, max_age

When a claim in a verified_claims request has a JSON object that contains "value", "values" or "max_age" and the claim is under verified_claims/verification (i.e. not under verified_claims/claims), the JSON object is used as a filtering condition.

  • "value" — The actual value of the claim must match the value specified by "value".
  • "values" — The actual value of the claim must match one or more elements in the "values" array.
  • "max_age" — The elapsed time since the date time that the actual value of the claim expresses must not exceed the number of seconds specified by "max_age".

<"value" example> The example below requests verified claims that have been verified by the rules of the trust framework uk_tfida. If the server does not have verified claims that satisfy the condition, "verified_claims" is not returned.

<"values" example> The example below requests verified claims that have been verified by the rules of either the trust framework nist_800_63A or the trust framework uk_tfida.

<"max_age" example> The example below requests that the elapsed time since the identity verification process took place not exceed 30 days (= 2,592,000 seconds). If the server does not have verified claims that were verified within the last 30 days, "verified_claims" is not returned.

Logical OR by Array

The “Requesting Verification Data” section of the specification contains interesting requirements for the evidence array as excerpted below.

A single entry in the evidence array represents a filter over elements of a certain evidence type. The RP therefore MUST specify this type by including the type field including a suitable value sub-element value. The values sub-element MUST NOT be used for the evidence/type field.

If multiple entries are present in evidence, these filters are linked by a logical OR.

As a result, the following request will result in that all available evidence whose type is either "document" or "electronic_signature" are included in the resultant "verified_claims".

This special rule should apply to other properties of array type such as check_details. However, there is a special rule for assurance_details as excerpted from the specification below.

assurance_details is an array representing how the evidence and check_details meets the requirements of the trust_framework. RP SHOULD only request this where they need to know this information. Where assurance_details have been requested by an RP the OP MUST return the assurance_details element along with all sub-elements that it has. If an RP wants to filter what types of evidence and check_methods they MUST use those methods to do so, e.g. requesting an assurance_type should have no filtering effect.

That is, all available sub-elements of assurance_details are returned when the property is requested. Data minimization and logical-or filtering don’t apply.

Example of Data Minimization and Filtering

Suppose the server holds a dataset that is equivalent to the content of the JSON below.

If the following verified_claims request is made against the dataset,

the server should generate the following "verified_claims".

Points to note are as follows:

  1. The dataset on the server side contains two elements in the "evidence" array, but the "evidence" array in the generated "verified_claims" contains only one element. It is because the constraint, check_details/*/organization == "OpenBankingTPP", filtered out the unmatched element.
  2. The generated "verified_claims" does not contain the "family_name" claim. It is because the actual value of the "family_name" claim in the dataset on the server side is not "Unknown". When the "value", "values" and "max_age" constraints are not satisfied under verified_claims/verification, the entire or partial dataset containing the unmatched property is omitted. On the other hand, under verified_claims/claims, unmatched claims are just omitted without affecting other parts.
  3. Many properties are omitted from the generated "verified_claims" for the data minimization policy. For example, "address" contains only "locality". Other properties such as "postal_code", "country" and "street_address" are omitted.

Attachments

Attachments” is a relatively big feature among others that were added by the third Implementer’s Draft. The feature enables to attach media that are related to the identity verification process. For example, scans of signed forms, photocopies of evidence, and so on.

Attachments can be embedded directly in the "attachments" array like below (embedded_attachments.json; copy from the eKYC-IDA Git repository).

Or, in the case where contents of attachments are hosted on a remote server, only their URLs can be included in the "attachments" array with an optional access token like below (external_attachments.json; copy from the eKYC-IDA Git repository).

Transformed Claims

Transformed Claims (TC) is not a part of the OIDC4IDA specification but a part of “OpenID Connect Advanced Syntax for Claims (ASC) 1.0” that is one of the specifications discussed in the eKYC-IDA WG.

Introduction

The feature of Transformed Claims enables to transform values of claims by applying transformation functions.

For example, by applying the years_ago transformation function to the birthdate claim, the age of the user can be computed and embedded in ID Tokens and/or UserInfo responses. Furthermore, if the gte transformation function (gte means “greater than or equal to”) with an argument 18 is applied to the result of the years_ago transformation function, a boolean value can be obtained that indicates whether the user is above 18 or not. This example can be used in scenarios where age verification is required but personal information such as birthday should not be disclosed.

Concept of Transformed Claims

A reason to pay attention to the TC specification is that age verification is one of key factors in a scenario that is described in the whitepaper of GAIN (Global Assured Identity Network), which is a project to build a global high-trust digital identity network over the Internet.

Transformed Claim Definition

A transformed claim consists of the following components.

  1. Name of the transformed claim
  2. Claim referenced as input
  3. Transformation functions (which may require arguments) applied to the input

In the case of example illustrated in the figure of “Concept of Transformed Claims”, the name of the transformed claim is age_18_or_over, the referenced claim is birthdate, and the transformation functions applied are years_ago and gte (with 18 as an argument).

A transformed claim is defined as a property in a JSON object. The key of the property is the name of the transformed claim and the value of the property is a JSON object which contains a claim property and a fn property. The claim property is a referenced claim and the fn property is a list of transformation functions.

For example, the age_18_or_over transformed claim can be defined as follows.

The value of the fn property is an array. Each element of the array represents a transformation function with or without arguments. When a transformation function takes no argument, only the name of the transformation function is put in the fn array (e.g. "years_ago"). On the other hand, when a transformation function takes arguments, the name of the transformation function and the arguments are packed into an array and the array is put in the fn array (e.g. ["gte", 18]).

Places for Transformed Claim Definitions

There are two places to put definitions of transformed claims in. One is the claims request parameter (OIDC Core, Section 5.5) of an authorization request. The other is the discovery document (OIDC Discovery, Section 4) of the authorization server.

§ transformed_claims

The specification defines transformed_claims as a new property that can appear in the claims request parameter. A client application can put definitions of transformed claims there.

The following is an example of the content of the claims request parameter. It contains "transformed_claims" which contains the definition of age_18_or_over transformed claim.

One more point to note is that the name of the defined transformed claim is referenced in "claims". When a transformed claim defined in "transformed_claims" is referenced, a colon (:) is prefixed like ":age_18_or_over".

§ transformed_claims_predefined

The specification defines transformed_claims_predefined as a new server metadata that may be included in the discovery document. An authorization server can put definitions of transformed claims there.

The following is an example of the transformed_claims_predefined server metadata.

Client applications can use transformed claims predefined by the authorization server in the claims request parameter without redefining them. The following is an example of the claims request parameter that references a predefined transformed claim by prefixing two colons (::) to the name.

Chain of Transformation Functions

The fn property in a definition of transformed claim is a list of transformation functions. The first transformation function in the list will receive a known claim as input. The second and the subsequent transformation functions will receive the execution result of their immediately preceding transformation function. The execution result of the last transformation function will be used as the value of the transformed claim.

For example, the years_ago transformation function in the example shown previously receives the value of the birthdate claim as input and may generate 30 for instance as an execution result. Then, the gte transformation function receives 30 as input and generates true as an execution result. The true generated by gte becomes the value of the age_18_or_over transformed claim.

Chain of Transformation Functions

Predefined Transformation Functions

The following transformation functions are predefined in the specification. See the ASC specification for details.

  • years_ago — computes the number of elapsed years since the input
  • eq — true if the input is equal to the argument
  • gt — true if the input is greater than the argument
  • lt — true if the input is less than the argument
  • gte — true if the input is greater than or equal to the argument
  • lte — true if the input is less than or equal to the argument
  • hash — computes a hash value of the input
  • any — true if any of elements in the input array is true
  • all — true if all of elements in the input array are true
  • none — true if none of elements in the input array are true
  • get — get the value of a specified property from the input JSON object
  • match — true if the input matches the regular expression specified by the argument

Demo of Transformed Claims

The author of this article (me) gave a demo of Transformed Claims in a session of OAuth Security Workshop on December 1, 2021. The recorded video is available on YouTube. The demo starts from 28:32.

OpenID Connect Advanced Syntax for Claims / Demo of Transformed Claims (28:32~)

Implementation

Implementation of Data Minimization and Filtering

As soon as you start to implement the OIDC4IDA specification without compromise, you will realize that it is difficult to implement the logic of the data minimization policy and the filtering rules.

In OIDC Core, all claims are flatly listed as top-level properties in the payload of ID Tokens and UserInfo responses (except the address claim; OIDC Core, Section 5.1.1). However, the structure of "verified_claims" request is too complex.

For discouraged developers, I have published an implementation of the logic as open source here:

The DatasetExtractor class is a part of the authlete-java-common library. The library is for Authlete, but the logic implemented in the class is independent of Authlete APIs. Therefore, you can port the logic to your implementation.

Implementation of Transformed Claims

AFAIK, Authlete 2.3 is the only working implementation of Transformed Claims in the world as of this writing (in May, 2022). The feature of Transformed Claims is implemented in Authlete Server, which is not open source. Please contact Authlete if you want to try Transformed Claims.

Implementation of Authorization Server

java-oauth-server is an open-source sample implementation of authorization server. It uses Authlete as a backend system that interprets OAuth/OIDC requests, generates & manages access tokens, and prepares OAuth/OIDC responses on behalf of a frontend authorization server.

If java-oauth-server is configured to use Authlete 2.3 that supports the latest IDA specification and Transformed Claims, you can try the specification explained in this article.

Below is a sample authorization request for java-oauth-server.

http://localhost:8080/api/authorization?client_id=7681191256&redirect_uri=http://localhost:4000/api/mock/redirection/5383012317&response_type=id_token&scope=openid+email&state=q4sa5o7g6y&nonce=n-0S6_WzA2Mj&claims={"id_token":{"verified_claims":{"verification":{"trust_framework":null,"assurance_process":{"assurance_details":[{"assurance_type":{"value":"verification"},"assurance_classification":null,"evidence_ref":{"txn":null}}]},"verification_process":null,"evidence":[{"type":{"value":"document"},"check_details":[{"check_method":{"value":"pvp"},"organization":null,"txn":null}],"time":null}]},"claims":{"given_name":null,"family_name":null,"address":{"street_address":null,"locality":null,"country":null},"::age_100_or_over":null,":age_18_or_over":null}}},"transformed_claims":{"age_18_or_over":{"claim":"birthdate","fn":["years_ago",["gte",18]]}}}

The JSON below is a formatted version of the content of the claims request parameter for readability.

java-oauth-server will return an authorization page like below as a response to the authorization request.

Authorization Page

An account for testing the latest IDA specification is inga (Login ID = inga, Password = inga). Verified claims of the account are loaded from document_800_63A.json and document_UKTDIF.json (that were copied from the examples/response directory in the eKYC-IDA Git repository).

If you input inga & inga to the Login ID & Password fields and press the “Authorize” button, the web browser will be redirected to the redirection endpoint hosted on java-oauth-server.

The JavaScript at the redirection endpoint displays information about the parameters the endpoint received. The page will look like below.

Information about Authorization Response

The payload part of the issued ID Token is as follows. You can confirm that data minimization and filtering worked and the transformed claims are contained in verified_claims/claims.

Finally

Because of complexity and instability, it is hard to keep pace with evolution of the OIDC4IDA specification. However, by using Authlete as a backend system of your OAuth/OIDC server, you can delegate the hard task to domain experts in Authlete, Inc.

Please contact Authlete if you need a high-quality and leading-edge implementation of OAuth, OpenID Connect, Financial-grade API, Identity Assurance and other related standard specifications.

--

--

Takahiko Kawasaki

Co-founder and representative director of Authlete, Inc., working as a software engineer since 1997. https://www.authlete.com/