Proofs

When a proof request is received an event will be emitted. There are two options for handling proofs: attempt to auto-accept and process the proof, or manually select credentials. A proof request can be automatically accepted if the request does not have any attributes that need to be self-attested (provided manually from the user) and there are sufficient credentials in the wallet.

A single proof request can contain multiple proofs that need to be satisfied and in turn can make manual selection complicated.

A proof event contains the proof record and the didExchangeId of the contact that it came from. The initial state for the proof record is requestReceived.

1

Auto Accepting

This flow attempts to automatically select credentials and accept the proof. It only succeeds if there are no required self-attested attributes and the wallet contains sufficient credentials.

Kotlin

Auto-accept proof (Kotlin)
// Gets the first proof event received, blocks whatever thread it is ran on.
val proofEvent = agent.events.getProofEvents().first()

try {
    agent.proofs.autoAcceptProof(proofEvent.proofRecord.id, proofEvent.didExchangeId)
} catch (e: Throwable) {
    println("An error occurred auto-accepting proof, message: ${e.message}")
}

React Native

Auto-accept proof (React Native / TypeScript)
const removeProofHandler = agent.events.registerProofHandler(
    (event) => {
        try {
            if (event.proofRecord.state === ProofState.REQUEST_RECEIVED) {
                await agent.proofs.autoAcceptProof(
                    event.proofRecord.id,
                    event.exchangeId
                );
            }
        } catch (error) {
            console.log(`An error ocurred auto-accepting proof, message ${error.message}`)
        }
    }
)

That is all it takes to fulfill an automatic proof request.

Reminder: this only works if there are not self-attested attributes for the request and the wallet contains sufficient credentials.

2

Manual Acceptance

Manual acceptance has two possible flows:

  • Let the agent auto-select credentials and return them to you so you can fill in any self-attested values.

  • Have the agent return all potential credentials that satisfy the proof, so you manually choose which to use.

Both options will throw if the wallet does not contain sufficient credentials for the proof request.

Kotlin

Manual acceptance - autoSelect or getCredentials (Kotlin)
val proofEvent = agent.events.getProofEvents().first()

// Returns a list of pairs containing first the proof and then the credential(s) selected
val proofAttributes: SelectedCredentialsForProof = agent.proofs.autoSelectCredentialsForProof(
    proofEvent.proofRecord.id,
    proofEvent.didExchangeId, 
    nonRevoked = false
) // nonRevoked indicates if you care if the credentials selected are revoked or not

// Or

// Returns a similar object but can potentially contain multiple credentials that need to be selected from
val proofAttributes: SelectedCredentials = agent.proofs.getCredentialsForProofRequest(
    proofEvent.proofRecord.id, 
    proofEvent.didExchangeId, 
    nonRevoked = false
)

React Native

Manual acceptance - autoSelect or getCredentials (React Native / TypeScript)
const removeProofHandler = agent.events.registerProofHandler(async (event) => {
    const proofAttributes = await agent.proofs.autoSelectCredentialsForProof(
        event.proofRecord.id,
        event.didExchangeId,
        false
    )

    // Or

    const proofAttributes = await agent.proofs.getCredentialsForProofRequest(
        event.proofRecord.id,
        event.didExchangeId,
        false
    )
})

The return from both of these functions is a PresentationData object. With the auto-select function having some data already filled in.

PresentationData structure and helpers

The PresentationData object contains four properties: proofId, exchangeId, attributes, and predicates (the last two being arrays). It also contains helper functions:

  • getRemaining — returns an array of the remaining proofReferent that do not have a selection.

  • isReady — returns a boolean that indicates if a valid selection has been made for all proofReferents.

  • autoSelect — does an in-place auto selection of the provided credentials and returns a boolean indicating if it successfully made selections for all request referents.

  • getRequiredSelfAttested — returns a list of all the attributes that are required to be self-attested.

The attributes and predicates arrays contain objects called attributeReferent and predicateReferent (two types of proofReferent). These objects contain the properties canSelfAttest, requiredSelfAttest, and selfAttestedValue. These properties pertain to self-attesting during a proof (only available with an attribute and not a predicate).

  • canSelfAttest indicates if the value can be self-attested.

  • requiredSelfAttest indicates if the value must be self-attested.

  • selfAttestedValue is a mutable string that should be set to data not in a credential (e.g., user input or from elsewhere in the app).

Each proofReferent also has three object properties: selection, credentials, and request.

  • selection is the credential match you want to use to satisfy the proofReferent. It can be set using the selectCredential function which takes a credentialMatch object or an index corresponding to a value in the credentials array.

  • credentials is an array of all the credentials that satisfy the proofReferent.

  • request is the actual object that indicates what data is being requested from the wallet.

Differences between attributeReferent and predicateReferent:

  • predicateReferent also has a requirement string that indicates the relational requirement for the requested data.

  • Predicates should not be self-attested and thus should always return false for self-attested values.

Filling in self-attested values is intended to be done in place. If an optional self-attested attribute is supplied it will be given priority over any supplied credential value.

Auto selection flow (processing returned PresentationData)

Kotlin:

Auto-selection handling (Kotlin)
val proofData = agent.proofs.autoSelectCredentialsForProof(
    proofEvent.proofRecord.id,
    proofEvent.didExchangeId, 
    nonRevoked = false
)

// Check if there are any required self-attested attributes
val selfAttested = proofData.getRequiredSelfAttested()
if(selftAttested.size != 0){
    selfAttested.forEach{ referent -> 
        referent.selfAttestedValue = "Data from somewhere else"
    }
}

// Supply the originally returned object that has been modified in place
agent.proofs.acceptProofs(proofData)

React Native / TypeScript:

Auto-selection handling (React Native / TypeScript)
const proofData = await agent.proofs.autoSelectCredentialsForProof(
    event.proofRecord.id,
    event.didExchangeId,
    false
)

const selfAttested = proofData.getRequiredSelfAttested()

if(selfAttested.size != 0) {
    selfAttested.forEach((referent) => {
        referent.selfAttestedValue = "Data from somewhere else"
    })
}

await agent.proofs.acceptProofs(proofData)

Manual Selection

Self-attested attributes function the same way for manual selection.

Manual selection requires that a credential from the returned list be selected for each referent in the proof. This allows the end user to select exactly what credentials are shared but is more complex to process.

Kotlin:

Manual selection (Kotlin)
val proofData = agent.proofs.getCredentialsForProofRequest(
    proofEvent.proofRecord.id,
    proofEvent.didExchangeId, 
    nonRevoked = false
)

// Goes through all attributes and picks the first credential that matches
proofData.attributes.forEach{ attribute => 
    attribute.selectCredential(0)
}

proofData.predicates.forEach{ predicate => 
    predicate.selectCredential(0)
}

agent.proofs.acceptProofs(proofData)

React Native / TypeScript:

Manual selection (React Native / TypeScript)
const proofData = await agent.proofs.getCredentialsForProofRequest(
    proofEvent.proofRecord.id,
    proofEvent.didExchangeId, 
    nonRevoked = false
)

proofData.attributes.forEach((attribute) => {
    attribute.selectCredential(0)
})

proofData.predicates.forEach((predicate) => {
    predicate.selectCredential(0)
})

await agent.proofs.acceptProofs(proofData)

Last updated

Was this helpful?