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:
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:
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:
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 frommdocIacasUri
.authorizeEndpoint
: Endpoint used to make the request to access thecredentialEndpoint
. This is the URL the SDK redirects the user to in order to authenticate with the issuer.tokenEndpoint
: Once the user is authenticated by theauthorizeEndpoint
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 thecredentialEndpoint
.credentialEndpoint
: Endpoint used by the SDK to trigger issuing the credential. The SDK must provide the token obtained from thetokenEndpoint
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:

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:
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 thediscoverCredentialOffer
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.
- When set to
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:
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:

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:
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 theretrieveCredentials
method is unable to retrieve the credentials, it will return one of the following error types:
Type | Description |
---|---|
certificateNotFound | The Issuer’s certificate is not found in the SDK storage. |
connectivityError | Connectivity problems with issuer prevented retrieving the credential |
credentialNotAdded | Credential failed any of the addCredential validation steps described above. |
failedToRetrieveCredential | Failed 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
:
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 thecredentialId
returned inRetrieveCredentialResult
).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 whenverified
isfalse
: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.

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
:
Type | Description |
---|---|
MobileCredentialExpired | Credential has expired. |
StatusRevoked | Credential has been permanently revoked. |
StatusSuspended | Credential has been temporarily revoked. |
StatusUnknown | Unable to retrieve the status list referenced in the credential and determine its status. |
TrustedIssuerCertificateExpired | Issuer IACA certificate expired. |