Verify a W3C Verifiable Credential with SpruceKit Mobile SDK
1. Verify an embedded credential
In this flow, the Verifier will scan a QR-code presented by the Wallet. The QR-Code will directly contain the verifiable presentation encoded as a JWT. As such, the Verifier has to engage the QRCodeScanner component.
// Example View for a VC Verifier
fun VerifyVCView(
navController: NavController
) {
var success by remember {
mutableStateOf<Boolean?>(null)
}
fun onRead(content: String) {
GlobalScope.launch {
try {
verifyJwtVp(jwtVp = content)
success = true
} catch (e: Exception) {
success = false
e.printStackTrace()
}
}
}
fun back() {
navController.navigate(
Screen.HomeScreen.route.replace("{tab}", "verifier")
) {
popUpTo(0)
}
}
if (success == null) {
QRCodeScanner(
title = "Scan QR Code",
subtitle = "Looking",
cancelButtonLabel = "Cancel",
onRead = onRead,
isMatch = "true",
onCancel = onCancel,
fontFamily = Inter,
readerColor = Color.White,
guidesColor = Color.White,
textColor = Color.White,
backgroundOpacity = 0.5f
)
} else {
// Call your Verifier results View here
}
}
Verify VCs
Do you know what you are scanning? You can select what you need from the functions below
import com.spruceid.mobile.sdk.rs.verifyPdf417Barcode
import com.spruceid.mobile.sdk.rs.verifyJwtVp
import com.spruceid.mobile.sdk.rs.VerifyVcbQrcodeAgainstMrz
// Verify a W3C VC JWT-VP
_ = try await VerifyJwtVp(jwtVp: vp)
// Verify a W3C VC Barcode
_ = try await VerifyPdf417Barcode(payload: payload)
// Verify a W3C VC Barcode against a Machine Readable Zone
_ = try await VerifyVcbQrcodeAgainstMrz(mrzPayload: mrz, qrPayload: vcb)
The steps as explained above allow you to execute a verification offline by scanning a credential embedded in the QR code. You can also verify online with OID4VP, using the DelegatedVerifer component.
2. Delegated Verifier
In the delegated flow, the Verifier generates a QR code to advertise the PresentationRequest to the Wallet. That PresentationRequest can be retrieved by the Wallet from the advertised endpoint. That endpoint should be your own backend service. To use the DelegateVerifier, you will need a back-end service that supports the OID4VP transaction. From your mobile application, you will only advertise the request and poll the status. To manage the UI during the verification, you will have to manage the DelegatedVerifierStatus. You can monitor that state, like in the example below, and manage your UI based on the state.
// Define your DelegatedVerifier View
@Composable
fun VerifyDelegatedOid4vpView(
navController: NavController,
verificationId: String,
verificationMethodsViewModel: VerificationMethodsViewModel,
verificationActivityLogsViewModel: VerificationActivityLogsViewModel,
statusListViewModel: StatusListViewModel
) {
val scope = rememberCoroutineScope()
lateinit var verificationMethod: VerificationMethods
lateinit var url: Url
lateinit var baseUrl: String
var step by remember { mutableStateOf(VerifyDelegatedOid4vpViewSteps.LOADING_QRCODE) }
var status by remember { mutableStateOf(DelegatedVerifierStatus.INITIATED) }
var loading by remember { mutableStateOf<String?>(null) }
var errorTitle by remember { mutableStateOf<String?>(null) }
var errorDescription by remember { mutableStateOf<String?>(null) }
lateinit var verifier: DelegatedVerifier
var authQuery by remember { mutableStateOf<String?>(null) }
lateinit var uri: String
var presentation by remember { mutableStateOf<String?>(null) }
fun monitorStatus(status: DelegatedVerifierStatus) {
try {
scope.launch {
val res =
verifier.pollVerificationStatus(
"$uri?status=${status.toString().lowercase()}"
)
when (res.status) {
// Manage your DelegatedVerifierStatus here
}
}
} catch (e: Exception) {
errorTitle = "Error Verifying Credential"
errorDescription = e.localizedMessage
}
}
fun back() {
navController.navigate(
Screen.HomeScreen.route.replace("{tab}", "verifier")
) {
popUpTo(0)
}
}
LaunchedEffect(Unit) {
try {
// Verification method from db
verificationMethod =
verificationMethodsViewModel.getVerificationMethod(verificationId.toLong())
// Verification method base url
url = Url(verificationMethod.url)
baseUrl = "${url.protocol.name}://${url.host}:${url.port}"
// Delegated Verifier
verifier = DelegatedVerifier.newClient(baseUrl)
// Get initial parameters to delegate verification
val delegatedInitializationResponse =
verifier.requestDelegatedVerification(url.encodedPathAndQuery)
authQuery = "openid4vp://?${delegatedInitializationResponse.authQuery}"
uri = delegatedInitializationResponse.uri
// Display QR Code
step = VerifyDelegatedOid4vpViewSteps.PRESENTING_QRCODE
// Call method to start monitoring status
monitorStatus(status)
} catch (e: Exception) {
errorTitle = "Failed getting QR Code"
errorDescription = e.localizedMessage
}
}
if (errorTitle != null && errorDescription != null) {
ErrorView(
errorTitle = errorTitle!!,
errorDetails = errorDescription!!,
onClose = { back() }
)
} else {
when (step) {
// Manage your VerifyDelegatedOid4vpViewSteps here
}
}
}