How to implement OpenID Connect eKYC / Identity Assurance

Providers of verified identities are encouraged to adopt the new OpenID Connect extension for eKYC and Identity Assurance (eKYC / IdA). This guide explains how to configure your Connect2id server (v9.0+) and integrations for that. It assumes draft 09 of the specification.

1. Configuration

1.1 OpenID provider metadata

Configure the Connect2id server to advertise support for the eKYC / IdA extension, such as the available trust frameworks and the list of verified claims which can be requested by Relying Parties (RPs). This will also enable processing of verified claims requests in the authorisation session API of the Connect2id server.

Example configuration for eIDAS at level of assurance "High":

op.assurance.supportsVerifiedClaims=true
op.assurance.supportedTrustFrameworks=eidas_ial_high
op.assurance.supportedIdentityEvidenceTypes=qes
op.assurance.supportedVerifiedClaims=name,given_name,family_name,birthdate

2. Integration

How to update your authorisation session handler for verified claims:

  • Claims that are requested as verified by an RP will appear with verified: prefixed to their name in the usual consent prompt.

    For example, the following claims request

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

    will translate to a consent prompt similar to this:

    {
    "type"        : "consent",
    "sid"         : "g6f5K6Kf6EY11zC00errCf64yLtg9lLANAcnXQk2xUE",
    "display"     : "popup",
    "sub_session" : { ... },
    "client"      : { ... },
    "scope"       : { "new"       : [ "openid" ],
                      "consented" : [ ] },
    "claims"      : { "new"       : { "essential" : [ ],
                                      "voluntary" : [ "verified:given_name",
                                                      "verified:family_name",
                                                      "verified:birthdate" ] },
                      "consented" : { "essential" : [ ],
                                      "voluntary" : [ ] } }
    }
    
  • If the handler is capable it should also check for present verification metadata in the claims request, which may specify the desired trust framework (e.g. "eidas_ial_high"), identity proofing evidences and other parameters to the Identity Assurance process. The handler should at minimum ensure that if a particular trust framework is requested by the RP it is among the supported by the provider.

    Claims request by an RP according to the trust framework eIDAS at the identification assurance level "High":

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

    The verification metadata will appear in the consent prompt under claims.verification:

    {
    "type"        : "consent",
    "sid"         : "g6f5K6Kf6EY11zC00errCf64yLtg9lLANAcnXQk2xUE",
    "display"     : "popup",
    "sub_session" : { ... },
    "client"      : { ... },
    "scope"       : { "new"         : [ "openid" ],
                      "consented"   : [ ] },
    "claims"      : { "new"         : { "essential" : [ ],
                                        "voluntary" : [ "verified:given_name",
                                                        "verified:family_name",
                                                        "verified:birthdate" ] },
                      "consented"   : { "essential" : [ ],
                                        "voluntary" : [ ] },
                      "verification : { "userinfo" : { "trust_framework" : "eidas_ial_high" } } }
    }
    
  • If the RP has set the purpose parameter to explain why verification is being requested, the provider should display the message in the consent screen to the end-user.

    {
    "type"        : "consent",
    "sid"         : "g6f5K6Kf6EY11zC00errCf64yLtg9lLANAcnXQk2xUE",
    "display"     : "popup",
    "sub_session" : { ... },
    "client"      : { ... },
    "scope"       : { "new"       : [ "openid" ],
                      "consented" : [ ] },
    "claims"      : { "new"       : { "essential" : [ ],
                                      "voluntary" : [ "verified:given_name",
                                                      "verified:family_name",
                                                      "verified:birthdate" ] },
                      "consented" : { "essential" : [ ],
                                      "voluntary" : [ ] } },
    "purpose"     : "Required details for the insurance contract"
    }
    

    The RP can also attach a purpose message to each individual requested claim. The purpose strings will then appear in a the claims.purposes JSON object with claim name / purpose string pairs.

    Important: In order to prevent injection attacks all special characters in a purpose string must be escaped before shown in a user interface!

  • If you need access to the raw claims request in the consent prompt enable op.authz.includeRawClaimsRequestInPrompt.

    Alternatively, make a GET call for the authorisation session which will also return the OpenID authentication request and its "claims" parameter.

  • The consented verified claims are to be submitted by the handler in the usual claims parameter of the consent object. The name of each verified claims must be prefixed with verified: so that the claims source can distinguish the verified claims from the regular ones when composing the UserInfo object.

    Example consent for verified (name, address) and regular claims (email):

    {
    "scope"  : [ "openid" ],
    "claims" : [ "email", "verified:name", "verified:address" ]
    }
    
  • Update your Connect2id server claims source to detect if the list of the consented claims includes verified ones (marked with the verified: prefix), and put them into the verified_claims element, together with the necessary verification metadata, as shown in this example for the OpenID Connect SDK.

  • If the authorisation session handler needs to pass some data to the claims source when provisioning the actual claims, for example the verification element or even claim values, it can do so via the claims_data consent parameter.

    {
    "scope"       : [ "openid" ],
    "claims"      : [ "email",
                      "verified:name",
                      "verified:address" ]
    "claims_data" : { "trust_framework"      : "eidas_ial_high",
                      "time"                 : "2020-03-16T18:25Z",
                      "verification_process" : "f24c6f-6d3f-4ec5-973e-b0d8506f3bc7" }
    }
    

    The claims_data will be included in the issued access token (if the claims are to be delivered at the UserInfo endpoint). To keep the claims data confidential from the RP choose either an identifier access token encoding (access_token.encoding = IDENTIFIER in the consent) in the consent or if a self-contained (JWT) token is chosen it must be additionally encrypted (access_token.encrypt = true).

    An AdvancedClaimsSource SPI implementation can retrieve the claims data JSON object by a call to the ClaimsSourceRequestContext.getClaimsData method.

3. Future improvements

Connect2id server improvements which are being considered to further aid processing of eKYC / IdA requests:

  • An op.authz.includeRawClaimsRequestInPrompt setting to cause the raw claims request parameter to also be included in the authentication prompt. This will allow a provider which supports multiple levels of authentication assurance (ACR / LoA) to find out which one is appropriate for a verified claims request (in the absence of an acr_values request parameter or when it doesn't match the ACR required for verified claims).