04 Advanced Credential Interactions
In this guide, we'll look at credential interactions involving e.g. presentation of a different credential by a holder before a credential issuance.
Interactions with EUDI Reference Wallet
EUDI Reference Wallet does not support the OpenID extension of OAuth 2.0 Authorization.
Therefore, the openid authentication with either id_token or vp_token is unsupported.
To issue credentials into an EUDI Wallet, you need to set the authorization field of wallet config to one of these values:
none: Use this value when the issuer will only issue credentials with Pre-Authorized Credential OffersoauthNoAuth: This option uses a mock authorization server that always authorizes the caller. Use only for testingoauthCustom: Use this option with a custom authentication provider. More information here.
Here are examples of issuer definitions using the first two options. The oauthCustom option is explained in more details here.
- No Authorizarion
- OAuth Mock Authorization
{
"name": "Identity Card",
"id": "id_card",
"signingKeyIdentifier": "x509",
"authorization": "none",
"credentialFormat": "sd_jwt_vc",
"credentialIssuer": "IssuanceQueue",
"credentialType": "urn:identity_card",
"disclosableClaims": [
"$.family_name",
"$.given_name"
]
}
{
"name": "Identity Card",
"id": "id_card",
"signingKeyIdentifier": "x509",
"authorization": "oauthNoAuth",
"credentialFormat": "sd_jwt_vc",
"credentialIssuer": "IssuanceQueue",
"credentialType": "urn:identity_card",
"disclosableClaims": [
"$.family_name",
"$.given_name"
]
}
Filling credential claims from a presentation
For this use-case, we'll use a wallet with the following configuration:
{
"trustFramework": "NOOP",
"walletKeyIdentifier": "did",
"credentialIssuers": [
{
"id": "poa",
"name": "Power of Attorney",
"credentialFormat": "jwtimport { Mermaid } from 'mdx-mermaid/Mermaid'_vc_vcdm",
"credentialIssuer": "VPDriven",
"credentialType": "VerifiableCredential,PowerOfAttorney",
"issuerConfiguration": {
"credentialVerifierId": "national_id_identity_disclosure",
"mapping": {
"$.[0].firstName": "$.firstName",
"$.[0].familyName": "$.familyName",
"$.[0].dateOfBirth": "$.dateOfBirth"
}
}
}
],
"credentialVerifiers": [
{
"id": "passport_full_disclosure",
"name": "Passport Full Disclosure",
"presentationDefinition": {
"id": "national_id_identity_disclosure",
"name": "National ID",
"presentationDefinition": {
"format": {
"jwt_vc": {
"alg": ["ES256"]
},
"jwt_vp": {
"alg": ["ES256"]
}
},
"id": "national_id_identity_disclosure_presentation",
"input_descriptors": [
{
"id": "national_id",
"constraints": {
"fields": [
{
"name": "National ID",
"filter": {
"const": "urn:national_id",
"type": "string"
},
"path": ["$.vct"]
},
{
"name": "Photo",
"path": ["$.photo"]
},
{
"name": "First Name",
"path": ["$.firstName"]
},
{
"name": "Family Name",
"path": ["$.familyName"]
},
{
"name": "Date of Birth",
"path": ["$.dateOfBirth"]
},
{
"name": "Nationality",
"path": ["$.nationality"]
}
]
}
}
]
}
}
}
],
"oidcRevision": {
"oidc4vci": "Draft15",
"oidc4vp": "Draft23"
}
}
The credential verifier uses a DIF Presentation Exchange Presentation Definition,
which will match a credential of type urn:national_id and disclose the claims photo, firstName, familyName, dateOfBirth and nationality.
The credential issuer will map the values firstName, familyName and dateOfBirth of the presented credential to the credential that will be issued.
In this case, the code stays the same as in a typical interaction.
Note: This interaction (and all following interactions) only work with in-time authorized credential issuance flow.
Verifying a Credential Presentation before Issuing a Credential
For this use-case, we'll consider the following wallet configuration:
{
"trustFramework": "NOOP",
"walletKeyIdentifier": "did",
"credentialIssuers": [
{
"id": "poa",
"name": "Power of Attorney",
"credentialFormat": "jwt_vc_vcdm",
"credentialIssuer": "CredentialRequirements",
"credentialType": "VerifiableCredential,PowerOfAttorney",
"issuerConfiguration": {
"credentialVerifierId": "national_id_identity_disclosure"
}
}
],
"credentialVerifiers": [
{
"id": "passport_full_disclosure",
"name": "Passport Full Disclosure",
"presentationDefinition": {
"id": "national_id_identity_disclosure",
"name": "National ID",
"presentationDefinition": {
"format": {
"jwt_vc": {
"alg": ["ES256"]
},
"jwt_vp": {
"alg": ["ES256"]
}
},
"id": "national_id_identity_disclosure_presentation",
"input_descriptors": [
{
"id": "national_id",
"constraints": {
"fields": [
{
"name": "National ID",
"filter": {
"const": "urn:national_id",
"type": "string"
},
"path": ["$.vct"]
},
{
"name": "Photo",
"path": ["$.photo"]
},
{
"name": "First Name",
"path": ["$.firstName"]
},
{
"name": "Family Name",
"path": ["$.familyName"]
},
{
"name": "Date of Birth",
"path": ["$.dateOfBirth"]
},
{
"name": "Nationality",
"path": ["$.nationality"]
}
]
}
}
]
}
}
}
],
"oidcRevision": {
"oidc4vci": "Draft15",
"oidc4vp": "Draft23"
}
}
In order to specify required values of credential fields, the call to CredentialIssuanceInit needs to be modified.
The following example will require field firstName to have the value John and field familyName to have the value Doe.
- Go
- TypeScript
firstNameVal := wallet.FieldsToVerify_Value{}
_ = firstNameVal.FromFieldToVerifyString("John")
familyNameVal := wallet.FieldsToVerify_Value{}
_ = familyNameVal.FromFieldToVerifyString("Doe")
requirements := &wallet.IssuanceRequirementsToVerify{
VerifiedFields: []wallet.FieldsToVerify{
{
Path: "$.firstName",
Value: firstNameVal,
},
{
Path: "$.familyName",
Value: familyNameVal,
},
},
}
issInitResp, err := client.CredentialIssuanceInitWithResponse(ctx, credentialId,
&wallet.CredentialIssuanceInitParams{WalletId: walletId},
wallet.CredentialIssuanceInit{IssuerId: "id_card", IssuanceRequirementsToVerify: requirements})
if err != nil {
log.Panicf("failed to init issuance: %v", err)
}
if issInitResp.StatusCode() != 200 {
log.Panicf("error while issuance init: %d %s", credCreateResp.StatusCode(), credCreateResp.Body)
}
await client.credentialIssuanceInit(credentialId, walletId, {
issuerId: 'id_card',
issuanceRequirementsToVerify: {
verifiedFields: [
{ path: '$.firstName', value: 'John' },
{ path: '$.familyName', value: 'Doe' },
],
},
})
Putting Both flows together
Adding verification requirements to issuers of VPDriven type is possible in the same way as in the case of CredentialRequirements type.
In this case, the wallet configuration is the same as in case of filling credential claims from a presentation.
Custom Authorization Provider/Authentic Source
Custom authentication flow can be plugged into the Credential Issuance process. This is done by creating a web service exposing 2 endpoints:
- Authentication redirect endpoint with 2 query parameters:
redirect_uri- URI to which the Authentication provider redirects to after completing authenticationstate- A unique state used to track requests
- Authentication result endpoint
After accepting a credential offer, the holder is redirected to the Authentication redirect endpoint.
This request contains a query parameter called redirect_uri.
After completing authentication, the Authentication service redirects the holder to the URL specified in this query parameter.
Before redirecting, the authentication service appends a new query parameter called authn_result, which specifies an URL,
where the Issuer's Authorization Server is able to fetch the authentication result.
The flow is described by the following diagram:
Authentication result is a JSON with the following structure:
{
"authnStatus": "ok/error",
"data": [
{
"given_name": "Jonatan",
"family_name": "Cesto"
...
},
{
"date_of_birth": "01-01-2000",
...
},
]
}
The data sent from the Authentication Service can be used to issue a Credential using the VPDriven credential issuer.
Claims from the Authentic Source are accessed in the same way as claims from Credential Presentations.
The following example shows configuration of a VPDriven issuer that uses a custom authentication provider
with data mappings to the previous data object.
{
"trustFramework": "NOOP",
"walletKeyIdentifier": "did",
"credentialIssuers": [
{
"id": "poa",
"name": "Power of Attorney",
"credentialFormat": "jwtimport { Mermaid } from 'mdx-mermaid/Mermaid'_vc_vcdm",
"credentialIssuer": "VPDriven",
"credentialType": "VerifiableCredential,PowerOfAttorney",
"authorization": "openidCustom",
"authnProviderUrl": "https://my.authn.provider.com/handle_request"
"issuerConfiguration": {
"credentialVerifierId": "national_id_identity_disclosure",
"mapping": {
"$.[0].given_name": "$.firstName",
"$.[0].family_name": "$.familyName",
"$.[2].date_of_birth": "$.dateOfBirth"
}
}
}
],
"oidcRevision": {
"oidc4vci": "Draft15",
"oidc4vp": "Draft23"
}
}
For issuers that are using a custom authentication provider, the authorization field of the issuer definition must be set
to one of these values:
oauthCustom: Use this value in the case you need to have interactions compatible with the EUDI WalletopenidCustom: Use this value otherwise