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.
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.