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 iOS SDK
  4. Build a Verifier

Verify a W3C VC

Verify a W3C Verifiable Credential with SpruceKit Mobile SDK

This guide is for iOS applications. Building for Android? Look here: Verify a W3C VC

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.


import SwiftUI
import SpruceIDMobileSdkRs

// Here is an example View to scan and try verify a W3C VC JWT VP
struct VerifyVCView: View {
    
    @State var success: Bool?
    
    @Binding var path: NavigationPath
    
    var body: some View {
        if success == nil {
            // Engage the SpruceKit Mobile SDK ScanningComponent
            QRCodeScanner(
                        title: "Scan QR Code",
                        subtitle: "Looking...",
                        onRead: onRead: { code in
                        Task {
                            do {
                                try await verifyJwtVp(jwtVp: code)
                                success = true
                            } catch {
                                success = false
                                print(error)
                            }
                        }
                    },
                        onCancel: onCancel,
                        // example font values
                        titleFont: .customFont(font: .inter, style: .bold, size: .h0),
                        subtitleFont: .customFont(font: .inter, style: .bold, size: .h4),
                        cancelButtonFont: .customFont(font: .inter, style: .medium, size: .h3),
                        readerColor: .white
                    )
            )
        } else {
            // Plug in your Verifier results view
        }
        
    }
}

Verify VCs

Do you know what kind of credential format you are verifying?

import SpruceIDMobileSdkRs

// 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. The DelegatedVerifier allows your Mobile App Verifier to rely on your own web service to handle a PresentationRequest, and receive and validate the response. The Mobile App will then only receive an outcome back from your web service.

2. Delegated Verifier

In the delegated flow, the Verifier generates a QR-code to advertise the PresentationRequest to the Wallet. To use the DelegateVerifier, you will need a back end service that executes 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

struct VerifyDelegatedOid4vpView: View {
    @Binding var path: NavigationPath
    var verificationId: Int64
    var verificationMethod: VerificationMethod?
    var url: URL?
    var baseUrl: String
    
    @State var step = VerifyDelegatedOid4vpViewSteps.loadingQrCode
    @State var status = DelegatedVerifierStatus.initiated
    @State var loading: String? = nil
    @State var errorTitle: String? = nil
    @State var errorDescription: String? = nil
    
    @State var verifier: DelegatedVerifier? = nil
    @State var authQuery: String? = nil
    @State var uri: String? = nil
    @State var presentation: String? = nil

    
    init(path: Binding<NavigationPath>, verificationId: Int64) {
        self._path = path
        self.verificationId = verificationId
        do {
            // Verification method from db
            verificationMethod = try VerificationMethodDataStore
                .shared
                .getVerificationMethod(rowId: verificationId)
                .unwrap()
            
            // Verification method base url
            url = URL(string: verificationMethod!.url)
            
            let unwrappedUrl = try url.unwrap()
                
            baseUrl = unwrappedUrl
                .absoluteString
                .replacingOccurrences(of: unwrappedUrl.path(), with: "")
        } catch {
            self.errorTitle = "Failed Initializing"
            self.errorDescription = error.localizedDescription
            self.verificationMethod = nil
            self.url = URL(string: "")
            self.baseUrl = ""
        }
    }
    
    func monitorStatus(status: DelegatedVerifierStatus) async {
        do {
            let res = try await verifier?.pollVerificationStatus(url: "\(uri.unwrap())?status=\(status)")
            
            if let newStatus = res?.status {
                switch newStatus {
                    // Manage your DelegatedVerifierStatus here
                }
            } else {
                // if can't find res.status, call monitorStatus
                // with the same parameters
                await monitorStatus(status: status)
            }
        } catch {
            errorTitle = "Error Verifying Credential"
            errorDescription = error.localizedDescription
        }
    }
    
    func initiateVerification() {
        Task {
            do {
                let unwrappedUrl = try url.unwrap()

                // Delegated Verifier
                verifier = try await DelegatedVerifier.newClient(baseUrl: baseUrl)
                
                // Get initial parameters to delegate verification
                let delegatedVerificationUrl = "\(unwrappedUrl.path())?\(unwrappedUrl.query() ?? "")"
                let delegatedInitializationResponse = try await verifier
                    .unwrap()
                    .requestDelegatedVerification(url: delegatedVerificationUrl)
                    
                authQuery = "openid4vp://?\(delegatedInitializationResponse.authQuery)"
                
                uri = delegatedInitializationResponse.uri
                
                // Display QR Code
                step = VerifyDelegatedOid4vpViewSteps.presentingQrCode
                
                // Call method to start monitoring status
                await monitorStatus(status: status)
            } catch {
                errorTitle = "Failed getting QR Code"
                errorDescription = error.localizedDescription
            }
        }
    }
    
    func onBack() {
        while !path.isEmpty {
            path.removeLast()
        }
    }
    
    var body: some View {
        ZStack {
            if errorTitle != nil && errorDescription != nil {
                ErrorView(
                    errorTitle: errorTitle!,
                    errorDetails: errorDescription!,
                    onClose: onBack
                )
            } else {
                switch step {
                    //  Manage your VerifyDelegatedOid4vpViewSteps here
                }
            }
        }
        .navigationBarBackButtonHidden(true)
        .onAppear(perform: {
            initiateVerification()
        })
    }
}
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