Identity Assurance — OpenID Connect in the eKYC era

Takahiko Kawasaki
18 min readDec 31, 2019

--

Introduction

Act on Prevention of Transfer of Criminal Proceeds was revised in Japan on November 30, 2018. The revision has added methods to verify identities of natural persons only through online and is now regarded as the legal basis for eKYC (electronic Know Your Customer).

On November 11, 2019, about one year after the revision, OpenID Foundation, a non-profit international standardization organization, published a technical document, Implementer’s Draft 1 of “OpenID Connect for Identity Assurance 1.0”. The organization also established a new working group, “eKYC and Identity Assurance WG”, soon after the publication. And, about half a year later, Implementer’s Draft 2 was published on May 19, 2020.

The revision of the Japanese law and the release of the new technical specification are independent events, but they have relevance as jp_aml, an identifier representing the Japanese law, has been defined and listed as a kind of trust frameworks in the specification (Trust Frameworks).

This article explains “OpenID Connect for Identity Assurance 1.0” that has emerged in the eKYC era. (Japanese version is here)

2020-May-31: This article was updated to follow the Implementer’s Draft 2.

2022-May-03: This article is out of date due to breaking changes introduced by Implementer’s Draft 3 (which was published in November 2021) and further breaking changes that will surely come in the next draft. Please read “OpenID Connect for Identity Assurance, explained by an implementer” (published on May 3, 2022) which is written based on the latest IDA specification.

1. OpenID Connect Review

Let’s start from reviewing prior knowledge needed to understand OpenID Connect for Identity Assurance 1.0 (“IDA” hereinafter) that is an extension of OpenID Connect (“OIDC” hereinafter).

1.1. ID Token and UserInfo Endpoint

OIDC is often explained as a technology related to user authentication. However, the fact is that “OpenID Connect Core 1.0”, the core specification of OIDC, does not define how users should be authenticated and leaves user authentication to implementations. That is, user authentication is out of scope.

The main goal of OIDC is to define a means to provide information about the result of user authentication and user attributes whereby the information can be verified later. To be concrete, OIDC has defined rules to issue an “ID token” (2. ID Token) that contains information about the result of user authentication and user attributes. As an ID token includes signature of its issuer, it is possible to verify the information the ID token holds later. See “Understanding ID Token” for details about ID tokens.

In addition, OIDC has defined “UserInfo Endpoint” (5.3. UserInfo Endpoint) that is an API which returns user information. A client application can get user information by accessing the UserInfo endpoint with an access token whose scope includes openid.

1.2. Claim

The format of ID tokens is JWT (RFC 7519), so an ID token seems just a meaningless random string as shown below (newlines are not included in actual ID tokens but this example includes them for readability),

eyJraWQiOiIxZTlnZGs3IiwiYWxnIjoiUlMyNTYifQ.ewogImlz
cyI6ICJodHRwOi8vc2VydmVyLmV4YW1wbGUuY29tIiwKICJzdWIiOiAiMjQ4
Mjg5NzYxMDAxIiwKICJhdWQiOiAiczZCaGRSa3F0MyIsCiAibm9uY2UiOiAi
bi0wUzZfV3pBMk1qIiwKICJleHAiOiAxMzExMjgxOTcwLAogImlhdCI6IDEz
MTEyODA5NzAsCiAibmFtZSI6ICJKYW5lIERvZSIsCiAiZ2l2ZW5fbmFtZSI6
ICJKYW5lIiwKICJmYW1pbHlfbmFtZSI6ICJEb2UiLAogImdlbmRlciI6ICJm
ZW1hbGUiLAogImJpcnRoZGF0ZSI6ICIwMDAwLTEwLTMxIiwKICJlbWFpbCI6
ICJqYW5lZG9lQGV4YW1wbGUuY29tIiwKICJwaWN0dXJlIjogImh0dHA6Ly9l
eGFtcGxlLmNvbS9qYW5lZG9lL21lLmpwZyIKfQ.rHQjEmBqn9Jre0OLykYNn
spA10Qql2rvx4FsD00jwlB0Sym4NzpgvPKsDjn_wMkHxcp6CilPcoKrWHcip
R2iAjzLvDNAReF97zoJqq880ZD1bwY82JDauCXELVR9O6_B0w3K-E7yM2mac
AAgNCUwtik6SjoSUZRcf-O5lygIyLENx882p6MtmwaL1hd6qn5RZOQ0TLrOY
u0532g9Exxcm-ChymrB4xLykpDj3lUivJt63eEGGN6DH5K6o33TcxkIjNrCD
4XB1CKKumZvCedgHHF3IAK4dVEDSUoGlH9z4pP_eWYNXvqQOjGs-rDaQzUHl
6cQQWNiDpWOl_lxXjQEvQ

but you can find the payload part is JSON by decoding it.

{
"iss": "http://server.example.com",
"sub": "248289761001",
"aud": "s6BhdRkqt3",
"nonce": "n-0S6_WzA2Mj",
"exp": 1311281970,
"iat": 1311280970,
"name": "Jane Doe",
"given_name": "Jane",
"family_name": "Doe",
"gender": "female",
"birthdate": "0000-10-31",
"email": "janedoe@example.com",
"picture": "http://example.com/janedoe/me.jpg"
}

Properties in the JSON are called “claims”. The JSON tells:

  • iss — the issuer of this ID token is http://server.example.com,
  • sub — the identifier of the user is 248289761001, and
  • exp — this ID token will expire on July 21, 2011 (1311281970).

Especially, note that the name claim and the subsequent claims are information about user attributes.

  • name — Jane Doe
  • given_name — Jane
  • family_name — Doe
  • gender — female
  • birthdate — October 31
  • emailjanedoe@example.com
  • picturehttp://example.com/janedoe/me.jpg

Basically, user attributes are managed by the issuer of the ID token. However, because in most cases the information has been registered by user themselves into the service run by the issuer, it is not sure that the information is correct. Therefore, it is not possible to regard user information in an ID token as correct as individual information managed by governmental organizations. This is one reason that needs IDA as an extension.

1.3. The claims Parameter

A client application can request particular claims to be embedded in an ID token and/or a UserInfo response when it makes an authorization request.

A simple way is to request claims roughly by using pre-defined scopes such as profile and email (5.4. Requesting Claims using Scope Values). Another way that is not so simple but enables to request even custom claims is to use the claims parameter (5.5. Requesting Claims using the “claims” Request Parameter). Because IDA uses the latter way, here we review the claims parameter.

The value of the claims parameter is JSON and its format is like the following:

{
"userinfo" : {
claims to be embedded in a UserInfo response
},
"id_token" : {
claims to be embedded in an ID token
}
}

The following is an example excerpted from Section 5.5 of OIDC Core 1.0.

{
"userinfo":
{
"given_name": {"essential": true},
"nickname": null,
"email": {"essential": true},
"email_verified": {"essential": true},
"picture": null,
"http://example.info/claims/groups": null
},
"id_token":
{
"auth_time": {"essential": true},
"acr": {"values": ["urn:mace:incommon:iap:silver"] }
}
}

This example indicates that the client application requests given_name, nickname, email, email_verified, picture and http://example.info/claims/groups claims for a UserInfo response and auth_time and acr claims for an ID token. (Note that the acr claim is, however, treated specially. See 5.5.1.1. Requesting the “acr” Claim for details.)

Basically, it is enough to list claims in the format of "{claim-name}":null in userinfo and id_token which are top-level properties in the JSON specified by the claims parameter. On the other hand, to add conditions, a JSON object that may contain essential, value and/or values should be given instead of null. See 5.5.1. Individual Claims Requests of OIDC Core 1.0 for details about the format.

We have finished reviewing the prior knowledge. The following chapter explains IDA itself.

2. IDA Specification

2.1. Output

An OpenID provider that supports IDA embeds verified_claims in ID tokens and/or UserInfo responses independently of other claims. The following is an example of UserInfo response excerpted from 6.5.2. UserInfo Response of the specification.

{
"sub": "248289761001",
"email": "janedoe@example.com",
"email_verified": true,
"verified_claims": {
"verification": {
"trust_framework": "de_aml",
"time": "2012-04-23T18:25:43Z",
"verification_process": "f24c6f-6d3f-4ec5-973e-b0d8506f3bc7",
"evidence": [
{
"type": "id_document",
"method": "pipp",
"time": "2012-04-22T11:30Z",
"document": {
"type": "idcard",
"issuer": {
"name": "Stadt Augsburg",
"country": "DE"
},
"number": "53554554",
"date_of_issuance": "2010-03-23",
"date_of_expiry": "2020-03-22"
}
}
]
},
"claims": {
"given_name": "Max",
"family_name": "Meier",
"birthdate": "1956-01-28"
}
}
}

In this example, email and email_verified are traditional claims because they are put outside verified_claims. On the other hand, given_name, family_name and birthdate claims are treated differently and put inside (claims of) verified_claims. Claims treated differently in this way are called “verified claims”.

The verification property in verified_claims tells that the verified claims have been obtained from an ID card (number = 53554554, date of issuance = March 23, 2010, date of expiry = March 22, 2020) which was issued by Augsburg City in Germany. In addition, it tells that the verification process and the assurance level are based on German Anti-Money Laundering Law (de_aml) and that the identity document has been verified through physical in-person proofing (pipp).

If a company that provides eKYC service which is based on Japanese Act on Prevention of Transfer of Criminal Proceeds (jp_aml) and uses supervised remote in-person proofing (sripp) to verify identity documents implements IDA, ID tokens and UserInfo responses generated by the company’s OpenID provider will include verified_claims like the following.

"verified_claims": {
"verification": {
"trust_framework": "jp_aml",
......
"evidence": [
{
"type": "id_document",
"method": "sripp",
......
}
]
},
"claims": {
......
}
}

2.2. How to Request Verified Claims

Verified claims can be requested by adding verified_claims directly under userinfo and/or id_token properties in the JSON specified by OIDC’s claims parameter. The following is the first example shown in 5.1. Requesting End-User Claims.

{
"userinfo":{
"verified_claims":{
"verification": {
"trust_framework": null
},
"claims":{
"given_name":null,
"family_name":null,
"birthdate":null
}
}
}
}

This example requests that given_name, family_name and birthdate be embedded in a UserInfo response as verified claims.

To add conditions as done for traditional claims, a JSON object should be used as values for verified claims instead of null. The following example sets "essential":true to given_name and family_name using the same way as is defined in 5.5.1 Individual Claims Requests of OIDC Core 1.0.

{
"userinfo":{
"verified_claims":{
"verification": {
"trust_framework": null
},
"claims":{
"given_name":{"essential": true},
"family_name":{"essential": true},
"birthdate":null
}
}
}
}

2.2.1. purpose

IDA has added purpose as an extension to the traditional set of conditions (essential, value and values). Client applications may use purpose for each verified claim to describe the purpose of requesting the claim. In the following example, purpose is set to given_name and birthdate.

{
"userinfo":{
"verified_claims":{
"verification": {
"trust_framework": null
},
"claims":{
"given_name":{
"essential":true,
"purpose":"To make communication look more personal"
},
"family_name":{
"essential":true
},
"birthdate":{
"purpose":"To send you best wishes on your birthday"
}
}
}
}
}

The specification requires that the number of characters of purpose, if it is present, be in the range from 3 to 300. Also, the OpenID provider implementation must display purposes in the consent screen.

2.2.2. All Verified Claims

The Implementer’s Draft 1 has a special rule where "claims":null is interpreted as a request for all possible claims (while the specification requires "claims":{} be handled as invalid_request).

{
"userinfo":{
"verified_claims":{
"claims":null
}
}
}

However, this rule was removed from the Implementer’s Draft 2. In the latest specification, all the following cases are treated as errors: (a) "claims" is null, (b) "claims" is empty ({}), and (c) "claims" is missing.

2.3. Requirements for Identity Verification

In IDA, client applications may set detailed requirements for identity verification as well as for verified claims. The following example excerpted from 5.2. Requesting Verification Data requests trust_framework and time.

{
"userinfo": {
"verified_claims": {
"verification": {
"trust_framework": null,
"time":null
},
"claims": {
"give_name": null,
"family_name": null,
"birthdate": null
}
}
}
}

The most complex example in the specification is the one shown in 5.3. Defining constraints on Verification Data as follows.

{
"userinfo":{
"verified_claims": {
"verification": {
"trust_framework": {
"value": "de_aml"
},
"evidence": [
{
"type": {
"value": "id_document"
},
"method": {
"value": "pipp"
},
"document": {
"type": {
"values": [
"idcard",
"passport"
]
}
}
}
]
},
"claims": {
"given_name": null,
"family_name": null,
"birthdate": null
}
}
}
}

This example requests verified claims that have been obtained from an ID card (idcard) or a passport (passport) which was verified through physical in-person proofing (pipp) based on German Anti-Money Laundering Law (de_aml).

The syntax has been extended for the nested structure of verified_claims. That is, while leaf nodes (such as trust_framework and method) take a traditional JSON object that may contain essential, value and values, inner nodes (such as evidence and document) have the same layered structure (when the value is not null) as corresponding properties in the output do.

2.3.1. max_age

IDA allows date-type and datetime-type leaf nodes under verification to have max_age as well as traditional essential, value and values. The following is an example in 5.3.2. max_age.

{
"userinfo": {
"verified_claims": {
"verification": {
"trust_framework": {
"value": "jp_aml"
},
"time": {
"max_age": 63113852
}
},
"claims": {
"given_name": null,
"family_name": null,
"birthdate": null
}
}
}
}

The max_age in the example means that “the verification process of the data is not allowed to be older than 63113852 seconds.”

The specification says that max_age is “applicable to claims that contain dates or timestamps.” However, it is not so clear how max_age should be interpreted when it is specified to the following claims.

  • verification/time
  • verification/evidence/type=id_document/time
  • verification/evidence/type=id_document/document/date_of_issuance
  • verification/evidence/type=id_document/document/date_of_expiry
  • verification/evidence/type=qes/created_at
  • verification/evidence/type=utility_bill/date

For each claim above, it should be discussed whether requesting max_age has a meaning or not and how it should be interpreted in case it is specified, and the result of the discussion should be explicitly written in the specification (Issue 1139).

2.4. Transaction-specific Purpose

IDA has added a new request parameter, purpose (8. Transaction-specific Purpose). It is different from purpose for each verified claim explained in “2.2.1 purpose” above. The request parameter is used to describe the purpose for the transfer of user data the client application is asking for.

On the other hand, requirements imposed on the purpose request parameter is the same as are imposed on the purpose property for verified claims. That is, when the purpose request parameter is included in an authorization request, the number of characters must be in the range from 3 to 300 and it must be displayed in the consent screen.

2.5. Pre-defined Values

Some identifiers are pre-defined in IDA as listed below. These values can be found in the “ekyc-ida / identifiers” page of the Wiki of the eKYC-IDA Working Group.

Trust Frameworks

  • de_aml
  • eidas_ial_substantial
  • eidas_ial_high
  • nist_800_63A_ial_2
  • nist_800_63A_ial_3
  • jp_aml
  • jp_mpiupa
  • cz_aml

Identity Documents

  • idcard
  • passport
  • driving_permit
  • de_idcard_foreigners
  • de_emergency_idcard
  • de_erp
  • de_erp_replacement_idcard
  • de_idcard_refugees
  • de_idcard_apatrids
  • de_certificate_of_suspension_of_deportation
  • de_permission_to_reside
  • de_replacement_idcard
  • jp_drivers_license
  • jp_residency_card_for_foreigner
  • jp_individual_number_card
  • jp_permanent_residency_card_for_foreigner
  • jp_health_insurance_card
  • jp_residency_card

Verification Methods

  • pipp
  • sripp
  • eid
  • uripp

2.6. Metadata

An OpenID provider that supports IDA has the following metadata (7. OP Metadata).

  • verified_claims_supported — [boolean] whether IDA is supported or not.
  • trust_frameworks_supported — [string array] supported trust frameworks.
  • evidence_supported — [string array] supported identity evidence.
  • id_documents_supported — [string array] supported identity documents.
  • id_documents_verification_methods_supported — [string array] supported verification methods for identity documents.
  • claims_in_verified_claims_supported — [string array] supported verified claims.

3. IDA Implementation

IDA is not a technical specification that defines how to do KYC. Instead, it defines how to embed information obtained through KYC in ID tokens and UserInfo responses. Therefore, you cannot start KYC business only by implementing IDA. Rather, what is expected is that companies and governmental organizations that have already operated KYC as business or a part of service will implement IDA in order to expand their business and improve their services.

Solutions that support IDA are listed in the “ekyc-ida / implementations” page of the Wiki.

In the remaining part of this chapter explains how to implement IDA using Authlete. Note that IDA is supported by Authlete 2.2 onwards. Please contact Authlete, Inc. for details.

3.1. Flow

Being different from competitors’ products, Authlete is not an OpenID provider implementation but an API server that runs behind an OpenID provider. Therefore, it is Authlete’s customers themselves who implement an OpenID provider. (Sample open-source OpenID provider implementations are available in Java (java-oauth-server), C# (csharp-oauth-server), PHP (authlete-php-laravel), Python (django-oauth-server) and Go (gin-oauth-server).)

Compared to other OAuth and OIDC specifications, steps conducted on Authlete side for IDA are light, and steps conducted on OpenID provider side are relatively heavy.

The diagram below shows what an OpenID provider does and what Authlete does for IDA.

Points in the flow to be noted are as follows.

OpenID Provider : Authorization Endpoint

If Authlete is used to implement an OpenID provider, the implementation of the authorization endpoint of the OpenID provider delegates verification of authorization requests to Authlete’s /api/auth/authorization API.

Authlete : /api/auth/authorization API

Authlete’s /api/auth/authorization API checks if verified_claims included in the authorization request conforms to the specification. If an error is detected here, the response from the API (AuthorizationResponse) includes "action":"BAD_REQUEST". If the implementation on the OpenID provider side is correct, an error is returned to the client application.

OpenID Provider : Consent Screen Generation

The OpenID provider generates a consent screen based on the information returned from the /api/auth/authorization API. The response from the API includes information about not only the client name and requested scopes but also the value of the purpose request parameter and the values of userinfo and id_token that may be included in the claims request parameter.

As explained in “2.4. Transaction-specific Purpose” and “2.2.1. purpose”, the OpenID provider must display the value of the purpose request parameter and purposes of verified claims in the consent screen. It is easy to extract the value of the purpose request parameter from the API response. On the other hand, to extract purposes of verified claims, the OpenID provider must parse verified_claims in userInfoClaims and idTokenClaims and go down some layers of the JSON.

The open-source authlete-java-common library provides VerifiedClaimsContainerConstraint class to help process verified_claims in userInfoClaims and idTokenClaims. With the class, purposes of verified claims can be extracted as follows.

// A response from the /api/auth/authorization API
AuthorizationResponse res = ...;
// "userinfo" in the 'claims' request parameter of the
// authorization request. If the request does not include the
// 'claims' request parameter or if "userinfo" is not included
// in the JSON or its value is null, userInfoClaims becomes null.
String userInfoClaims = res.getUserInfoClaims();
if (userInfoClaims == null)
{
// No further processing is needed because "userinfo" is
// not available.
return;
}
// Parse "verified_claims" that may be included in "userinfo".
// Even if "userinfo" does not include "verified_claims",
// verifiedClaimsConstraint does not become null.
VerifiedClaimsConstraint verifiedClaimsConstraint =
VerifiedClaimsContainerConstraint.fromJson(userInfoClaims)
.getVerifiedClaims();
// If "userinfo" does not include "verified_claims" or its
// values is null.
if (!verifiedClaimsConstraint.exists() ||
verifiedClaimsConstraint.isNull())
{
// No further processing is needed because "verified_claims"
// is not available.
return;
}
/* NOTE: Because the Implementer's Draft 2 has dropped the
special meaning of the case where "claims" is null,
this 'if' is commented out.
// If "verified_claims" does not include "claims" or its value
// is null, it is interpreted as "all possible verified claims
// are request".
if (verifiedClaimsConstraint.isAllClaimsRequested())
{
// All verified claims are requested. In this case,
// "claims" is null and verified claims are not listed
// in "claims". Therefore, there is no need to extract
// purposes of verified claims.
return;
}
*/
// VerifiedClaimsConstraint.getClaims() returns an instance
// of ClaimsConstraint class.
ClaimsConstraint claimsConstraint =
verifiedClaimsConstraint.getClaims();
// Because ClaimsConstraint extends LinkedHashMap, methods
// defined in Map interface can be used.
for (Map.Entry<String, VerifiedClaimConstraint> entry
: claimsConstraint.entrySet())
{
// The name of the requested verified claim.
String claimName = entry.getKey();
// The value of "purpose".
String purpose = entry.getValue().getPurpose();
......
}

The process in the code above is written in AuthorizationPageModel.java in the authlete-java-jaxrs library (which is not authlete-java-common). Note that any code which parses verified_claims cannot be found in the source tree of java-oauth-server (a sample OpenID provider implementation) because java-oauth-server generates the consent screen using the AuthorizationPageModel class.

OpenID Provider : verified_claims Generation (for ID Token)

After obtaining consent from the user, the OpenID provider generates tokens and returns an authorization response which includes the tokens to the browser. If the OpenID provider is implemented using Authlete, the OpenID provider calls Authlete’s /api/auth/authorization/issue API to generate tokens and an authorization response.

A claims parameter can be passed to the /api/auth/authorization/issue API. If the optional parameter is given, the JSON specified by the parameter is merged into an ID token being generated in cases where the authorization flow generates an ID token (= when response_type of the authorization request includes id_token or when response_type includes code and scope includes openid).

An OpenID provider that supports IDA prepares JSON that contains verified_claims and optionally other normal claims and passes the JSON as the value of the claims request parameter to the /api/auth/authorization/issue API.

To help generation of verified_claims, the authlete-java-common library provides com.authlete.common.assurance package. For higher affinity for other JSON libraries, classes under the package extend LinkedHashMap or ArrayList.

For example, with the classes under com.authlete.common.assurance package, the JSON shown below

{
"email": "max@example.com",
"verified_claims": {
"verification": {
"trust_framework": "de_aml",
"evidence": [
{
"type": "id_document",
"method": "pipp",
"document": {
"type": "idcard",
"issuer": {
"name": "Stadt Augsburg",
"country": "DE"
},
"number": "53554554",
"date_of_issuance": "2012-04-23",
"date_of_expiry": "2022-04-22"
}
}
]
},
"claims": {
"given_name": "Max",
"family_name": "Meier"
}
}
}

can be generated by the following code.

Map<String, Object> claims = new LinkedHashMap<String, Object>();

// "email": "max@example.com",
claims.put("email", "max@example.com");

// "verified_claims": {
claims.put("verified_claims", new VerifiedClaims()
// "verification": {
.setVerification(new Verification()
// "trust_framework": "de_aml",
.setTrustFramework("de_aml")
// "evidence": [ {
.addEvidence(
// "type": "id_document",
new IDDocument()
// "method": "pipp",
.setMethod("pipp")
// "document": {
.setDocument(new Document()
// "type": "idcard",
.setType("idcard")
// "issuer": {
.setIssuer(new Issuer()
// "name": "Stadt Augsburg",
.setName("Stadt Augsburg")
// "country": "DE"
.setCountry("DE")
// }
)
// "number": "53554554",
.setNumber("53554554")
// "date_of_issuance": "2012-04-23",
.setDateOfIssuance("2012-04-23")
// "date_of_expiry": "2022-04-22"
.setDateOfExpiry("2022-04-22")
// }
)
// }
)
// ] },
)
// "claims": {
.setClaims(new Claims()
// "given_name": "Max",
.putClaim("given_name", "Max")
// "family_name": "Meier"
.putClaim("family_name", "Meier")
// }
)
// }
);

// Convert to JSON
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String json = gson.toJson(claims);

If your implementation uses AuthorizationDecisionHandler to call the /api/auth/authorization/issue API as java-oauth-server does, the getVerifiedClaims(String, VerifiedClaimsConstraint) method of the AuthorizationDecisionHandlerSpi interface is called if id_token is included in the claims request parameter of the authorization request. To embed verified_claims in the ID token, return a List of VerifiedClaims instances from the implementation of the method.

OpenID Provider : UserInfo Endpoint

If Authlete is used to implement an OpenID provider, the implementation of the UserInfo endpoint of the OpenID provider extracts an access token from the UserInfo request and passes it to Authlete’s /api/auth/userinfo API.

Sample resource server implementations that include a UserInfo endpoint implementation are available in Java (java-resource-server), C# (csharp-resource-server), Python (django-resource-server) and Go (gin-resource-server). PHP version is included in authlete-php-laravel.

Authlete : /api/auth/userinfo API

Authlete’s /api/auth/userinfo API validates the given access token. If the access token is invalid due to expiration, missing the openid scope, or other reasons, the API returns other responses than "action":"OK". On the other hand, if the access token is valid, the API returns information about the access token with "action":"OK".

OpenID Provider : verified_claims Generation (for UserInfo Response)

Based on the information included in the response from the /api/auth/userinfo API, the OpenID provider prepares information that should be included in the UserInfo response and calls the /api/auth/userinfo/issue API.

Among pieces of information included in the response from the /api/auth/userinfo API, the important one for IDA is userInfoClaims. This is the same as the userInfoClaims in the response from the /api/auth/authorization API. That is, the userInfoClaims parameter represents userinfo in the claims request parameter of the authorization request which had been made for the access token.

Like in “OpenID Provider : verified_claims Generation (for ID Token)”, the OpenID provider prepares JSON that includes verified_claims and optionally other normal claims and passes the JSON to the /api/auth/userinfo/issue API as the value of the claims request parameter.

If your implementation uses UserInfoRequestHandler to call the /api/auth/userinfo/issue API as java-resource-server does, the getVerifiedClaims(String, VerifiedClaimsConstraint) method of the UserInfoRequestHandlerSpi interface is called if userinfo is included in the claims request parameter of the authorization request. To embed verified_claims in the UserInfo response, return a List of VerifiedClaims instances from the implementation of the method.

3.2. Metadata for IDA

The Web console for Authlete API server that supports IDA provides “Identity Assurance” tab to edit metadata related to IDA.

3.3. Snapshots of IDA Implementation

3.3.1. Consent Screen

The screenshot above is the consent screen generated by java-oauth-server (a sample OpenID provider implementation) for an authorization request that includes the purpose request parameter with the value my_purpose and the claims request parameter with the JSON shown below.

{
"id_token": {
"verified_claims": {
"claims": null
}
},
"userinfo": {
"verified_claims": {
"claims": {
"given_name": {
"essential": true,
"purpose": "To make communication look more personal"
},
"family_name": {
"essential": true
},
"birthdate": {
"purpose": "To send you best wishes on your birthday"
}
}
}
}
}

The consent screen has “Identity Assurance” section and the section shows the value of the purpose request parameter and purposes of requested verified claims.

Note that the screenshot and the JSON above were prepared based on the Implementer’s Draft 1. Therefore, "claims":null is interpreted as “all possible claims”. However, since Implementer’s Draft 2, "claims":null is treated as an error.

3.3.2. ID Token

The screenshot above is the page displayed by the development-purpose redirection endpoint. "verified_claims" is included in the payload part of the ID token.

3.3.3. UserInfo Endpoint

In the screenshot of a terminal above, a UserInfo request is sent to the UserInfo endpoint (/api/userinfo) of java-resource-server (a sample resource server implementation) and a UserInfo response that includes "verified_claims" is returned.

3.3.4. Discovery Endpoint

The screenshot above is a part of the content returned from /.well-known/openid-configuration (OIDC Discovery 1.0 Section 4.1) of java-oauth-server (a sample OpenID provider implementation). Metadata related to IDA such as trust_frameworks_supported are included.

Finally

The first version of “OpenID Connect for Identity Assurance 1.0” was published a bit hastily because it was needed as a prerequisite to establish “eKYC and Identity Assurance Working Group”. Therefore, the specification included typos and errors (PR#1) in main paragraphs and examples, and even in the JSON schema whose aim is to help automatic validation on JSON documents containing a verified_claims element. It was good to see that the second version was released with many corrections about half a year later. The working group is working actively. Please watch ekyc-ida’s mailing list and issue list for further updates.

If you are interested in expanding your business and improving your services by utilizing OpenID Connect for Identity Assurance 1.0, please contact Authlete, Inc.

--

--

Takahiko Kawasaki
Takahiko Kawasaki

Written by Takahiko Kawasaki

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

Responses (3)