This document proposes a standardized means for PFIs (Participating Financial Institution) to perform KYC (Know Your Customer) and issue a subsequent KCC (Known Customer Credential) on a DID (Decentralized Identifer) controlled by a retail customer for the purpose of providing financial services to that DID in accordance to regulatory requirements.
KCC (Known Customer Credential) is a VC (Verifiable Credential) which is intended to be utilized by a retail customer as proof of an actively compliant KYC verification.
The json schema for the KCC can be found here: KCC Schema. This schema defines the structure and requirements for a Known Customer Credential, ensuring all necessary information is included and correctly formatted.
In the financial industry, KYC (Know Your Customer) is term used to describe a set of policies, procedures, and processes that financial institutions use to determine the true identity of a customer, and assess the on-going risk that a customer poses to an organization during the life-time of a customer relationship. KYC typically encompasses:
Regulatory KYC requirements can vary by region with respect to the information that needs to be collected, the information that needs to be validated and verified, how long that information needs to be retained, and how often various aspects of KYC need to be repeated (e.g. sanctions screening, refreshing IDV, re-collecting source of funds information).
IDV (Identity Verification) is a critical component of KYC wherein the PII (Personally Identifying Information) collected from an individual is verified using third party resources. IDV often includes steps such as verification of a valid government-issued photo ID, liveness checks, and verification of user-submitted PII against authoritative databases.
Financial institutions often leverage IDV Vendors to streamline the IDV process.
Integration with IDV vendors happens in 1 of 2 ways:
[!IMPORTANT] The 2 styles of integration provide flexibility for PFI identity verification systems, but they don't impact Mobile Apps at all, as they have the same external behaviour.
This body of work is an extension of the work being done for tbDEX. In effect, this proposal considers the following as requirements:
Ensuring that this is possible is essential to reduce friction or pain points for financial institutions interested in providing liquidity on tbDEX.
This requirement is critical to the value proposition of using Verifiable Credentials within the context of KYC. Performing KYC has a non-negligible cost for financial institutions which can be drastically reduced by receiving the necessary PII in a format that has been provably verified by a trusted third party.
[!IMPORTANT] We will need to consider scenarios wherein an individual possesses one or more "Identity Wallet" mobile applications that store credentials
[!IMPORTANT] We will need to consider issuance to and presentation from identity wallets that did not initiate the flow
Necessitating that PII come in contact with an application's backend systems introduces undesired complexity for many use-cases (e.g. self-custodial wallets that wish to provide on/off-ramps to their users without owning customer relationships)
A PFI could be a bank that an individual already has an account with. In this scenario, The individual should be able to log in to their pre-existing account via webview vs. having to go through IDV again.
Interoperability is critical for the ecosystem as a whole. This is also an implied requirement in order to leverage credentials that are already being issued/presented using pre-existing standards
Concretely, the objective is to implement a solution that allows a mobile application to initiate an IDV flow with a PFI used to perform KYC that results in a Known Customer Credential issued by the PFI. This KCC can be presented by the holder to the PFI to utilize financial services (e.g. tbDEX value exchange)
As a means to provide clarity, many of the examples in this section will refer to an imaginary mobile application named Mobile App.
Mobile App is a mobile application that can be used by individuals to:
Mobile App acts as a self-custodial Identity Wallet that:
service
endpointsThis implementation involves 3 distinct participants that have different responsibilities:
The PFI operates an Issuer, implementing this protocol.
The Mobile app is responsible for:
[!NOTE] Triggered by the mobile app as a byproduct of initiating the IDV flow
The Web view is utilized to:
[!IMPORTANT] This implementation has chosen to use Web Views to render IDV flows for the following reasons:
- provides PFI with maximal flexibility as to how they collect Personal Information from an individual
- prevents Wallets / Mobile Apps from having to update source code in order to integrate with different PFIs
- establish a clear distinction between the application initiating the flow and a PFI
Financial service providers often perform KYC incrementally in response to customer's expressed intent to access services. For example, minimal upfront diligence on newly onboarded customers, followed by additional diligence when the customer's activity passes a threshold.
A KCC Issuer may define multiple KCC types to represent different levels of KYC diligence, and describe each with a Presentation Definition. Mobile Apps which hold a previously issued KCC may apply for new credentials to acquire a higher level KCC (see Initiate Application)
sequenceDiagram
actor A as Applicant
participant W as Webview
participant D as Mobile App
participant P as PFI
participant I as IDV
rect rgba(0, 0, 0, 0.1)
D->>+P: Initiate KCC application
Note right of I: Initiate Application
P-->>-D: IDV Request
end
rect rgba(0, 0, 0, 0.1)
D->>+W: Load URL
Note right of I: Collect IDV
A->>W: Provide identity data
W->>+I: Applicant identity data
deactivate W
end
rect rgba(0, 0, 0, 0.1)
D->>+P: Request KCC
Note right of I: Credential Issuance
P-->>-D: Issue KCC
end
PFI's can become publicly discoverable by advertising their IDV endpoint as a Service within their DID Document. In order to increase the likelihood of being discovered, the service
entry SHOULD include the following properties:
Property | Value |
---|---|
id |
MUST be equal to the DID URI with an appended idv fragment, example did:example:123#idv , therefore the service MAY be dereferenced. |
type |
IDV |
serviceEndpoint |
PFI's publicly addressable IDV endpoint for usage in Initiate Application. |
[!NOTE]
Decentralized discoverability is dependent upon whether the underlying verifiable registry of the selected DID Method is crawlable
The application flow is initiated with a SIOPv2 interaction that authenticates the applicant's DID.
sequenceDiagram
autonumber
participant W as Webview
participant D as Mobile App
participant P as PFI
D->>+P: GET
P->>P: Construct SIOPv2 Authorization Request
P-->>-D: SIOPv2 Authorization Request
D->>D: Construct SIOPv2 Authorization Response
D->>+P: SIOPv2 Authorization Response
P->>P: Construct IDV Request
P-->>-D: IDV Request
D->>D: Verify IDV Request
D->>W: Load URL in IDV Request
serviceEndpoint
specified in Discover Initiation Endpointresponse_uri
from the SIOPv2 Authorization RequestAn HTTP GET request begins the IDV and KCC issuance flow.
Query Parameter | Description | Required | References | Comments |
---|---|---|---|---|
presentation_definition_id |
The ID of a presentation definition describing the KCC to be issued. | n | Presentation Exchange 2.0.0 tbDEX Offering | If not provided, the PFI chooses which KCC to issue |
The response is a SIOPv2 Authorization Request.
Field | Description | Required | References | Comments |
---|---|---|---|---|
client_id |
The DID of the Relying Party (the PFI) | y | ||
scope |
What's being requested. 'openid' indicates ID Token is being requested | y | OIDC | |
response_type |
What sort of response the RP is expecting. MUST include id_token . MAY include vp_token |
y | OIDC | |
response_uri |
The URI to which the SIOPv2 Authorization Response will be sent | y | OID4VP | |
response_mode |
The mode in which the SIOPv2 Authorization Response will be sent. MUST be direct_post |
y | OID4VP | |
presentation_definition |
Used by PFI to request VCs as input to IDV process | n | OID4VP | If present, Response Type vp_token MUST also be present |
nonce |
A nonce which MUST be included in the ID Token provided in the SIOPv2 Authorization Response | y | ||
client_metadata |
A JSON object containing the Verifier metadata values | y | OIDC SIOPv2 |
Field | Description | Required | References | Comments |
---|---|---|---|---|
subject_syntax_types_supported |
Array of strings, each a DID method supported for the subject of ID Token | y | SIOPv2 | Example ["did:dht", "did:jwk"] |
client_name |
Human-readable string name of the client to be presented to the end-user during authorization | n | RFC7591 | |
client_uri |
URI of a web page providing information about the client | n | RFC7591 | |
logo_uri |
URI of an image logo for the client | n | RFC7591 | |
contacts |
Array of strings representing ways to contact people responsible for this client, typically email addresses | n | RFC7591 | |
tos_uri |
URI that points to a terms of service document for the client | n | RFC7591 | |
policy_uri |
URI that points to a privacy policy document | n | RFC7591 |
[!IMPORTANT] Include
vp_formats
in Client Metadata? https://openid.net/specs/openid-4-verifiable-presentations-1_0.html#section-9.1-2.2[!IMPORTANT] the inclusion of
presentation_definition
as per OID4VP allows for other verifiable credentials to be provided as input for IDV.
The SIOPv2 Authorization Request is encoded as a URI before being returned to Mobile App, as per SIOPv2. No authorization_endpoint
is used in the URI, so it is the query parameter portion of the URI only.
The Mobile App responds with a Cross-Device SIOPv2 Authorization Response.
Field | Description | Required | References | Comments |
---|---|---|---|---|
id_token |
A self issued, signed JWT which responds to the SIOPv2 Authorization Request | y | JWT SIOPv2 | |
vp_token |
A Verifiable Presentation or an array of VPs in response to presentation_definition |
n | OIDV4VP | |
presentation_submission |
A Presentation Submission that contains mappings between the requested VC and where to find them within vp_token |
n | OIDV4VP |
Field | Description | Required | References | Comments |
---|---|---|---|---|
iss |
Issuer MUST match the value of sub (Applicant's DID) |
y | ||
sub |
Subject. The DID of the customer applying for KCC | y | ||
aud |
Audience MUST match the value of client_id from the SIOPv2 Authorization Request (PFI's DID) |
y | ||
nonce |
Nonce MUST match the value of nonce from the SIOPv2 Authorization Request |
y | ||
exp |
Expiry time | y | ||
iat |
Issued at time | y |
The response is an IDV Request.
Field | Description | Required | References | Comments |
---|---|---|---|---|
url |
URL of form used to collect PII | y | Required for now until we figure out how to support exclusively providing credentials as input | |
credential_offer |
y | OID4VCI |
Field | Description | Required | References | Comments |
---|---|---|---|---|
credential_issuer |
The URL of the Credential Issuer that the Mobile App will interact with in subsequent steps | y | OID4VCI | |
credential_configuration_ids |
Array of unique strings that each identify a credential being offered. Mobile App can use these to request metadata | y | OID4VCI | |
grants |
Object containing Grant Types that the Credential Issuer will accept for this credential offer. MUST contain urn:ietf:params:oauth:grant-type:pre-authorized_code |
y | OID4VCI |
Field | Description | Required | References | Comments |
---|---|---|---|---|
urn:ietf:params:oauth:grant-type:pre-authorized_code |
Grant Type that allows the Mobile App to follow a Pre-Authorized Code Flow to collect the credential | y | OID4VCI |
Field | Description | Required | References | Comments |
---|---|---|---|---|
pre-authorized_code |
The code representing the Credential Issuer's authorization for the Mobile App to obtain a credential | y | OID4VCI |
[!WARNING] TODO: explain rationale behind providing
credential_offer
at this stage
The IDV Request sent to the Mobile App contains a url
field. The Mobile App MUST load this URL in an embedded
webview. The Applicant is guided through whatever steps are necessary to collect identity data and submit to the IDV
server. The webview MUST close itself when the application steps are complete.
[!IMPORTANT] Whether the PFI is utilizing an IDV vendor is entirely opaque from the originating mobile app's perspective.
sequenceDiagram
autonumber
actor A as Applicant
participant W as Webview
participant D as Mobile App
participant P as PFI
participant V as IDV Vendor
D->>W: Load URL
A->>W: Provide PII, Submit
W->>V: PII
V->>V: Process
V->>W: Callback URI or 200
W->>W: Close
sequenceDiagram
autonumber
actor A as Applicant
participant W as Webview
participant D as Mobile App
participant P as PFI
D->>W: Load URL
loop until 200 response
A->>W: Provide PII, Submit
W->>P: PII
P->>P: Process
P->>W: 200 or 400 with errors
end
W->>W: Close
Credential Issuance is an OID4VCI Pre-Authorized Code flow.
The pre-authorized_code
from the IDV Request can be exchanged for an Access Token via the Token Endpoint.
sequenceDiagram
autonumber
participant D as Mobile App
participant P as PFI
D->>+P: Fetch metadata
P-->>-D: Metadata
D->>+P: Request authorization
P-->>-D: Authorize
D->>+P: Issue credential
P-->>-D: Credential
Metadata resources are hosted by the Credential Issuer as a means of informing client's of endpoint locations, technical capabilities, feature support and (internationalized) display information.
Credential Issuers are required to set up a number of well known endpoints to facilitate authorization and credential issuance as follows.
URLs to retrieve both Credential Issuer Metadata and Authorization Server Metadata are dynamically constructed by the client using .well-known
URI's.
credential_issuer
+ /.well-known/openid-credential-issuer
credential_issuer
+ /.well-known/oauth-authorization-server
Where credential_issuer
originates from within the Credential Offer from within the IDV Request
The Credential Issuer Metadata informs clients of endpoint locations, technical capabilities, supported Credentials, and (internationalized) display information.
Field | Description | Required | References | Comments |
---|---|---|---|---|
credential_issuer |
URL of the Credential Issuer | y | OID4VCI | Same value as the credential_issuer within the Credential Offer |
credential_endpoint |
URL for the Credential Endpoint | y | OID4VCI | |
credential_configurations_supported |
Object which defines the specifics of the credentials being issued | y | OID4VCI |
credential_configurations_supported
The credential_configurations_supported
is an object which defines the specifics of the credentials being issued. The credential_configurations_supported
is a key/value object wherein each key corresponds to a value within the credential_configuration_ids
from the Credential Offer and the value is defined with the following fields.
Field | Description | Required | References | Comments |
---|---|---|---|---|
format |
Format for the given credential | y | OID4VCI | MUST be jwt_vc_json |
cryptographic_binding_methods_supported |
List of supported DID Methods | y | OID4VCI | MUST be ["did:web", "did:jwk", "did:dht"] |
credential_signing_alg_values_supported |
List of supported cryprographic signing algorithms | y | OID4VCI | MUST be EdDSA or ES256K |
proof_types_supported |
Object that describes the supported key proof | y | OID4VCI | MUST be {"jwt": {"proof_signing_alg_values_supported": ["EdDSA", "ES256K"]}} |
The Credential Issuer's Authorization Server Metadata informs clients of its endpoint locations and authorization server capabilities.
Field | Description | Required | References | Comments |
---|---|---|---|---|
issuer |
URL of then Credential Issuer | y | RFC8414 | Same value as credential_issuer |
token_endpoint |
URL for the Token Request | y | RFC8414 |
[!WARNING] TODO we need to consider additional fields, such as
authorization_endpoint
(once we support the Auth Flow) orresponse_types_supported
Clients must authorize with the Credential Issuer prior-to interfacing with the Issuance Endpoints as a means of authorizing the Credential Issuer access to the client resources created during the IDV phase.
Clients must request an access token in order to interface with the 3. Issuance Endpoints.
Field | Description | Required | References | Comments |
---|---|---|---|---|
grant_type |
y | OID4VCI | MUST be urn:ietf:params:oauth:grant-type:pre-authorized_code |
|
pre-authorized_code |
The value of pre-authorized_code from the Credential Offer |
y | OID4VCI | |
client_id |
The client DID | y | OID4VCI |
[!WARNING] TODO we only support pre-auth flow now, but once we support auth flow then
code
will be used instead ofpre-authorized_code
Clients must use the fields from token response in subsequent calls to the 3. Issuance Endpoints.
Field | Description | Required | References | Comments |
---|---|---|---|---|
access_token |
The access token granted | y | RFC6749 | access_token 's are Compact Serialized JWT's. |
token_type |
y | RFC6749 | MUST be bearer |
|
expires_in |
Seconds from issue until the access token expires | y | RFC6749 | |
c_nonce |
A nonce for use in the subsquent call to Credential Endpoint | y | OID4VCI | |
c_nonce_expires_in |
Seconds from issue until the c_nonce expires |
y | OID4VCI |
Additionally the token response MUST contain HTTP headers "Cache-Control: no-store" and "Pragma: no-cache" as per RC6749
[!WARNING] TODO we need to define error responses https://datatracker.ietf.org/doc/html/rfc6749#section-4.2.2.1
TODO including
authorization_pending
https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#name-token-error-responsethe `authorization_pending` occurs here, and is approved by
[!WARNING] TODO we need to define refresh token flows
access_token
JOSE HeaderThe access_token
granted by the Credential Issuer contains the following JOSE Header fields.
Field | Description | Required | References | Comments |
---|---|---|---|---|
alg |
(Algorithm) The cryptographic algorithm used to sign the JWT | y | RFC7515 | MUST be EdDSA or ES256K |
kid |
(KeyID) The fully qualified DID Key ID of the signer | y | RFC7515 | In the form did:{method}:{identifier}#{key_id} |
typ |
(Type) The explicit JWT type | y | RFC7515 | MUST be at+jwt per RFC9068 |
access_token
ClaimsThe access_token
granted by the Credential Issuer contains the following JWT Claim fields.
Field | Description | Required | References | Comments |
---|---|---|---|---|
iss |
(Issuer) The DID of the Authorization Server | y | RFC7519 | |
aud |
(Audience) The resource indicator (DID) of the Credential Issuer | y | RFC7519 | |
sub |
(Subject) The DID of the customer applying for KCC (Applicant DID) | y | RFC7519 | |
client_id |
(Client ID) The DID of the customer applying for KCC (Applicant DID) | y | RFC8693 | |
exp |
(Expiration) The time at which the access_token expires |
y | RFC7519 | |
iat |
(IssuedAt) The time at which the access_token was granted |
y | RFC7519 | |
jti |
(JWT ID) A unique identifier for the token | y | RFC7519 | |
c_nonce |
A nonce to be used in the Proof JWT | y | OID4VCI | |
c_nonce_expiry |
Expiry time of the c_nonce | y | OID4VCI |
Clients interface with the following endpoints as a means of acquiring the credential.
sequenceDiagram
autonumber
participant D as Mobile App
participant P as PFI
participant V as IDV Vendor
D->>+P: Credentials Request
P->>-D: txn_id
loop until credential received
D->>+P: Deferred Cred Request
P->>-D: issuance_pending
end
V->>+P: Webhook Request w. results
P->>P: evaluate results and Issue Credential or Reject
D->>P: Deferred Credential Request
P->>D: Credential Response w/ Credential
P->>-P: Invalidate preauth code
Clients use the Credential Request to request a credential.
The access_token
must be passed as an HTTP Authorization
header (i.e. Authorization: Bearer {access_token}
)
Field | Description | Required | References | Comments |
---|---|---|---|---|
format |
The format of the credential issued | y | OID4VCI | MUST be jwt_vc_json |
proof |
Proof of possession of cryptographic materials | y | OID4VCI |
proof
proof
is an object which contains proof of possession of the client's cryptographic materials.
Field | Description | Required | References | Comments |
---|---|---|---|---|
proof_type |
The type of proof | y | OID4VCI | MUST be jwt |
jwt |
The proof JWT | y | OID4VCI |
proof.jwt
JOSE HeadersFor the client to prove possession of their cryptographic materials, they must construct a JWT with the following JOSE Header fields.
Field | Description | Required | References | Comments |
---|---|---|---|---|
alg |
(Algorithm) The cryptographic algorithm used to sign the JWT | y | OID4VCI | MUST be EdDSA or ES256K |
typ |
(Type) The explicit JWT type | y | OID4VCI | MUST be openid4vci-proof+jwt |
kid |
(KeyID) The fully qualified DID Key ID of the signer | y | OID4VCI | In the form did:{method}:{identifier}#{key_id} |
proof.jwt
ClaimsFor the client to prove possession of their cryptographic materials, they must construct a JWT with the following JWT Claim fields.
Field | Description | Required | References | Comments |
---|---|---|---|---|
iss |
(Issuer) The DID of the customer applying for KCC (Applicant DID) | y | OID4VCI | |
aud |
(Audience) The DID of the Credential Issuer | y | OID4VCI | |
iat |
(IssuedAt) The time at which the key proof was created | y | OID4VCI | |
nonce |
The value of the c_nonce from the Token Response |
y | OID4VCI |
The Credential Issuer will respond to a Credential Request with either the credential (in jwt_vc_json
format) given the Credential Issuer is ready to issue, whereafter the credential may be used for the purpose of providing financial services to that DID in accordance to regulatory requirements, else, given the Credential Issuer is not ready to issue the credential, they must respond with a transaction_id
which is to be used in a subsequent call in the Deferred Credential Request.
Field | Description | Required | References | Comments |
---|---|---|---|---|
credential |
The credential in jwt_vc_json format |
n | OID4VCI | If missing, transaction_id must be present |
transaction_id |
ID used for subsequent call to Deferred Credential Request | n | OID4VCI | If missing, then credential must be present |
[!WARNING] TODO we need to define the c_nonce stuff for the deferred flow; right now
proof
is embedded under the Credential Request, but it's applicable against the deferred and batch credential requests
TODO
TODO
It may very well be the case that this approach works for identity verification in general even outside the purposes of performing KYC but it's far too early to say or have that discussion. Just something to keep in the back of our minds