Technical Specifications
Attestation Issuance

Attestation Issuance

Issuance as defined in the Architecture Reference Framework (ARF) is based on the OpenID for Verifiable Credential Issuance (OID4VCI (opens in a new tab)) protocol. This page outlines the specific flows that need to be supported for Attestation Issuance within Company Passport.

OpenID for Verifiable Credential Issuance

Attestations MUST be issued using the OID4VCI (opens in a new tab) protocol, and MUST support both Authorization Code Flow and Pre-Authorized Code Flow. In addition implementations MUST support the Batch Credential Endpoint. An Issuer MAY support deferred credential issuance, which MUST be supported by the Wallet. Both the Issuer and Wallet MUST support the Notification Endpoint for updates from the Wallet to the Issuer.

The Organizational Wallet can act as both Issuer and Wallet.

Credential Format Profiles

Both the Issuer and Wallet MUST support the vc+sd-jwt (for the SD-JWT VC Attestation Format) and mso_mdoc (for the ISO/IEC 18013-5 mDL Attestation Format) Credential Format Profiles as defined in OID4VCI (opens in a new tab). Other Credential Format Profiles MAY be supported. See Attestation Formats for requirements around supported Attestation Formats.

High Assurance

For additional security, requirements as defined in Section 4. of High Assurance Interoperability Profile (opens in a new tab) MUST be supported in Company Passport solutions. Additional custom URL schemes in addition to haip:// can be supported.

Issuance using Authorization Code flow

Issuance Authorization Code

Authorization Code Flow in-depth

Initialization:

  1. (Wallet initiated) The user opens and unlocks the wallet .
  2. (Wallet initiated) The user opens the wallet provided credential catalogue of pre-configured (Q)EAA Providers. After a (Q)EAA is selected the Wallet continues the flow with the pre-configured Credential Issuer URL and credential identifier. No Resource server/web page is involved

Or 3. (Issuer initiated) User browses to (Q)EAA Provider's website. 4. (Issuer initiated) Browser opens the Resource server/website, either provided by the (Q)EAA Provider's or an external entity 5. (Issuer initiated) Resource server request to create a credential offer with the (Q)eAA Provider. Optionally providing a state value and information to be stored in the credential (can also be done later)

For the unique issuer_state, the (Q)EAA Provider either:

a) Offline signed JWT 6. (Issuer initiated) Creates an offline signed JWT itself using a private key, trusted by the IDP. The benefit is that the IDP needs little integration. The provider is responsible for storing this in a session somehow

b) IDP session/token

  1. b) (Issuer initiated) Or sends a request to the IDP, asking it to create a session and unique issuer_state. The IDP is now responsible for the session and state. State is either a JWT or opaque token
  2. b) (Issuer initiated) The IDP sends back the session and issuer_state to the (Q)EAA provider in the previous case

b) IDP session/token

  1. c) (Issuer initiated) Delegate credential offer creation to the IDP\n Step 004, could of course also happen directly against the IDP in this case
  2. c) (Issuer initiated) The IDP returns the credential offer.

d) (Issuer initiated) The credential offer was completely static, which could be used with a Authorization code flow only; This is currently not supported by our issuer component yet;

  1. (Issuer initiated) Credential offer(s) for QR and/or deeplink are returned to the Resource server, optionally including a QR code as image next to the value(s)
  2. (Issuer initiated) returns a HTML page to the browser containing a Credential Offer; containing
    • the Credential Issuer URL
    • an identifier to the offered credential
    • an optional issuer_state parameter to bind this issuance to a pre-existing session with the Provider
  3. (Issuer initiated) The user unlocks the wallet

Status feedback

  1. The Resource server could ask for regular status updates from the (Q)EAA Provider. This allows the website to inform the user via the browser about progress and/or errors. There are 2 possibilities (only the first one is currently supported). A regular POST to a status endpoint or a regular callback to a URL.
  2. The Resource Server does a regular POST or GET to the status endpoint of the (Q)EAA; Or the browser does this directly with the Provider using a secure host-only cookie
  3. The Provider matches the requested ID with it's internal session, optionally using the IDP.
  4. and 18. The (Q)EAA Provider returns a status/error response and the Resource Server updates its webpage

Metadata

  1. The Wallet fetches the Credential Issuer's metadata from the ./well-known files of the Credential Issuer URL
  2. The (Q)EAA Provider returns the Credential Issuer Metadata; containing:
    • information about the Issuer supported credentials, key types, DID methods
    • translations and display information like order of attestations, logo's and colors for the offered credentials
  3. The Wallet shows information about the (Q)EAA Provider and the offered (Q)EAA to the user and asks for consent
  4. The user consents and optionally selects multiple (Q)EAAs if supported ((Issuer initiated))

Wallet attestations (WIP, not supported yet)

  • The Wallet retrieves a nonce for the client attestation from the (Q)EAA Provider; //could also be the state if provided//
  • The (Q)EAA Provider generates a nonce and links it to a session managed by the (Q)EAA Provider
  • Or the (Q)EAA Provider delegate to the IDP to generate the nonce and bind it to its session
  • In the latter case the IDP would return the nonce to the (Q)EAA Provider.
  • The (Q)EAA Provider returns the nonce to the Wallet
  • The Wallet fetches fresh client attestation from the Wallet Provider backend
  • The Wallet generates proof of possession (PoP) using the nonce fetched in the previous step and the private key for wallet attestations

Authentication

  1. The Wallet sends a Pushed Authorization Request (PAR) to the (Q)EAA Provider; containing:
    • the Wallet Provider's client_id
    • a PKCE code_challenge
    • The issuer_state value
    • the client attestation and proof of possession
    • a redirect_uri containing an app deeplink
    • an identifier for the requested (Q)EAA
  2. The (Q)EAA Provider either verifies the Offline state JWT signed by the issuer using its known public key
  3. Or the (Q)EAA Provider verifies the session info and issuer_state
  4. The (Q)EAA Provider verifies the wallet/client attestation and validates the status of the Wallet instance through a trust list
  5. The IDP returns the PAR response including the request_uri and expires_in values to the Wallet
  6. The Wallet uses the request_uri to create an Authorization Request and is opening the Wallets default browser using the URL.
  7. The Browser sends the Authorization Request to the IDP
  8. The IDP may exchange any information via the browser to the user, using the front channel. This can for instance be:
    • username / password auth
    • OID4VP requesting other (Q)EAA, etc..
    • E-herkenning, IDIN, DigiD
    • 2FA/MFA
  9. The IDP responds with an Authorization Response; containing
    • the auth code
    • the redirect provided by the wallet in the PAR
  10. The browser follows the redirect, launching the wallet
  11. The Wallet sends a Token Request to the IDP; containing:
    • the auth code from Authorization Response
    • the PKCE code_verifier matching the code_challenge from Authorization Request
    • the client attestation and Proof of possession
    • a DPoP key, which will be used later during the Credential Request
  12. The Issuer does a lookup for the code, verifies the PKCE code_verifier against the already known code_challenge. It then generates an access token bound to the DPoP public key.
  13. It verifies the client attestation. (note this could be part of step 40. Obviously the response will only be created once everything is in order)
  14. The IDP sends a Token Response; containing
    • DPoP-bound access token
    • a unique c_nonce, which later will be used to sign the Credential request
  15. The Wallet optionally generates a key pair for the device binding of the (Q)EAA and signs the c_nonce. The key pair could be unique per request, or per issuer
  16. The Wallet sends the Credential Request to the Issuer; containing
    • the DPoP-bound access token
    • the proof of device binding key signed c_nonce

TODO: Deferred and batch credential here

  1. The Issuer validates the access_token and the proof in case it is an offline JWT from the IDP
  2. Or the issuer uses the IDPs userinfo or introspect endpoints using the access token to verify the access token in cass the token is used online or is opaque
  3. In this case the IDP returns a successful response, it is verified, in case of error it is not
  4. The (Q)EAA Provider validates the subject key proof with the signature and c_nonce value

Issuance of the (Q)EAA or W3C JWT VC

The next few steps highlight the different credential formats. The actual attestation data can either be fetched by the Issuer at this point using a callback/hook from the issuer perspective. This could be a Database lookup, REST call, or for instance the information provided during creation of the credential offer (Provider initiated only)

  1. 9**(JSON-LD (Q)EAA)** The (Q)EAA Provider creates a W3C JSON-LD Verifiable Credential with its private key containing
    • attestation data
    • public key or DID as issuer (id)
  2. (SD-JWT (Q)EAA) The (Q)EAA Provider creates the Disclosures from attestation data and signs the SD-JWT with private key containing
    • attestation data and hashed Disclosures as the user claims
    • public key or DID as cnf claim
    • appends the full Disclosure(s).
  3. (mdoc (Q)EAA) The (Q)EAA Provider creates the hashed Releases from attestation data and signs the MDOC with private key containing
    • attestation data and hashed Releases as issuerAuth
    • public key as deviceKeyInfo
  4. (JWT VC) The (Q)EAA Provider creates a W3C JWT encoded Verifiable Credential with its private key containing
    • attestation data
    • public key or DID as iss claim
  5. The (Q)EAA Provider sends the Credential Response; containing:
    • The (Q)EAA as credential
  6. Optional user consent to accept the (Q)EAA and store it
  7. The Wallet stores the (Q)EAA and the associated keys.
  8. (Issuer initiated) Optional success feedback to user browser

Verifying Wallet Instance Attestation

Wallet Instances Attestations MUST be used for the Token and Pushed Authorization Request (PAR) endpoints before credential issuance as defined in OAuth 2.0 Attestation-Based Client Authentication (opens in a new tab).