Requesting and verifying mDocs
Overview
The core SDK functionality is to request and verify mDocs via a proximity presentation workflow as per ISO/IEC 18013-5:2021.
To build a step-by-step implementation of this workflow, give the Proximity verification tutorial a try.
Sequence diagram
Detailed steps
Create a presentation request
As a verifier, you can select what information you request for verification by creating an instance
of the SDK’s
MobileCredentialRequest
structure:
data class MobileCredentialRequest(val docType: DocType, val namespaces: NameSpaces)
docType
: Indicates the requested credential type.namespaces
: This is a dictionary of namespaces that are requested for verification. Eachnamespace
is itself a dictionary of:DataElementIdentifier
: Requested claim identifier.IntentToRetain
: Boolean indicating whether or not your application intends to retain this claim’s value after the verification process is completed. Setting this totrue
doesn’t actually store any information. It merely informs the holder that you intent to retain that information. Retaining the claim should be implemented separately.
This is the structure that will be shared with the holder’s wallet application as part of the verification workflow. It enables the wallet application to inform the holder what information is requested for verification.
UX Considerations
Your verifier application can either use hardcoded requests, or create a UI element that enables the user to create different requests on the fly by selecting different combinations of credential types, namespaces and claims. Check out our GO Verify app to see this is action.
Retrieve device engagement string from QR code presented by holder
As defined in ISO/IEC 18130-5:2021, a proximity presentation workflow is always initiated by the holder, who must create a QR code for the verifier to scan in order to initiate the device engagement phase.
This means that your application must be able to scan and process this QR code. You can see an example of implementing a third party framework to achieve this in the Proximity verification tutorial.
Once the QR code is scanned and processed, you should be able to retrieve the device engagement string embedded in it. This string must then be used to establish a secure connection between the holder and verifier devices.
Create a proximity presentation session
To establish a secure connection between the holder and verifier devices, your verifier application
must call the SDK’s
createProximityPresentationSession
method:
suspend fun createProximityPresentationSession(
activity: Activity,
encodedDeviceEngagementString: String,
onSessionTerminated: ProximityPresentationSession.OnSessionTerminated? = null
): ProximityPresentationSession
encodedDeviceEngagementString
: The string retrieved from the QR code presented by the holder.
Once called, the
createProximityPresentationSession
method will establish a secure connection with the holder application and return an instance of the
ProximityPresentationSession
class.
UX Considerations
This method requires granting bluetooth permissions to your application.
When calling this method for the first time, a system UI will prompt the user to grant bluetooth
permissions to the application. If the user has denied access, the
VerifierException.BluetoothPermissionException
exception is thrown and the workflow cannot
continue until bluetooth permissions are granted to the application. Your wallet application should
provide a UX to cover this scenario.
Send a presentation request
Once the connection is established, your verifier application should call the
ProximityPresentationSession
class’
requestMobileCredentials
method to request information for verification:
suspend fun requestMobileCredentials(
request: List<MobileCredentialRequest>,
skipStatusCheck: Boolean = false
): MobileCredentialResponse
request
: This is the instance of the SDK’sMobileCredentialRequest
structure referenced above.skipStatusCheck
: Controls whether credential revocation status is checked (false
) or not (true
).
As per ISO/IEC 18013, once a valid request is sent a response is expected:
- When a response is received from the holder it is decoded, verified and returned by the method
as an instance of the
MobileCredentialResponse
class. - If no response is received after 300 seconds the request will timeout and a
TimeoutError
error thrown. The session will not be terminated and your verifier application can send a new request if required.
UX Considerations
As per ISO/IEC 18013, a credential presentation and a sessionTermination
status code can be sent
by the holder in a single response. In this scenario the method will return the credential
presentation and then immediately execute the onSessionTerminate(_:) callback, closing the data
transport session.
Handle the presentation response
The holder’s response is returned by the
requestMobileCredentials
method as an instance of the
MobileCredentialResponse
structure:
data class MobileCredentialResponse(
val credentials: List<MobileCredentialPresentation>?,
val credentialErrors: List<CredentialError>?
)
credentials
: This is an array of credentials included in the holder’s response, represented asMobileCredentialPresentation
structure(s):
data class MobileCredentialPresentation(
val docType: DocType,
val validityInfo: MobileCredentialValidity,
val claimErrors: Map<NameSpace, Map<DataElementIdentifier, ErrorCode>>?,
val claims: Map<NameSpace, Map<DataElementIdentifier, MobileCredentialElement>>?,
val branding: Branding?,
val issuerInfo: IssuerInfo?,
val verificationResult: MobileCredentialVerificationResult
)
doctype
: Credential’s type.validityInfo
:validFrom
: Indicates the date when this credential becomes valid.validUntil
: Indicates the date when this credential expires.
claimErrors
: This is a dictionary of any errors found with specific claims included in the credential.claims
: This is a dictionary of namespaces that are included in the credential, the identifiers (DataElementIdentifier
) of claims that were requested for verification and their values (MobileCredentialElementValue
).branding
: Information and links to graphic assets that should be used by your wallet application to render this credential.issuerInfo
:commonName
: Issuer’s common name, matching its certificate. This can be used to display the credential issuer’s human readable name.trustedIssuerCertificateId
: Issuer’s IACA certificate.
VerificationResult
:reason
: Verification failure reason (when applicable):message
: Verification failure message.type
: Verification failure type.
verified
: Boolean indicating whether verification was successful (true
) or not (false
).
Your verifier application can now parse this instance and display relevant information to the user.
Verification failures
If validation fails, one of the following errors can be returned in
verificationResult.reason.type
:
Type | Description |
---|---|
DeviceKeyInvalid | When an issuer issues an mDoc to a holder, they can optionally limit what claims from the mDoc the holder can present. If a holder attempts to present claims that they are not allowed to present (as per the issuer’s policy), this error is returned. |
InvalidSignerCertificate | Indicates an error in the certificate used to sign the credential. No information included in the credential can be trusted. |
MobileCredentialExpired | Credential has expired. |
MobileCredentialInvalid | Captures different scenarios where the credential cannot be validated due to tampering, decoding problems and others. No information included in the credential can be trusted. |
MobileCredentialNotYetValid | Credential has future activation date. |
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 revocation status. |
TrustedIssuerCertificateExpired | Issuer IACA certificate expired. |
TrustedIssuerCertificateNotYetValid | Credential was signed with a certificate that has a future activation date (e.g. valid from future date). |
UnsupportedCurve | The SDK currently only supports NIST P-*-based curves from the ISO/IEC 18013-5:2021 standard. If the credential was signed using any other curve, this error is returned and the credential cannot be verified. |