SpruceKit
SpruceID
  • 🌲SpruceKit Introduction
    • Decentralized Identity Overview
    • Glossary
  • ⚡Quickstart
  • SpruceKit Mobile
    • SpruceKit Showcase App
      • Installation
      • Getting Started
      • Issue a Showcase Credential
      • Present a Showcase Credential
    • SpruceKit Mobile SDK
      • Introduction
      • Core Components
        • StorageManager
        • KeyManager
        • CredentialPack
        • Card
        • IsoMdlPresentation
        • mDocReader/IsomDLReader
        • Document Scanner
      • SpruceKit iOS SDK
        • Installation
        • Build a Wallet
          • Accept a W3C VC
          • Present a W3C VC
          • Present mDL in-person/offline
          • Present an mDL over the internet
        • Build a Verifier
          • Verify a W3C VC
          • Verify an mDL in-person/offline
          • Verify an mDL over the internet
      • SpruceKit Android SDK
        • Installation
        • Build a Wallet
          • Accept a W3C VC
          • Present a W3C VC
          • Present an mDL in-person/offline
          • Present an mDL over the internet
        • Build a Verifier
          • Verify a W3C VC
          • Verify an mDL in-person/offline
          • Verify an mDL over the internet
  • Verifiable Digital Credentials
    • ⚙️DIDKit
      • Installation
      • Core Concepts
      • DID Methods
      • Runtime Configuration
      • Specifications and Dependencies
      • Quickstart
      • DIDKit Packages
        • Command Line Interface
        • HTTP Server
        • Rust Crate
        • C Interface
        • Java and Android
        • Python
        • Javascript
      • DIDKit Examples
        • Core Functions (CLI)
        • Core Functions (HTTP)
        • did-web in minutes
        • Batch Generation & Verification
    • 🪪ISO mDL
      • Quickstart
      • Core Concepts
      • User Guide
  • Schema Definition Language
    • 🔗TreeLDR
      • TreeLDR Quickstart
        • First Schema
        • Compilation into JSON Schema
        • Compilation into JSON-LD Context
        • Writing a Layout
        • Simple Rust Integration
      • Types
        • Literal Types
      • Layouts
        • Primitive Layouts
        • Literal Layouts
        • Enumeration
        • Array Layout
        • References
      • Compiling
        • Schema Definition Formats
          • JSON Schema
          • JSON-LD Context
          • Resource Description Framework (RDF)
        • Programming Languages
          • Compiling to Rust
      • RDF Vocabulary
      • 💡TreeLDR Basics
        • Types and Layouts
        • Properties
        • Syntax
  • Witness for Credential Claims
    • 🔭Rebase
      • Core Library
      • Rust Client/Witness SDK
      • WASM Client SDK
      • Simple "Basic Post" Schema
      • DNS Witness Flow Schema
  • References
    • Contributing
    • Code of Conduct
Powered by GitBook
On this page
  • 1. Verify an embedded credential
  • Verify VCs
  • 2. Delegated Verifier

Was this helpful?

  1. SpruceKit Mobile
  2. SpruceKit Mobile SDK
  3. SpruceKit Android SDK
  4. Build a Verifier

Verify a W3C VC

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

PreviousBuild a VerifierNextVerify an mDL in-person/offline

Last updated 4 months ago

Was this helpful?

To implement your OID4VP Server, take a look at our

open source OID4VP library