Claiming and managing mDocs

Overview

One of the core SDK functionalities is to interact with a credential offer and claim an mDoc as per OpenID4VCI (OpenID for Verifiable Credential Issuance).

To build a step-by-step implementation of this workflow, give the Claim a credential tutorial a try.

Sequence diagram

Detailed steps

Retrieve the credential offer URL

Users can receive OID4VCI Credential offers from issuers as deep-links or QR codes, as shown in the following example:

Claim a credential example

Your application must provide a way for the user to interact with these offers. This can include scanning a QR code or following a deep-link. This will enable your application to retrieve the URL-encoded Credential offer embedded in the QR code/deep-link.

Refer to the Claim a credential tutorial for an example using a 3rd party framework to scan a QR code and retrieve the offer URL embedded in it.

Retrieve credential offer details

After the Credential offer URL is retrieved, your application should call the SDK’s discoverCredentialOffer method, passing the Credential offer URL as its offer parameter. This method will make a request to this URL (this is referred to as Credential discovery).

See this example for calling the discoverCredentialOffer method from the Claim a credential tutorial:

Calling the discoverCredentialOffer method
    Task {
        do {
            discoveredCredentialOffer = try await mobileCredentialHolder.discoverCredentialOffer(offer)
            // present credential offer screen, as soon as credential offer is discovered
            navigationPath.append(NavigationState.credentialOffer)
        } catch {
            print(error)
        }
    }

The issuer should respond with the following offer details:

  • What Issuer is offering the credentials?
  • What credentials are being offered, in what format and what claims do they include?

This information is returned by the discoverCredentialOffer method as a DiscoveredCredentialOffer object, as per OID4VCI:

DiscoveredCredentialOffer object
struct DiscoveredCredentialOffer {
    let issuer: URL
    let authorizeEndpoint: URL
    let tokenEndpoint: URL
    let credentialEndpoint: URL
    let credentials: [OfferedCredential]
    let mdocIacasUri: URL?
}
  • issuer : Issuer’s domain, used to validate their ownership of the certificate retrieved from mdocIacasUri.
  • authorizeEndpoint : Endpoint used to make the request to access the credentialEndpoint. This is the URL the SDK redirects the user to in order to authenticate with the issuer.
  • tokenEndpoint : Once the user is authenticated by the authorizeEndpoint they are issued an authorization code. This endpoint is used by the SDK to exchange this code for a token that is used to make a request to the credentialEndpoint.
  • credentialEndpoint : Endpoint used by the SDK to trigger issuing the credential. The SDK must provide the token obtained from the tokenEndpoint when making a request to this endpoint.
  • credentials : This array includes details regarding the offered credential and what claims it includes.
  • mdocIacasUri : Endpoint used to retrieve the certificates used to sign the credential.

These properties are used by the SDK in the next steps.

Display credential offer details to user

Your application should now parse the DiscoveredCredentialOffer object and display the offer details to the user, alongside a UI element to enable the user to provide consent to claiming the offered credentials:

Claim offer button

After reviewing the offer details, the user can interact with the UI element and provide their consent to claiming the offered credential.

Interact with issuer to initiate OID4VCI workflow

Once the user provides their consent, your application should call the SDK’s retrieveCredentials method, as shown in the following example:

Calling the retrieveCredentials method
    Task {
        do {
            let retrievedCredentialResults = try await mobileCredentialHolder.retrieveCredentials(
                credentialOffer: discoveredCredentialOffer!,
                clientId: Constants.clientId,
                redirectUri: Constants.redirectUri,
                autoTrustMobileCredentialIaca: true)
            Task {
                var credentials: [MobileCredential] = []
                for result in retrievedCredentialResults {
                    if let credentialId = result.credentialId {
                        if let credential = try? await mobileCredentialHolder.getCredential(credentialId: credentialId) {
                            credentials.append(credential)
                        }
                    }
                }
                self.retrievedCredentials = credentials
                // Clear navigation stack and display retrievedCredentials view
                navigationPath = NavigationPath()
                navigationPath.append(NavigationState.retrievedCredentials)
            }
        } catch {
            print(error.localizedDescription)
        }
    }
  • credentialOffer : This parameter is the object returned by the discoverCredentialOffer method. The different properties are used by the SDK to interact with the issuer and claim the credential, as detailed below.
  • clientId : This parameter is used by the issuer to recognize your application as it is making a request to claim credentials.
    • It must be defined as a resource in your application project, as shown in the Claim a credential tutorial.
    • It must be registered as a key pair with redirectUri as part of the issuer’s OID4VCI workflow configuration.
  • redirectUri : This parameter is used by the issuer to redirect the user back to a specific view in your application after completing the configured OID4VCI workflow.
    • It must be defined as a resource in your application project, as shown in the Claim a credential tutorial.
    • It must be registered as a key pair with clientId as part of the issuer’s OID4VCI workflow configuration.
  • autoTrustMobileCredentialIaca :
    • When set to true, this request will accept credentials from any issuer. The SDK will retrieve the IACA referenced in the offered credential and add it to the list of trusted issuers in the application storage.
    • When set to false, this request will only accept credentials issued by trusted issuers, identified by their IACA certificate. This means the IACA referenced in the offered credential must exist in the application’s trusted issuers list prior to accepting the credential offer.
Add trusted issuers

To add a trusted issuer your application should call the SDK’s addTrustedIssuerCertificates method, passing the issuer’s IACA as a parameter:

Adding a trusted issuer
func addCertificate(certificate: String) {
    do {
      _ = try mobileCredentialHolder.addTrustedIssuerCertificates(certificates: [certificate])
    } catch {
      print(error.localizedDescription)
    }
  }

Redirect user to authenticate with issuer

Once the retrieveCredentials method is called, the user is redirected to the authorizeEndpoint defined in the DiscoveredCredentialOffer object. This endpoint is used by the issuer to authenticate the user:

Redirect to authenticate

Upon successful authentication, the user will proceed to complete the OID4VCI workflow configured by the issuer. This workflow can include different steps based on the issuer’s configuration. Once all required steps are completed, the issuer will redirect the user back to the configured redirectUri, which should be handled by your application.

Trigger credential issuance

The user is redirected with an authorization code (retrieved from the issuer’s authorization server) which is used by the SDK to make a request to the tokenEndpoint defined in the DiscoveredCredentialOffer object, and exchange the authorization code for an access token.

The SDK then proceeds to making a request to the credentialEndpoint defined in the DiscoveredCredentialOffer object, and make a request to issue credentials as per the credential offer.

The issuer then responds to the SDK’s request to the credentialEndpoint endpoint with the issued credentials. These are returned to the retrieveCredentials method, where the request came from. Once retrieved, the user is redirected to the configured redirectUri in your wallet application.

Validate and store credential

The SDK internally calls the addCredential method to validate the received credentials against the ISO/IEC 18013-5:2021 standard. This includes validating the following:

  • The public, device and COSE keys.
  • The issuer’s certificate.
  • The algorithm used to sign the credential exists and is supported.
  • All the certificates in the credential’s chain of trust.
  • The credential has not been tampered with.
  • The credential has not expired.

Credentials who meet validation logic are stored in the application’s internal data storage.

When validation is successful, the retrieveCredentials method returns a RetrieveCredentialResult, which includes unique identifiers of all the credentials that were retrieved in the current interaction:

RetrieveCredentialResult object
struct RetrieveCredentialResult {
    let docType: String
    let credentialId: String?
    let error: RetrieveCredentialError?
}
  • docType : Identifies the type of the credential.
  • credentialId : Internally unique identifier of this credential. It can be used by the SDK to retrieve this specific credential from the storage when required.
  • RetrieveCredentialError : If the retrieveCredentials method is unable to retrieve the credentials, it will return one of the following error types:
TypeDescription
certificateNotFoundThe Issuer’s certificate is not found in the SDK storage.
connectivityErrorConnectivity problems with issuer prevented retrieving the credential
credentialNotAddedCredential failed any of the addCredential validation steps described above.
failedToRetrieveCredentialFailed to retrieve credential for any other reason.

Display credential to issuer

Your application can now call the SDK’s getCredential method, passing the credentialId as a parameter to retrieve a specific credential as an instance of MobileCredential:

MobileCredential object
let branding: Branding?
let claims: [MobileCredentialDataTypes.NameSpace : [MobileCredentialDataTypes.ElementID : MobileCredentialElementValue]]?
let docType: String
let id: String
let issuerInfo: IssuerInfo
let validityInfo: Validity
let verificationResult: VerificationResult?
  • branding : Information and links to graphic assets that should be used by your wallet application to render this credential.
  • claims : This is a dictionary of namespaces that are included in the credential. Each namespace is in itself a dictionary of elements identifiers and their corresponding values.
  • doctype : Credential’s type.
  • id : Unique identifier of this credential (this is the credentialId returned in RetrieveCredentialResult).
  • issuerInfo :
    • commonName : Issuer’s common name, matching its certificate. This can be used to display the credential issuer’s human readable name to the user.
    • trustedIssuerCertificateId : Issuer’s IACA certificate.
  • validityInfo :
    • validFrom : Indicates the date when this credential becomes valid.
    • validUntil : Indicates the date when this credential expires.
  • verificationResult :
    • reason : Indicates verification failure reason when verified is false:
      • message : Verification error message.
      • type : Verification error type.
    • verified : Indicates successful (true) or failed (false) verification.

Your application can then parse the returned object and display the credential to the user.

Display claimed credential
Verification errors

Whenever the getCredential method is called, the SDK repeats the validation steps performed before storing the credential. If validation fails, one of the following errors can be returned in verificationResult.reason:

TypeDescription
MobileCredentialExpiredCredential has expired.
StatusRevokedCredential has been permanently revoked.
StatusSuspendedCredential has been temporarily revoked.
StatusUnknownUnable to retrieve the status list referenced in the credential and determine its status.
TrustedIssuerCertificateExpiredIssuer IACA certificate expired.