Skip to main content

Receiving Mobile Credentials in Wallet SDK using OpenID Credential Provisioning

Initialise a wallet instance

@mattrglobal/wallet-sdk-react-native does not come in mobile credential support by default. To enable the mobile credential feature, an additional peer dependency @mattrglobal/mobile-credential-holder-react-native is needed. Install the following dependency in your app.

tip

NOTE: mobile credential presentation utilise Bluetooth connection. For iOS make sure the NSBluetoothAlwaysUsageDescription and NSBluetoothPeripheralUsageDescription description are configured inside Info.plist.


yarn add @mattrglobal/mobile-credential-holder-react-native

Include the mobile credential holder extension during initialisation


import { initialise } from "@mattrglobal/wallet-sdk-react-native";
import MobileCredentialHolder from "@mattrglobal/mobile-credential-holder-react-native";

await initialise({ extensions: [MobileCredentialHolder], walletId });

Start an OpenID Credential Provisioning flow

Discover OpenID credential offer


const uri =
"openid-credential-offer://?credential_offer=%7B%22credential_issuer%22
%3A%22https%3A%2F%2Fmyissuer.example.com%22%2C%22credentials%22%3A%5B%
22707e920a-f342-443b-ae24-6946b7b5033e%22%5D%2C%22request_parameters%22
%3A%7B%22login_hint%22%3A%22test.user%40example.com%22%2C%22prompt%22%
3A%22login%22%7D%7D";

const discoveryResult = await wallet.openid.issuance.discover(uri);
if (discoveryResult.isErr()) {
// Handle error from discoveryResult.error
}
const { offer } = discoveryResult.value;

or Construct the offer manually


const offer: OpenidIssuanceCredentialOffer = {
issuer: "https://example.com/",
authorizeEndpoint: "https://example.com/oauth/authorize",
tokenEndpoint: "https://example.com/oauth/token",
credentialEndpoint: "https://example.com/oauth/credential",
credentials: [
{
profile: "mobile",
scope: "mso_mdoc:com.example.employeecredential.1",
docType: "com.example.employeecredential.1"
}
]
}

Generate an OAuth authorization url to request access token to retrieve the credentials


import { Linking } from "react-native";

const generateAuthorizeUrlResult = await wallet.openid.issuance.generateAuthorizeUrl({ offer, clientId, redirectUri });

if (generateAuthorizeUrlResult.isErr()) {
// Handle error from generateAuthorizeUrlResult.error
return;
}

const { url, codeVerifier } = generateAuthorizeUrlResult.value;
await Linking.openURL(url);

Retrieve the token


const retrieveTokenResult = await wallet.openid.issuance.retrieveToken({
offer,
clientId,
redirectUri,
codeVerifier,
code: route.params.code, // code comes authorization success callback above
});

if (retrieveTokenResult.isErr()) {
// Handle error from retrieveTokenResult.error
return;
}

const { accessToken } = retrieveTokenResult.value;

Retrieve credentials


import { CredentialProfileSupported } from "@mattrglobal/wallet-sdk-react-native";
const retrieveCredentialsResult = await wallet.openid.issuance.retrieveCredentials({
offer, // offer that contains mobile credentials
accessToken,
clientId,
});

retrieveCredentialsResult.forEach((credentialOfferResult) => {
if ("error" in credentialOfferResult) {
const { offer, error } = credentialOfferResult;
// Handle error from retrieveCredentialsResult.error
} else {
const { offer, result } = credentialOfferResult;
if (result.profile === CredentialProfileSupported.Mobile) {
const credentialId = result.credentialId;
}
}
});

Manage Storage of Mobile Credentials

The SDK manages the storage of any retrieved mobile credential. They will be accessible via the following mobile credential functions.


// Add new trusted issuer certificates
await wallet.credential.mobile.addTrustedIssuerCertificates(certificates);

// Get all trusted certificates
const certificates = await wallet.credential.mobile.getTrustedIssuerCertificates();

// Rmove one of the trusted issuer certificate
await wallet.credential.mobile.deleteTrustedIssuerCertificate(id);

Enable Auto Trust for Issuer Certificates

You may also instruct the SDK to automatically download and add certificates if it's discoverable via the openid credential issuer metadata into the trusted list while retrieving a mobile credential via OpenID4VCI.


const retrieveCredentialsResult = await wallet.openid.issuance.retrieveCredentials({
offer, // offer that contains mobile credentials
accessToken,
clientId,
autoTrustMobileCredentialIaca: true, // enable auto trust
});

Error handling

Functions that are expected to have an error path return a Neverthrow Result type that represents either success (Ok) or failure (Err).

Although this pattern is more verbose, it encourages the handling of possibly errors and reserves throwing exceptions for truly exceptional situations.


import { initialise } from "@mattrglobal/wallet-sdk-react-native";

const initialiseWalletResult = await initialise();

if (initialiseWalletResult.isErr()) {
// Handle error from initialiseWalletResult.error
return;
}

const wallet = initialiseWalletResult.value;

Unwrap

A utility function is provided for convenience if you decide not to handle your errors as results. This function will simply throw an error if the function passed in returns a Result where Result.isErr() is true.

import { unwrap } from "@mattrglobal/wallet-sdk-react-native";

try {
const wallet = unwrap(await initialise());
} catch (error) {
// Handle thrown error
}

Find the comprehensive SDK interfaces for these examples and others in the documentation https://github.com/mattrglobal/docs-wallet-sdk.

Get in touch if you wish to find out more about using the Wallet SDK in production.