OpenID Connect Identity Assurance / eKYC explained

The digital economy, despite its recent successes in online marketplaces and finance, cannot meaningfully evolve into new fields without easy, standard access to verified identities. This fundamental need inspired the eKYC / Identity Assurance extension to OpenID Connect. Applications and services can now use it to obtain verified person data and metadata.

1. Knowing your customer

For a transaction or contract to be valid and enforceable under the law one crucial criteria must always be fulfilled - the parties involved must be who they claim to be. This applies to all contracts, on paper as well as those made online.

One crude method to verify a customer's identity online has been to request a credit card or other payment method for validation. But this approach has assurance issues and limitations - in terms of reliably identifying the person, to which the reported annual global credit card fraud exceeding U$ 20 billion testifies, and in terms of what details can be checked, typically limited to the cardholder's name.

Depending on the type of transaction, perceived risk and government regulations to be met, such as anti-money laundering laws, a business may require a stronger and more adequate assurance of identity to conduct its transactions digitally and online.

2. Legal and contractual concerns in online transactions

Three concerns come up when businesses consider a shift to online transactions:

  • That the identity of the other party, such as legal name and being of legal age, is sufficiently verified to rest assured that the contract governing the transaction is valid and enforceable by law.

  • That other data crucial for the fulfillment of the contract, for example resident address, bank account number or credit score, is also verified.

  • That the business doesn't find itself involved in some fraud or money laundering scheme via the transaction, and is able to demonstrate it performed all due diligence, which involves verification of the customer identity and collecting other details where required.

A good scheme for Know Your Customer (KYC) and Identity Assurance (IdA) in general must cater for all three concerns.

The OpenID specification for eKYC / IdA was designed to tick all boxes regarding possible legal concerns of adopters, in jurisdictions around the world, in addition to being a protocol that can plug into existing OpenID Connect and OAuth 2.0 infrastructure like the Connect2id server.

3. OpenID Connect eKYC / IdA is an international effort of identity, privacy and security experts

The OpenID Connect eKYC / IdA standard is developed in a open working group at the OpenID Foundation, by experts in identity, privacy, and security, with the objective to make it universally useful in jurisdictions around the world.

As of January 2022 the specification has received contributions from experts from countries in Europe, Japan, the US, Canada and Australia.

4. Relationship to OpenID Connect

Those familiar with OpenID Connect will notice how seamless the integration of the eKYC / IdA extension is.

OpenID Connect has become the de-facto internet standard for single sign-on and identity provisioning. Client applications, called relying parties (RP), receive the user's identity in a digitally signed object called ID token. Additional details about the user, called claims, can also be requested and if consented and available the OpenID provider puts them up for retrieval in JSON or signed JWT format at its UserInfo endpoint, in exchange for an access token.

To support the provision of verified identities the core OpenID Connect protocol is extended in two places:

  • A verified_claims element is defined for the optional claims OpenID authentication request parameter.

  • A verified_claims element, or container, is defined for the ID token or UserInfo to return the verified claims and data about the verification itself.

5. How to request verified claims

A relying party requests verified claims via the existing claims OpenID authentication request parameter. The parameter takes the form of a JSON object and was originally designed to give an RP a way to signal whether a given claim should be returned in the issued ID token or at the UserInfo endpoint, and to set additional requirements and constraints.

Here is an example claims parameter for requesting the claims given_name, family_name and birthdate to be released at the UserInfo endpoint:

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

To request the same claims, but with assurance according to the default trust framework available at the identity provider, their names are put within a verified_claims element like this:

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

The provider can also be asked to return various data about the verification itself, encoded within the verification element. This will be explained later.

To request the verified claims to be returned in the issued ID token the top-level element is set to id_token:

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

The JSON object format allows requesting a mix of regular and verified claims, as well as mixing the two methods for their delivery - UserInfo and ID token. For example:

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

An example of a complete OpenID authentication request with an URL-encoded claims parameter:

https://c2id.com/login?
response_type=code
&scope=openid
&client_id=123
&state=ohngaisho4ad0Eef
&redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb
&claims=%7B%22userinfo%22%3A%7B%22verified_claims%22%3A%7B%22verification%22
 %3A%7B%22trust_framework%22%3Anull%2C%7D%2C%22claims%22%3A%7B%22given_name%22
 %3Anull%2C%22family_name%22%3Anull%2C%22birthdate%22%3Anull%7D%7D%7D%7D

When the request is submitted to the OpenID provider the usual steps of user authentication and consent will take place, and if they pass successfully, upon completion of the OAuth 2.0 code flow the relying party will receive its ID token and access token for the UserInfo endpoint.

6. Delivery of verified claims

If the requested verified claims were consented by the end-user and are actually available to the OpenID provider, they will be returned at the UserInfo endpoint and / or the ID token, as directed by the relying party. If a particular claim isn't consented or not available at the OpenID provider, it is simply omitted, i.e. this doesn't produce an error.

The claims in the UserInfo response and the ID token payload are delivered in a JSON object, keyed by their name.

Regular (non-verified) claims reside at the top-level of the JSON object, where sub is the unique identifier of the subject (end-user) at the OpenID provider:

{
  "sub"         : "478e4589-0145-42e2-a54e-bc291f9c7af3",
  "given_name"  : "Alice",
  "family_name" : "Adams",
  "birthdate"   : "1987-12-01"
}

Verified claims are put in a specially designated verified_claims element, which includes the provided claims in a claims sub-element, and requested details about the verification that took place in a verification sub-element. We'll talk more about latter in the next section.

{
  "sub": "478e4589-0145-42e2-a54e-bc291f9c7af3",
  "verified_claims": {
    "verification": {
       "trust_framework": "eidas"
    },
    "claims": {
      "given_name": "Alice",
      "family_name": "Adams",
      "birthdate": "1987-12-01"
    }
  }
}

The claims delivered at the UserInfo endpoint are normally returned as a plain JSON object, with the HTTP response having an application/json content type. The OpenID provider also has the option to return the UserInfo as a signed JSON Web Token (JWT), to assert that it vouches for the claims, and even apply additional encryption to the JWT, with a public key registered by the relying party, for additional confidentiality on top of that provided by the TLS layer in HTTPS. The HTTP content type will then be application/jwt.

7. Verification data

In addition to the mechanics for requesting and delivering verified claims, the OpenID Connect eKYC / IdA spec defines a verification JSON object to describe the underlying verification that took place. From this object a relying party can obtain contextual information, such as how the identity of the user was verified and what types of evidence were used. An RP can also ask to receive a transaction ID for dispute resolution and audit purposes.

The verification JSON object schema is over 500 lines long and quite rich, to cater for all anticipated trust framework requirements and scenarios. The OpenID Connect SDK maintained by Connect2id has received numerous updates to allow developers to construct, parse and process verification objects in a convenient and type-safe manner.

What details can go into the verification object?

This is governed by the trust framework. In eidas for instance there is no need to provide additional verification data. On the other hand, trust frameworks like de_aml which comply with anti-money laundering laws will typically require details about the identity evidences (ID card, passport, etc). In other words, a trust framework would establish its own JSON schema for the verification element, based on the generic one defined by the eKYC / IdA spec.

This is an overview of the verification element top-level structure:

Element Description
trust_framework

An official identifier for the trust framework. The existing claimed identifiers, like eidas and de_aml can be found in the de facto registry managed by the eKYC working group.

A framework will typically specify the claims that can be provided and what further elements are required or optional for the verification element, based on the underlying assurance that takes place and applicable regulations.

The eidas trust framework for instance is the European eIDAS scheme of approved providers, which is typically based on qualified electronic signatures and national eIDs. The minimum available attributes are name and birth date.

assurance_level

Identifier for the assurance level for the provided claims.

With eidas for instance the levels can be low, substantial and high.

Optional unless required by the trust framework.

assurance_process

Object describing the assurance process that was followed.

Optional unless required by the trust framework.

time

Timestamp, e.g. 2022-01-18T19:41:00Z when the verification took place.

Optional unless required by the trust framework.

verification_process

Unique identifier for the verification that took place, intended for dispute resolution and audits.

Optional unless required by the trust framework.

evidence

Information about the evidence(s) used to verify the identity of the end-user.

Five types of evidences are currently specified, each one expands to its own object with additional metadata:

  • document - Verification based on a physical or electronic document provided by the user, such as an ID card or passport.
  • electronic_record - Verification based on data from some approved source, such as a bank or population register.
  • vouch - Verification based on attestation given by some approved or recognised person.
  • utility_bill - Verification based on a utility bill.
  • electronic_signature - Verification based on a electronic signature.

An evidence can be supplemented with an attachment (embedded or referenced by secured URL), for example a scan of the original document. The use of attachments, their processing and storage is determined by the trust framework.

Optional unless required by the trust framework.

Example minimal verification object for an eIDAS (eidas) based verification:

{
  "trust_framework": "eidas"
}

With extra metadata - a timestamp and a unique identifier for the verification:

{
  "trust_framework": "eidas",
  "time": "2022-01-18T12:12:59Z",
  "verification_process": "6994ca5a-3615-4347-9062-c9037d847d3b"
}

Example verification object for a driving permit based verification according to the UK digital identity and attributes trust framework (uk_tfida), where physical in-person proofing has taken place. The driving permit details, such as issuer and validity, can be found under evidence[0].document_details:

{
  "trust_framework": "uk_tfida",
  "assurance_level": "medium",
  "assurance_process": {
      "policy": "gpg45",
      "procedure": "m1b"
  },
  "time": "2021-05-11T14:29Z",
  "verification_process": "7675d80f-57e0-ab14-9543-26b41fc22",
  "evidence": [
    {
      "type": "document",
      "validation_method": {
        "type": "vpiruv",
        "policy": "gpg45",
        "procedure": "score_3"
      },
      "verification_method": {
        "type": "pvp",
        "policy": "gpg45",
        "procedure": "score_3"
      },
      "time": "2021-04-09T14:12Z",
      "document_details": {
        "type": "driving_permit",
        "personal_number": "MORGA753116SM9IJ",
        "document_number": "MORGA753116SM9IJ35",
        "serial_number": "ZG21000001",
        "date_of_issuance": "2021-01-01",
        "date_of_expiry": "2030-12-31",
        "issuer": {
            "name": "DVLA",
            "country": "UK",
            "country_code": "GBR",
            "jurisdiction": "GB-GBN"
        }
      }
    }
  ]
}

How to request verification details?

When an OpenID provider returns verified claims it will by default return a minimal verification object that only indicates the trust framework, for example:

{
  "trust_framework": "uk_tfida"
}

This follows from the principles of privacy and data minimisation. Any other verification details available under the trust framework and which the RP deems essential to fulfill its purpose must be explicitly requested by the RP, and will be subjected to user consent just like the user claims.

The verification details are requested as part of the standard OpenID claims parameter, using the same established syntax for requesting regular and verified user claims:

  • To request a specific verification detail include its JSON member name, with the value set to null.
  • A verification detail can be constrained by specifying a value or a values array.
  • A max_age (in seconds) can be applied to verification details that represent times and timestamps.

Example claims request parameter where the relying party wishes to verify the user with eIDAS (note, the OpenID provider metadata can be queried in advance to find which trust frameworks it supports):

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

The above example where the RP also asks to receive details for the assurance level, the verification timestamp and an ID for audit purposes:

{
  "userinfo": {
    "verified_claims": {
      "verification": {
        "trust_framework": {
          "value": "eidas"
        },
        "assurance_level": null,
        "time": null,
        "verification_process": null
      },
      "claims": {
        "given_name": null,
        "family_name": null,
        "birthdate": null
      }
    }
  }
}

Example use of max_age (in seconds) to indicate the acceptable age of the verification (set to 1 month):

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

Relying party developers should note that an OpenID provider of verified claims may not support the value / values / max_age syntax, as those queries may be difficult to implement. But setting a preferred trust_framework when multiple are available should always work.

The eKYC / Identity Assurance working group is developing a more complex query syntax, featuring selective abort / omit syntax. This spec is still a raw draft and was originally intended to minimise verification expenses for RPs when essential claims cannot be fulfilled by the provider.

8. How to query OpenID provider support for verified claims

OpenID Connect providers expose a well-known endpoint where a JSON document, called OpenID provider metadata, is published. It lists its standard OAuth 2.0 / OpenID Connect server endpoints, capabilities and supported encryption algorithms. Developers of relying party applications use this metadata configure their software.

The URL of the endpoint is obtained by appending .well-known/openid-configuration to the issuer (base) URL of the provider, for example:

Issuer URL https://demo.c2id.com
OpenID provider metadata URL https://demo.c2id.com/.well-known/openid-configuration

Regular OpenID providers list the names of the end-user claims that are made available in the claims_supported parameter, which is a JSON array. Note that not all supported claims may be publicly listed by the OpenID provider, for privacy or other reasons.

The OpenID Connect for eKYC / IdA extends the metadata with additional parameters, to indicate if the provider supports verified claims, their names, the supported trust frameworks and other metadata that may be useful.

  • verified_claims_supported {true|false} Indicates support for OpenID Connect for Identity Assurance 1.0. If omitted the default value is false.

  • trust_frameworks_supported {string array} List of the supported trust frameworks if OpenID Connect for Identity Assurance 1.0 is supported, omitted or empty if none.

  • evidence_supported {string array} List of the evidence types if OpenID Connect Identity for Assurance 1.0 is supported, omitted or empty if none.

  • documents_supported {string array} List of the document types if OpenID Connect for Identity Assurance 1.0 is supported, omitted or empty if none.

  • documents_methods_supported {string array} List of the supported coarse identity verification methods for evidences of type document if OpenID Connect for Identity Assurance 1.0 is supported, omitted or empty if none.

  • documents_validation_methods_supported {string array} List of the supported validation methods for evidences of type document if OpenID Connect for Identity Assurance 1.0 is supported, omitted or empty if none.

  • documents_verification_methods_supported {string array} List of the supported person verification methods for evidences of type document if OpenID Connect for Identity Assurance 1.0 is supported, omitted or empty if none.

  • [ electronic_records_supported ] {string array} List of the supported electronic record types if OpenID Connect for Identity Assurance 1.0 is supported, omitted or empty if none.

  • [ claims_in_verified_claims_supported ] {string array} List of the supported verified claims if OpenID Connect for Identity Assurance 1.0 is supported, omitted or empty if none.

  • [ attachments_supported ] {string array} List of the supported attachment types (embedded, external) if OpenID Connect for Identity Assurance 1.0 is supported, empty if none.

  • [ digest_algorithms_supported ] {string array} List of the the supported digest algorithms for external attachments if OpenID Connect for Identity Assurance 1.0 is supported, omitted or empty if none. The "sha-256" algorithm is always supported for external external attachments.

An example snippet for an OpenID provider which supports verified claims under the eidas framework:

{
  "issuer"                              : "https://c2id.com",
  "userinfo_endpoint"                   : "https://c2id.com/userinfo",
  "claims_supported"                    : [ "email",
                                            "name",
                                            "given_name",
                                            "family_name",
                                            "birthdate" ],
  "verified_claims_supported"           : true,
  "trust_frameworks_supported"          : [ "eidas" ],
  "evidence_supported"                  : [ "electronic_signature" ],
  "claims_in_verified_claims_supported" : [ "name",
                                            "given_name",
                                            "family_name",
                                            "birthdate" ],
  ...
}

9. UI hints for the consent screen

A recent survey indicates customers abandon 53% of transactions online. After "lack of visible security", the second top reason is too much information being asked for.

In the spirit of data minimisation relying parties shouldn't request more than the necessary set of claims to perform the transaction. Conversion and the overall quality of the user experience increases when customers are in the clear why the particular details are being required.

The ekYC / IdA extension defines an optional parameter to the OpenID authentication request, called purpose, which lets the relying party explain why the verification is being requested. The provider is expected to display the message in the consent screen.

The extension goes a step further and even allows the relying party to give an explanation for each individual requested claim within the claims request parameter, for example:

{
  "userinfo": {
    "verified_claims": {
      "verification": {
        "trust_framework": null
      },
      "claims": {
        "address": {
          "essential": true,
          "purpose": "Required for insurance policy calculation"
        }
      }
    }
  }
}

10. Standard and custom claims

The OpenID Connect core specification and the eKYC / IdA extension define a number of standard claims.

Some useful OpenID Connect core claims in the context of eKYC / IdA:

  • name
  • given_name
  • middle_name
  • family_name
  • birthdate
  • address

Additional standard claims defined in eKYC / IdA:

  • place_of_birth (with sub-members country, region and locality)
  • nationalities
  • birth_family_name
  • birth_given_name
  • birth_middle_name
  • salutation
  • title
  • msisdn

When a provider needs to define a custom claim, the good practise is to prefix the claim name with a unique string, normally an URL based on the OpenID provider's issuer URL.

Example: https://claims.my-idp.com/iban

11. Verified claims support in the OpenID Connect SDK and the Connect2id server

The open source OAuth 2.0 / OpenID Connect SDK introduced support for verified claims in version 6.21, allowing those to be constructed and parsed with type safety and observing the schema for the verified_claims element.

The Connect2id server for single sign-on and identity provisioning introduced support for eKYC / IdA in release 8.0, which was upgraded to the latest implementers' draft in release 12.6.

12. Complementary security standards

To uphold a high standard of security against theft of PII providers of verified identities will typically require strong client authentication and access tokens with cryptographic protection against leaks and unauthorised replay. This can be obtained by utilising OAuth 2.0 mutual-TLS client authentication and certificate-bound access tokens (RFC 8705), which is incorporated in the FAPI security profile.

The mTLS extension and the FAPI profile are readily supported by the Connect2id server.

13. FAQ

13.1 Where is the complete specification?

The specification can be found on the page of the eKYC / IdA working group at the OpenID Foundation:

https://openid.net/wg/ekyc-ida/

13.2 Does the provision of verified identities according to this spec also imply any legal liability for them?

The provision of identities with eKYC by itself doesn't imply any legal liability about the "verified" quality of the claims, this must be governed by the service contract and its terms and conditions. Consult with a lawyer.


comments powered by Disqus