Identity Assurance — OpenID Connect in the eKYC era
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 ishttp://server.example.com
,sub
— the identifier of the user is248289761001
, andexp
— 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 Doegiven_name
— Janefamily_name
— Doegender
— femalebirthdate
— October 31email
—janedoe@example.com
picture
—http://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 purpose
s 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 purpose
s 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 purpose
s 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, purpose
s 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 purpose
s 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.