Skip to content

Credential Verification

Verification Requests

Think of a verification request like asking someone for their ID.

You want to confirm a specific credential of theirs, say, their email address. You send a request to the issuer of the credential (the one who "issued their ID"). The issuer can either give a thumbs-up (approve) or thumbs-down (reject).

How to Send a Verification Request

This is akin to saying, "Hey, can you confirm this is Bob's email address? It's bob@test.com."

content, err := message.NewCredentialVerificationRequest().
    Type([]string{"VerifiableCredential", "EmailCredential"}).
    Parameter("email", "bob@test.com").
    Expires(time.Now().Add(time.Hour * 24)).
    Finish()
if err != nil {
    // handle error
}

err = selfAccount.MessageSend(address, content)
if err != nil {
    // handle error
}
1
2
3
4
5
6
7
8
val request = CredentialVerificationRequestBuilder()
    .type(arrayOf("VerifiableCredential", "EmailCredential"))
    .parameter("email", "bob@test.com")
    .expires(Timestamp.now() + 3600 * 24)
    .finish()

val sendStatus = account.messageSend(address, request)
println("send verification request status:${sendStatus.code()} - requestId:${request.id().toHexString()}")
val emailDTO = DataObject.Builder()
    .setData("bob@test.com".encodeToByteArray())
    .setContentType("text/plain")
    .build()
val codeDTO = DataObject.Builder()
    .setData("123456".encodeToByteArray()) // code from SecurityCodeRequest
    .setContentType("text/plain")
    .build()

val proofs = mapOf(
    Constants.SUBJECT_EMAIL to emailDTO,
    Constants.SUBJECT_SECURITY_CODE to codeDTO,
)

val verificationRequest = VerificationRequest.Builder()
    .setTypes(listOf(CredentialType.Email))
    .setProofs(proofs)
    .build()

account.send(verificationRequest) { messageId, error ->
    println("verification request $messageId")
}
let emailDTO = DataObject.Builder()
    .withData("bob@test.com".data(using: .utf8))
    .withContentType("text/plain")
    .build()
let codeDTO = DataObject.Builder()
    .withData("123456".data(using: .utf8))
    .withContentType("text/plain")
    .build()

let proofs = [
    Constants.SUBJECT_EMAIL: emailDTO,
    Constants.SUBJECT_SECURITY_CODE: codeDTO,
]

let verificationRequest = VerificationRequest.Builder()
        .withTypes([CredentialType.Email])
        .withProofs(proofs)
        .build()

// send the request
Task(priority: .background, operation: {
    try await self.account.send(message: verificationRequest, onAcknowledgement: {requestId, error in
        print("sent verification request: \(requestId) with error: \(error)")
    })
})

How to Receive a Verification Response

case message.TypeCredentialVerificationResponse:
    response, err := message.DecodeCredentialVerificationResponse(msg)
    if err != nil {
        // handle error
    }

    // Check the status
    log.Info("Response received with status", "status", response.Status())

    // Validate each credential
    for _, c := range response.Credentials() {
        err = c.Validate()
        if err != nil {
            // handle error
            continue
        }

        claims, err := c.CredentialSubjectClaims()
        if err != nil {
            // handle error
            continue
        }

        // Access specific claims
        println(claims["email"])
    }
ContentType.CREDENTIAL_VERIFICATION_RESPONSE -> {
    val response = CredentialVerificationResponse.decode(content)
    println("Response received with status: ${response.status().name}")

    // Validate each credential
    response.credentials().forEach { credential ->
        try {
            credential.validate()
            val claims = credential.credentialSubjectClaims()

            // Access specific claims
            println("Email: ${claims["email"]}")
        } catch (ex: Exception) {
            println("Failed to validate credential: ${ex.message}")
        }
    }
}
account.setOnResponseListener { msg ->
    when (msg) {
        is VerificationResponse -> {
            println("Response received with status:${msg.status().name}")
            msg.credentials().forEach { credential ->
                println("credential types: ${credential.types()}")
                credential.claims().forEach { claim ->
                    println("email value ${claim.value()}")
                }
            }
        }
    }
}
account.setOnResponseListener { message in
    print("setOnResponseListener: \(message)")
    switch message {
    case is VerificationResponse:
        let response = message as! VerificationResponse
        print("Handle verification response: \(response)")

    default:
        print("TODO: Handle For other response: \(message)")
        break;
    }
}

Verification flows in Android/iOS SDK

The Android and iOS SDKs provide a streamlined way to integrate identity verification flows into your mobile application. These flows support the capture and validation of the following user credentials: Email address, Passport, ID card

Integrate the SDK’s pre-built UI components into your app to guide users through each verification step. This includes interfaces for entering an email address, capturing images of passports or ID cards, and confirming submitted data.

After verification, the SDK stores the verified credentials securely in the device's local database. This can later be used to fulfill presentation requests.

Below are code examples in a simple MainActivity on how to integrate the email, document verification flow in the app.

class MainActivity : ComponentActivity() {    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // setup sdk and account        

        val account = Account.Builder()
            .setContext(applicationContext)
            .setEnvironment(Environment)
            .setSandbox(true)
            .setStoragePath(storagePath.absolutePath)
            .build()

        setContent {
            val coroutineScope = rememberCoroutineScope()
            val navController = rememberNavController()
            val selfModifier = SelfModifier.sdk()

            val claims = remember { mutableStateListOf<Claim>() }

            // get verified credentials from sdk
            fun refreshClaims() {
                val credentials = account.credentialsByType()
                claims.clear()
                claims.addAll(credentials.flatMap { cred -> cred.credentials.flatMap { it.claims() } })
            }

            NavHost(navController = navController,
                startDestination = "main",
                modifier = Modifier.systemBarsPadding(),
                enterTransition = { EnterTransition.None },
                exitTransition = { ExitTransition.None }
            ) {
                // see the full UI in the example link above

                // integrate email verification flow
                addEmailRoute(navController, route = "emailRoute", selfModifier = selfModifier,
                    account = { account },
                    onFinish = { error ->
                        if (error == null) {
                            refreshClaims() // refresh email credentials to display

                            coroutineScope.launch(Dispatchers.Main) {
                                Toast.makeText(applicationContext, "Email verification successfully", Toast.LENGTH_LONG).show()
                            }
                        }
                    }
                )

                // integrate passport, idcard verification flow
                addDocumentVerificationRoute(navController, route = "documentRoute", selfModifier = selfModifier,account = { account },
                    isDevMode = { false }, // true for testing only
                    onFinish = { error ->
                        if (error == null) {
                            refreshClaims() // refresh email credentials to display

                            coroutineScope.launch(Dispatchers.Main) {
                                Toast.makeText(applicationContext, "Document verification successfully", Toast.LENGTH_LONG).show()
                            }
                        }
                    }
                )
            }
        }
    }
}