Decide ID provides proof of personhood verification for applications built on the Internet Computer Protocol (ICP). By leveraging ICP's Internet Identity verifiable credentials system, applications can verify that their users are unique individuals through Decide ID's verification service.
Prerequisites
Your application must be built on the Internet Computer Protocol
Install the DFINITY Verifiable Credentials SDK:
npm install @dfinity/verifiable-credentials
Integration Steps
1. Import Required Dependencies
import { requestVerifiablePresentation, VerifiablePresentationResponse } from "@dfinity/verifiable-credentials/request-verifiable-presentation";
import { Principal } from "@dfinity/principal";
2. Request Verification
To initiate the verification process, call requestVerifiablePresentation with the following configuration:
const requestVerification = async (verifyPrincipal: Principal): Promise<void> => {
try {
const jwt: string = await new Promise((resolve, reject) => {
requestVerifiablePresentation({
onSuccess: async (verifiablePresentation: VerifiablePresentationResponse) => {
if ('Ok' in verifiablePresentation) {
resolve(verifiablePresentation.Ok);
} else {
reject(new Error(verifiablePresentation.Err));
}
},
onError(err) {
reject(new Error(err));
},
issuerData: {
origin: 'https://id.decideai.xyz',
canisterId: Principal.fromText('qgxyr-pyaaa-aaaah-qdcwq-cai'),
},
credentialData: {
credentialSpec: {
credentialType: 'ProofOfUniqueness',
arguments: {
// Specify the minimum date when the user's Decide ID verification must have occurred
// Format: ISO 8601 timestamp
minimumVerificationDate: "2024-12-01T00:00:00Z",
// Specify the minimum reputation level required for verification
// Possible values: "gold", "silver"
minimumReputationLevel: "gold"
},
},
credentialSubject: verifyPrincipal,
},
identityProvider: new URL('https://identity.ic0.app/'),
derivationOrigin: window.location.origin,
});
});
// Verify the JWT credentials received
await verifyCredentials(jwt);
} catch (error) {
console.error('Verification failed:', error);
throw error;
}
};
2. Frontend: Request Verification
The frontend code initiates the verification process and sends the received JWT to your backend canister:
use candid::Principal;
use ic_canister_sig_creation::IC_ROOT_PK_DER;
use identity_credential::validator::JwtValidationError;
#[derive(Debug)]
pub struct VerificationError {
message: String,
}
#[update]
async fn verify_credential(vp_jwt: String) -> Result<(), String> {
let current_time_ns = ic_cdk::api::time(); // Get current IC time in nanoseconds
// The subject we expect in the credential (typically the caller's principal)
let effective_subject = ic_cdk::api::caller();
// Your application's origin that was used in the credential request
let derivation_origin = "https://yourdapp.ic0.app";
// Configure the verification parameters
let vc_flow_signers = VcFlowSigners {
// Internet Identity canister ID
ii_canister_id: Principal::from_text("rdmx6-jaaaa-aaaaa-aaadq-cai").unwrap(),
ii_origin: "https://identity.ic0.app/".to_string(),
// Decide ID canister ID
issuer_canister_id: Principal::from_text("qgxyr-pyaaa-aaaah-qdcwq-cai").unwrap(),
issuer_origin: "https://id.decideai.xyz".to_string(),
};
// The credential specification that matches what was requested
let vc_spec = CredentialSpec {
credential_type: "ProofOfUniqueness".to_string(),
arguments: {
let mut args = HashMap::new();
args.insert(
"minimumVerificationDate".to_string(),
ArgumentValue::String("2024-12-10T00:00:00Z".to_string())
);
Some(args)
},
};
// Verify the presentation and all included credentials
validate_ii_presentation_and_claims(
&vp_jwt,
effective_subject,
derivation_origin.to_string(),
&vc_flow_signers,
&vc_spec,
IC_ROOT_PK_DER, // IC root public key for verifying canister signatures
current_time_ns,
).map_err(|e| format!("Verification failed: {:?}", e))?;
// If verification succeeds, store the verified state
// This is application-specific - implement based on your needs
Ok(())
}
Motoko Canister Example ( not available )
Currently Motoko backend support is not available
These backend verification steps are crucial for security as they:
Cannot be tampered with by end users
Use secure IC cryptographic primitives
Can maintain authoritative state about verified users
Can integrate with your canister's other security measures
⚠️ Important: Never rely on client-side verification alone. Always verify credentials in your backend canister.
## Error Handling
The verification process can return several types of errors:
```typescript
type VerificationError = {
version: string;
code: 'UNKNOWN' | 'TIMEOUT' | 'USER_ABORT' | 'INVALID_CREDENTIALS';
};
// Handle errors appropriately in your application
const handleVerificationError = (error: VerificationError) => {
switch (error.code) {
case 'TIMEOUT':
// Handle timeout
break;
case 'USER_ABORT':
// Handle user cancellation
break;
case 'INVALID_CREDENTIALS':
// Handle invalid credentials
break;
default:
// Handle unknown errors
break;
}
};
Verification Requirements
Date Requirements
The minimumVerificationDate parameter is a critical security feature that helps ensure the authenticity of user verifications. When specified, Decide ID will only accept verifications that were performed on or after the given date.
Usage:
typescriptCopyminimumVerificationDate: "2024-01-01T00:00:00Z" // ISO 8601 format
Reputation Level Requirements
The minimumReputationLevel parameter allows you to specify the required reputation level for verification. DecideAI implements a two-tier reputation system:
Gold: The highest reputation level, assigned to newly verified users
Silver: Users are automatically downgraded to silver after two weeks, requiring reverification to regain gold status. Note if a user is gold and you provide silver as the minimum then the credential request will succeed because they have a higher level than requested.
Usage:
typescriptCopyminimumReputationLevel: "gold" // Possible values: "gold", "silver"
Security Note: Both the minimumVerificationDate and minimumReputationLevel parameters in the credential request must be verified exactly in your backend canister. This ensures that:
The parameters haven't been modified from what your application requested
Prevents tampering with the verification requirements
Maintains consistent security standards across your application
When verifying, don't just check if the date is recent enough or if the reputation level is high enough - verify they match exactly what you requested.
Best Practices
Error Handling: Implement comprehensive error handling for various failure scenarios.
User Experience: Provide clear feedback to users during the verification process.
Security: Always verify both the cryptographic signatures and semantic content of received credentials.
Caching: Consider caching verification results (with appropriate expiration) to improve user experience.
Security Considerations
Always verify the issuer's canister ID matches Decide ID's official canister
Implement proper session management for verified users