Duration: 90 minutes
Prerequisites: Node.js, basic TypeScript knowledge, understanding of digital certificates
Learning Goals:
The BSV ecosystem uses a decentralized identity system based on cryptographic certificates. The IdentityClient
provides tools for managing identity certificates, verifying identities, and building identity-aware applications.
WalletClient
import { IdentityClient, WalletClient } from '@bsv/sdk'
async function basicIdentityOperations() {
const wallet = new WalletClient()
const identityClient = new IdentityClient(wallet)
console.log('Identity client initialized')
// Get our identity key
const { publicKey: identityKey } = await wallet.getPublicKey({
identityKey: true
})
console.log('Our identity key:', identityKey.substring(0, 20) + '...')
return { identityClient, identityKey }
}
basicIdentityOperations().catch(console.error)
import { IdentityClient, WalletClient } from '@bsv/sdk'
async function resolveIdentityByKey(identityKey: string) {
const identityClient = new IdentityClient()
try {
console.log('Resolving identity for key:', identityKey.substring(0, 20) + '...')
const identities = await identityClient.resolveByIdentityKey({
identityKey
})
console.log('Found identities:', identities.length)
identities.forEach((identity, index) => {
console.log(`Identity ${index + 1}:`)
console.log(' Name:', identity.name)
console.log(' Badge:', identity.badgeLabel)
console.log(' Avatar:', identity.avatarURL)
console.log(' Key:', identity.abbreviatedKey)
})
return identities
} catch (error) {
console.error('Failed to resolve identity:', error)
return []
}
}
// Example usage (replace with actual identity key)
// resolveIdentityByKey('actual-identity-key-here').catch(console.error)
import { IdentityClient } from '@bsv/sdk'
async function resolveIdentityByAttributes() {
const identityClient = new IdentityClient()
try {
console.log('Searching for identities by attributes...')
const identities = await identityClient.resolveByAttributes({
attributes: {
email: 'user@example.com'
}
})
console.log('Found identities with matching attributes:', identities.length)
identities.forEach((identity, index) => {
console.log(`Match ${index + 1}:`)
console.log(' Name:', identity.name)
console.log(' Badge:', identity.badgeLabel)
console.log(' Identity Key:', identity.identityKey.substring(0, 20) + '...')
})
return identities
} catch (error) {
console.error('Failed to resolve by attributes:', error)
return []
}
}
resolveIdentityByAttributes().catch(console.error)
import { IdentityClient, WalletClient } from '@bsv/sdk'
interface IdentityRecord {
identityKey: string
name: string
badgeLabel: string
avatarURL: string
verificationStatus: 'verified' | 'unverified' | 'pending'
certificates: any[]
lastUpdated: Date
}
class IdentityManager {
private identityClient: IdentityClient
private wallet: WalletClient
private identityCache: Map<string, IdentityRecord> = new Map()
constructor(wallet?: WalletClient) {
this.wallet = wallet || new WalletClient()
this.identityClient = new IdentityClient(this.wallet)
}
async getOurIdentity(): Promise<string> {
const { publicKey } = await this.wallet.getPublicKey({
identityKey: true
})
return publicKey
}
async verifyIdentity(identityKey: string): Promise<IdentityRecord | null> {
try {
console.log('Verifying identity:', identityKey.substring(0, 20) + '...')
// Check cache first
const cached = this.identityCache.get(identityKey)
if (cached && this.isCacheValid(cached)) {
console.log('Using cached identity data')
return cached
}
// Resolve identity from network
const identities = await this.identityClient.resolveByIdentityKey({
identityKey
})
if (identities.length === 0) {
console.log('No identity found for key')
return null
}
// Use the first identity found
const identity = identities[0]
const record: IdentityRecord = {
identityKey,
name: identity.name,
badgeLabel: identity.badgeLabel,
avatarURL: identity.avatarURL,
verificationStatus: 'verified',
certificates: [], // Would contain actual certificates
lastUpdated: new Date()
}
// Cache the result
this.identityCache.set(identityKey, record)
console.log('Identity verified:', record.name)
return record
} catch (error) {
console.error('Identity verification failed:', error)
return null
}
}
async searchIdentities(query: {
name?: string
email?: string
attributes?: Record<string, string>
}): Promise<IdentityRecord[]> {
try {
console.log('Searching identities with query:', query)
const searchAttributes = {
...query.attributes,
...(query.name && { name: query.name }),
...(query.email && { email: query.email })
}
const identities = await this.identityClient.resolveByAttributes({
attributes: searchAttributes
})
const records: IdentityRecord[] = identities.map(identity => ({
identityKey: identity.identityKey,
name: identity.name,
badgeLabel: identity.badgeLabel,
avatarURL: identity.avatarURL,
verificationStatus: 'verified' as const,
certificates: [],
lastUpdated: new Date()
}))
console.log('Found', records.length, 'matching identities')
return records
} catch (error) {
console.error('Identity search failed:', error)
return []
}
}
async revealPublicAttributes(
certificate: any,
fieldsToReveal: string[]
): Promise<boolean> {
try {
console.log('Revealing public attributes:', fieldsToReveal)
const result = await this.identityClient.publiclyRevealAttributes(
certificate,
fieldsToReveal
)
console.log('Attributes revealed successfully')
return true
} catch (error) {
console.error('Failed to reveal attributes:', error)
return false
}
}
private isCacheValid(record: IdentityRecord): boolean {
const cacheAge = Date.now() - record.lastUpdated.getTime()
const maxAge = 60 * 60 * 1000 // 1 hour
return cacheAge < maxAge
}
getCachedIdentities(): IdentityRecord[] {
return Array.from(this.identityCache.values())
}
clearCache(): void {
this.identityCache.clear()
console.log('Identity cache cleared')
}
}
async function demonstrateIdentityManager() {
const identityManager = new IdentityManager()
console.log('=== Identity Manager Demo ===')
// Get our own identity
const ourIdentity = await identityManager.getOurIdentity()
console.log('Our identity key:', ourIdentity.substring(0, 20) + '...')
// Search for identities
const searchResults = await identityManager.searchIdentities({
name: 'John'
})
console.log('Search results:', searchResults.length)
// Verify specific identities
for (const result of searchResults.slice(0, 2)) { // Limit to first 2
const verified = await identityManager.verifyIdentity(result.identityKey)
if (verified) {
console.log('Verified identity:', verified.name)
}
}
// Show cached identities
const cached = identityManager.getCachedIdentities()
console.log('Cached identities:', cached.length)
return { ourIdentity, searchResults, cached }
}
demonstrateIdentityManager().catch(console.error)
import { IdentityClient, WalletClient } from '@bsv/sdk'
interface AuthenticationResult {
success: boolean
identityKey?: string
identity?: any
error?: string
}
class IdentityAuthService {
private identityClient: IdentityClient
private authenticatedUsers: Map<string, {
identity: any
sessionStart: Date
lastActivity: Date
}> = new Map()
constructor(wallet?: WalletClient) {
this.identityClient = new IdentityClient(wallet)
}
async authenticateUser(identityKey: string): Promise<AuthenticationResult> {
try {
console.log('Authenticating user:', identityKey.substring(0, 20) + '...')
// Resolve identity
const identities = await this.identityClient.resolveByIdentityKey({
identityKey
})
if (identities.length === 0) {
return {
success: false,
error: 'Identity not found'
}
}
const identity = identities[0]
// Create session
this.authenticatedUsers.set(identityKey, {
identity,
sessionStart: new Date(),
lastActivity: new Date()
})
console.log('User authenticated:', identity.name)
return {
success: true,
identityKey,
identity
}
} catch (error) {
console.error('Authentication failed:', error)
return {
success: false,
error: error.message
}
}
}
async verifySession(identityKey: string): Promise<boolean> {
const session = this.authenticatedUsers.get(identityKey)
if (!session) {
return false
}
// Check session timeout (24 hours)
const sessionAge = Date.now() - session.sessionStart.getTime()
const maxAge = 24 * 60 * 60 * 1000
if (sessionAge > maxAge) {
this.authenticatedUsers.delete(identityKey)
return false
}
// Update last activity
session.lastActivity = new Date()
return true
}
async requireAuthentication(identityKey: string): Promise<{
authorized: boolean
identity?: any
error?: string
}> {
const isValid = await this.verifySession(identityKey)
if (!isValid) {
return {
authorized: false,
error: 'Authentication required'
}
}
const session = this.authenticatedUsers.get(identityKey)
return {
authorized: true,
identity: session?.identity
}
}
logout(identityKey: string): void {
this.authenticatedUsers.delete(identityKey)
console.log('User logged out:', identityKey.substring(0, 20) + '...')
}
getActiveSessions(): Array<{
identityKey: string
name: string
sessionStart: Date
lastActivity: Date
}> {
return Array.from(this.authenticatedUsers.entries()).map(([key, session]) => ({
identityKey: key,
name: session.identity.name,
sessionStart: session.sessionStart,
lastActivity: session.lastActivity
}))
}
}
async function demonstrateAuthentication() {
const authService = new IdentityAuthService()
console.log('=== Identity Authentication Demo ===')
// Simulate user authentication
const wallet = new WalletClient()
const { publicKey: userIdentity } = await wallet.getPublicKey({
identityKey: true
})
// Authenticate user
const authResult = await authService.authenticateUser(userIdentity)
if (authResult.success) {
console.log('✅ Authentication successful')
console.log('User:', authResult.identity?.name || 'Unknown')
// Verify session
const sessionValid = await authService.verifySession(userIdentity)
console.log('Session valid:', sessionValid)
// Test authorization
const authCheck = await authService.requireAuthentication(userIdentity)
console.log('Authorization check:', authCheck.authorized ? 'PASSED' : 'FAILED')
// Show active sessions
const sessions = authService.getActiveSessions()
console.log('Active sessions:', sessions.length)
// Logout
authService.logout(userIdentity)
console.log('User logged out')
} else {
console.log('❌ Authentication failed:', authResult.error)
}
return authResult
}
demonstrateAuthentication().catch(console.error)
```typescript import { IdentityClient, WalletClient } from ‘@bsv/sdk’
interface VerificationRequest { identityKey: string requiredCertificates: string[] purpose: string timestamp: Date }
interface VerificationResult { verified: boolean identityKey: string certificates: any[] trustScore: number issues: string[] }
class IdentityVerificationService { private identityClient: IdentityClient private verificationHistory: Map<string, VerificationResult[]> = new Map()
constructor(wallet?: WalletClient) { this.identityClient = new IdentityClient(wallet) }
async verifyIdentity(request: VerificationRequest): Promise
const result: VerificationResult = {
verified: false,
identityKey: request.identityKey,
certificates: [],
trustScore: 0,
issues: []
}
try {
// Resolve identity
const identities = await this.identityClient.resolveByIdentityKey({
identityKey: request.identityKey
})
if (identities.length === 0) {
result.issues.push('Identity not found')
return result
}
const identity = identities[0]
// Calculate trust score based on available information
result.trustScore = this.calculateTrustScore(identity)
// Check if verification meets requirements
if (result.trustScore >= 70) { // Minimum trust score
result.verified = true
console.log('✅ Identity verified:', identity.name)
} else {
result.issues.push('Insufficient trust score')
console.log('❌ Identity verification failed: low trust score')
}
// Store verification history
const history = this.verificationHistory.get(request.identityKey) || []
history.push(result)
this.verificationHistory.set(request.identityKey, history)
} catch (error) {
result.issues.push(`Verification error: ${error.message}`)
console.error('Verification error:', error)
}
return result }
private calculateTrustScore(identity: any): number { let score = 0
// Base score for having an identity
score += 30
// Score for having a name
if (identity.name && identity.name !== 'Unknown') {
score += 20
}
// Score for having an avatar
if (identity.avatarURL) {
score += 10
}
// Score for having a badge
if (identity.badgeLabel) {
score += 20
}
// Additional score for verified badge
if (identity.badgeLabel?.includes('Verified')) {
score += 20
}
return Math.min(score, 100) // Cap at 100 }
async batchVerify(identityKeys: string[], purpose: string): Promise<{
verified: VerificationResult[]
failed: VerificationResult[]
}> {
console.log(Starting batch verification of ${identityKeys.length} identities
)
const requests = identityKeys.map(key => ({
identityKey: key,
requiredCertificates: [],
purpose,
timestamp: new Date()
}))
const results = await Promise.all(
requests.map(request => this.verifyIdentity(request))
)
const verified = results.filter(r => r.verified)
const failed = results.filter(r => !r.verified)
console.log(`Batch verification complete: ${verified.length} verified, ${failed.length} failed`)
return { verified, failed } }
getVerificationHistory(identityKey: string): VerificationResult[] { return this.verificationHistory.get(identityKey) || [] }
getTrustStatistics(): { totalVerifications: number successRate: number averageTrustScore: number } { let totalVerifications = 0 let successfulVerifications = 0 let totalTrustScore = 0
for (const history of this.verificationHistory.values()) {
for (const result of history) {
totalVerifications++
totalTrustScore += result.trustScore
if (result.verified) {
successfulVerifications++
}
}
}
return {
totalVerifications,
successRate: totalVerifications > 0 ? successfulVerifications / totalVerifications : 0,
averageTrustScore: totalVerifications > 0 ? totalTrustScore / totalVerifications : 0
} } }
async function demonstrateVerificationService() { const verificationService = new IdentityVerificationService()
console.log(‘=== Identity Verification Service Demo ===’)
// Create test identities const wallet1 = new WalletClient() const wallet2 = new WalletClient()
const { publicKey: identity1 } = await wallet1.getPublicKey({ identityKey: true }) const { publicKey: identity2 } = await wallet2.getPublicKey({ identityKey: true })
const testIdentities = [identity1, identity2]
// Batch verification const batchResult = await verificationService.batchVerify( testIdentities, ‘User registration verification’ )
console.log(‘Batch verification results:’) console.log(‘ Verified:’, batchResult.verified.length) console.log(‘ Failed:’, batchResult.failed.length)
// Individual verification with details for (const identity of testIdentities.slice(0, 1)) { // Just first one const request: VerificationRequest = { identityKey: identity, requiredCertificates: [‘identity’], purpose: ‘Account access verification’, timestamp: new Date() }
const result = await verificationService.verifyIdentity(request)
console.log(`\nVerification for ${identity.substring(0, 20)}...`)
console.log(' Verified:', result.verified)
console.log(' Trust Score:', result.trustScore)
console.log(' Issues:', result.issues) }
// Get statistics const stats = verificationService.getTrustStatistics() console.log(‘\nVerification Statistics:’) console.log(‘ Total Verifications:’, stats.totalVerifications) console.log(‘ Success Rate:’, (stats.successRate * 100).toFixed(1) + ‘%’) console.log(‘ Average Trust Score:’, stats.averageTrustScore.toFixed(1))
return { batchResult, stats } }
demonstrateVerificationService().catch(console.error)