Skip to Content

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

Initialize the SDK with the required configuration

Make sure you included the CredentialIssuanceConfiguration structure when initializing the SDK:

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 credentials: [OfferedCredential] let transactionCode: TransactionCode? }
  • issuer : Issuer’s domain, used to validate their ownership of the certificate retrieved from mdocIacasUri.
  • credentials : This array includes details regarding the offered credential and what claims it includes.
  • transactionCode: Properties of the expected transaction code. Used in the Pre-authorized Code workflow.

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: discoveredCredentialOfferURL, clientId: Constants.clientId, transactionCode: nil ) 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 print(credentials) // Clear navigation stack and display retrievedCredentials view navigationPath = NavigationPath() navigationPath.append(NavigationState.retrievedCredentials) } } catch { print(error.localizedDescription) } }
  • credentialOffer : The same credential offer string that was used in discoverCredentialOffer method.
  • 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.
  • transactionCode: this parameter is only used for pre-authorized code workflow. The parameter is used to prove the user’s identity.

UX Considerations

The SDK’s retrieveCredentials method internally calls the generateDeviceKey method, which requires user authentication if the user has not authenticated in the last 30 seconds. To enable users to authenticate via Face ID you must add the NSFaceIDUsageDescription attribute to the application’s info.plist file.

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 user

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.
Last updated on