SelfBackendVerifier

A backend verification class that validates zero-knowledge proofs generated by the Self mobile app.

Constructor

new SelfBackendVerifier(
  scope: string,
  endpoint: string,
  mockPassport: boolean = false,
  allowedIds: Map<AttestationId, boolean>,
  configStorage: IConfigStorage,
  userIdentifierType: UserIdType
)

Parameters

Parameter
Type
Description

scope

string

Your application's unique identifier. Must match the scope used in SelfAppBuilder. Max 30 characters.

endpoint

string

Your backend verification endpoint URL. Must be publicly accessible and match your frontend configuration.

mockPassport

boolean

false for real documents (mainnet), true for testing with mock documents (testnet). Default: false

allowedIds

Map<AttestationId, boolean>

Map of allowed document types. Key: attestation ID, Value: allowed status

configStorage

IConfigStorage

Configuration storage implementation that determines verification requirements

userIdentifierType

UserIdType

Type of user identifier: 'uuid' or 'hex' (for blockchain addresses)

Methods

verify()

Validates zero-knowledge proofs from the Self mobile app.

async verify(
  attestationId: AttestationId,
  proof: VcAndDiscloseProof,
  pubSignals: BigNumberish[],
  userContextData: string
): Promise<VerificationResult>

Parameters

Parameter
Type
Description

attestationId

AttestationId

Document type identifier (1 = electronic passport, 2 = EU ID card)

proof

VcAndDiscloseProof

Zero-knowledge proof object containing cryptographic proof arrays

pubSignals

BigNumberish[]

Public signals from the zero-knowledge proof

userContextData

string

Hex-encoded string containing user context and configuration data

Return Value

The method returns a VerificationResult object with comprehensive verification details:

{
  attestationId: AttestationId;           // Document type that was verified
  isValidDetails: {
    isValid: boolean;                     // Overall cryptographic proof validity
    isOlderThanValid: boolean;            // Age requirement validation
    isOfacValid: boolean;                 // OFAC sanctions check result
  };
  forbiddenCountriesList: string[];      // Countries excluded from the proof
  discloseOutput: {                       // Disclosed document information
    nullifier: string;                    // Unique proof identifier (prevents reuse)
    forbiddenCountriesListPacked: string[];
    issuingState: string;                 // Country that issued the document
    name: string;                         // Full name (if disclosed)
    idNumber: string;                     // Document number
    nationality: string;                  // Nationality
    dateOfBirth: string;                  // Date of birth (if disclosed)
    gender: string;                       // Gender
    expiryDate: string;                   // Document expiry date
    olderThan: string;                    // Age verification result
    ofac: boolean[];                      // OFAC check results [passportNo, nameAndDob, nameAndYob]
  };
  userData: {
    userIdentifier: string;               // User identifier from context
    userDefinedData: string;              // Custom user data
  };
}

Error Handling

The method throws ConfigMismatchError when verification requirements don't match:

try {
  const result = await verifier.verify(attestationId, proof, pubSignals, userContextData);
  // Handle successful verification
} catch (error: any) {
  if (error.name === 'ConfigMismatchError') {
    console.error('Configuration mismatches:', error.issues);
    // error.issues contains detailed information about what failed
  } else {
    console.error('Verification error:', error);
  }
}

Common ConfigMismatch Types:

  • InvalidId - Attestation ID not in allowedIds

  • InvalidScope - Proof was generated for a different application

  • InvalidRoot - Merkle root not found on blockchain

  • InvalidForbiddenCountriesList - Countries don't match configuration

  • InvalidMinimumAge - Age requirement mismatch

  • InvalidTimestamp - Proof timestamp out of valid range (±1 day)

  • InvalidOfac - OFAC check requirements mismatch

  • ConfigNotFound - Configuration not found in storage

Types

VerificationConfig

{
  minimumAge?: number;                  // Minimum age requirement
  excludedCountries?: Country3LetterCode[];  // ISO 3-letter country codes to exclude
  ofac?: boolean;                       // Enable OFAC sanctions checking
}

VcAndDiscloseProof

{
  a: [BigNumberish, BigNumberish];
  b: [[BigNumberish, BigNumberish], [BigNumberish, BigNumberish]];
  c: [BigNumberish, BigNumberish];
}

AttestationId

Document type identifiers:

  • 1 - Electronic passport

  • 2 - EU ID card

ConfigMismatch Error Types

  • InvalidId - Attestation ID not in allowedIds

  • InvalidUserContextHash - User context hash mismatch

  • InvalidScope - Proof was generated for a different application

  • InvalidRoot - Merkle root not found on blockchain

  • InvalidAttestationId - Attestation ID mismatch

  • InvalidForbiddenCountriesList - Countries don't match configuration

  • InvalidMinimumAge - Minimum age requirement mismatch

  • InvalidTimestamp - Proof timestamp out of valid range (±1 day)

  • InvalidOfac - OFAC check requirements mismatch

  • ConfigNotFound - Configuration not found in storage

Configuration Storage Classes

The IConfigStorage interface is crucial for dynamic verification requirements. It determines what to verify based on user context.

DefaultConfigStore

Simple static configuration for uniform verification requirements:

import { DefaultConfigStore } from '@selfxyz/core';

const configStore = new DefaultConfigStore({
  minimumAge: 21,
  excludedCountries: ['IRN', 'PRK'],
  ofac: true
});

// Always returns the same configuration regardless of user or context

InMemoryConfigStore

Enables different verification rules based on user context:

import { InMemoryConfigStore } from '@selfxyz/core';

const configStore = new InMemoryConfigStore(
  async (userIdentifier: string, userDefinedData: string) => {
    // Parse user-defined data to determine requirements
    const context = JSON.parse(userDefinedData);
    
    // Return different config IDs based on context
    if (context.action === 'high_value_transfer') {
      return 'strict_verification';
    } else if (context.action === 'basic_signup') {
      return 'standard_verification';
    }
    return 'default_verification';
  }
);

// Set up different verification configurations
await configStore.setConfig('strict_verification', {
  minimumAge: 21,
  excludedCountries: ['IRN', 'PRK', 'CUB'],
  ofac: true
});

await configStore.setConfig('standard_verification', {
  minimumAge: 18,
  excludedCountries: [],
  ofac: false
});

Best Practices

Configuration Management

  • Use appropriate config storage: DefaultConfigStore for simple apps, InMemoryConfigStore for dynamic requirements

  • Validate attestation IDs: Ensure the attestation ID is in your allowedIds map

Error Handling

  • Always catch ConfigMismatchError: This provides detailed information about verification failures

  • Validate scope matching: Ensure frontend and backend scopes match exactly

Security

  • Store nullifiers: Track used nullifiers in your database to prevent proof reuse

  • Validate input: Always validate all parameters before calling verify()

Development and Testing

  • Use mockPassport: true: Enable for development and testing environments

  • Test different scenarios: Test with various age requirements, countries, and document types

Last updated