@bloque/sdk-identity 0.0.22 → 0.0.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -942
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,944 +1,5 @@
|
|
|
1
|
-
#
|
|
1
|
+
# `@bloque/sdk-identity`
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
⚠️ **Warning**: This package is intended for internal use. Its release cycle does not follow SemVer, which means we might release breaking changes (change APIs, remove functionality) without any prior warning.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
- **Identity Registration**: Register individual users (KYC) and businesses (KYB) to authentication origins
|
|
8
|
-
- **Multi-Origin Support**: Register identities across blockchain, OAuth, API key, and custom origins
|
|
9
|
-
- **Origin Management**: List and discover all available authentication origins
|
|
10
|
-
- **Aliases**: Get user identity information by email or phone
|
|
11
|
-
- **OTP Origins**: Send OTP codes via WhatsApp or Email
|
|
12
|
-
- **Custom Origins**: Support for custom authentication origins
|
|
13
|
-
- **Multiple Authentication Methods**: SIGNING_CHALLENGE, API_KEY, OAUTH_REDIRECT, WEBAUTHN, OTP, PASSWORD
|
|
14
|
-
- **TypeScript First**: Built with TypeScript for complete type safety
|
|
15
|
-
|
|
16
|
-
## Installation
|
|
17
|
-
|
|
18
|
-
```bash
|
|
19
|
-
bun add @bloque/sdk-identity
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
## Usage
|
|
23
|
-
|
|
24
|
-
This package is typically used through the main `@bloque/sdk` package, but can be used standalone:
|
|
25
|
-
|
|
26
|
-
```typescript
|
|
27
|
-
import { HttpClient } from '@bloque/sdk-core';
|
|
28
|
-
import { IdentityClient } from '@bloque/sdk-identity';
|
|
29
|
-
|
|
30
|
-
const httpClient = new HttpClient({
|
|
31
|
-
apiKey: process.env.BLOQUE_API_KEY!,
|
|
32
|
-
mode: 'production',
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
const identity = new IdentityClient(httpClient);
|
|
36
|
-
|
|
37
|
-
// Get alias information
|
|
38
|
-
const alias = await identity.aliases.get('user@example.com');
|
|
39
|
-
console.log('User URN:', alias.urn);
|
|
40
|
-
console.log('Alias status:', alias.status);
|
|
41
|
-
|
|
42
|
-
// Send OTP via WhatsApp
|
|
43
|
-
const otpWhatsApp = await identity.origins.whatsapp.assert('+1234567890');
|
|
44
|
-
console.log('OTP sent to:', otpWhatsApp.value.phone);
|
|
45
|
-
console.log('Expires at:', otpWhatsApp.value.expires_at);
|
|
46
|
-
|
|
47
|
-
// Send OTP via Email
|
|
48
|
-
const otpEmail = await identity.origins.email.assert('user@example.com');
|
|
49
|
-
console.log('OTP sent to:', otpEmail.value.email);
|
|
50
|
-
console.log('Attempts remaining:', otpEmail.params.attempts_remaining);
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
## API Reference
|
|
54
|
-
|
|
55
|
-
### Aliases
|
|
56
|
-
|
|
57
|
-
#### `aliases.get(alias)`
|
|
58
|
-
|
|
59
|
-
Retrieve alias information by the alias value (email or phone):
|
|
60
|
-
|
|
61
|
-
```typescript
|
|
62
|
-
const alias = await identity.aliases.get('user@example.com');
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
**Parameters**:
|
|
66
|
-
- `alias` (string): Email address or phone number
|
|
67
|
-
|
|
68
|
-
**Response**:
|
|
69
|
-
|
|
70
|
-
```typescript
|
|
71
|
-
interface Alias {
|
|
72
|
-
id: string; // Unique alias ID
|
|
73
|
-
alias: string; // Alias value
|
|
74
|
-
type: 'phone' | 'email' | string; // Alias type
|
|
75
|
-
urn: string; // Associated user URN
|
|
76
|
-
origin: string; // Origin identifier
|
|
77
|
-
details: {
|
|
78
|
-
phone?: string; // Phone details (if applicable)
|
|
79
|
-
};
|
|
80
|
-
metadata: {
|
|
81
|
-
alias: string; // Alias in metadata
|
|
82
|
-
[key: string]: unknown; // Additional metadata
|
|
83
|
-
};
|
|
84
|
-
status: 'active' | 'inactive' | 'revoked'; // Alias status
|
|
85
|
-
is_public: boolean; // Whether alias is public
|
|
86
|
-
is_primary: boolean; // Whether this is the primary alias
|
|
87
|
-
created_at: string; // Creation timestamp (ISO 8601)
|
|
88
|
-
updated_at: string; // Last update timestamp (ISO 8601)
|
|
89
|
-
}
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
### Origins
|
|
93
|
-
|
|
94
|
-
Origins provide OTP (One-Time Password) authentication flows for different channels.
|
|
95
|
-
|
|
96
|
-
#### `origins.whatsapp.assert(phone)`
|
|
97
|
-
|
|
98
|
-
Send an OTP code via WhatsApp to the specified phone number:
|
|
99
|
-
|
|
100
|
-
```typescript
|
|
101
|
-
const otp = await identity.origins.whatsapp.assert('+1234567890');
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
**Parameters**:
|
|
105
|
-
- `phone` (string): Phone number in international format (e.g., '+1234567890')
|
|
106
|
-
|
|
107
|
-
**Response**:
|
|
108
|
-
|
|
109
|
-
```typescript
|
|
110
|
-
interface OTPAssertionWhatsApp {
|
|
111
|
-
type: 'OTP';
|
|
112
|
-
params: {
|
|
113
|
-
attempts_remaining: number; // Number of remaining OTP attempts
|
|
114
|
-
};
|
|
115
|
-
value: {
|
|
116
|
-
phone: string; // Phone number where OTP was sent
|
|
117
|
-
expires_at: number; // Unix timestamp when OTP expires
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
#### `origins.email.assert(email)`
|
|
123
|
-
|
|
124
|
-
Send an OTP code via Email to the specified email address:
|
|
125
|
-
|
|
126
|
-
```typescript
|
|
127
|
-
const otp = await identity.origins.email.assert('user@example.com');
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
**Parameters**:
|
|
131
|
-
- `email` (string): Email address
|
|
132
|
-
|
|
133
|
-
**Response**:
|
|
134
|
-
|
|
135
|
-
```typescript
|
|
136
|
-
interface OTPAssertionEmail {
|
|
137
|
-
type: 'OTP';
|
|
138
|
-
params: {
|
|
139
|
-
attempts_remaining: number; // Number of remaining OTP attempts
|
|
140
|
-
};
|
|
141
|
-
value: {
|
|
142
|
-
email: string; // Email address where OTP was sent
|
|
143
|
-
expires_at: number; // Unix timestamp when OTP expires
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
#### `origins.custom(origin)`
|
|
149
|
-
|
|
150
|
-
Create a custom origin client for custom authentication origins:
|
|
151
|
-
|
|
152
|
-
```typescript
|
|
153
|
-
const customOrigin = identity.origins.custom('my-custom-origin');
|
|
154
|
-
const otp = await customOrigin.assert('identifier');
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
**Parameters**:
|
|
158
|
-
- `origin` (string): Custom origin identifier
|
|
159
|
-
|
|
160
|
-
**Returns**: `OriginClient<OTPAssertion>` instance with `assert()` method
|
|
161
|
-
|
|
162
|
-
#### `origins.list()`
|
|
163
|
-
|
|
164
|
-
List all available origins with their current status:
|
|
165
|
-
|
|
166
|
-
```typescript
|
|
167
|
-
const origins = await identity.origins.list();
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
**Response**:
|
|
171
|
-
|
|
172
|
-
```typescript
|
|
173
|
-
interface Origin {
|
|
174
|
-
namespace: string; // Unique namespace identifier
|
|
175
|
-
provider: string; // Provider type (e.g., 'evm', 'auth0', 'whatsapp')
|
|
176
|
-
status: 'active' | 'inactive' | 'disabled'; // Current status
|
|
177
|
-
metadata: Record<string, unknown>; // Additional metadata
|
|
178
|
-
created_at: string; // Creation timestamp (ISO 8601)
|
|
179
|
-
updated_at: string; // Last update timestamp (ISO 8601)
|
|
180
|
-
}
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
**Returns**: `Promise<Origin[]>` - Array of all registered origins
|
|
184
|
-
|
|
185
|
-
#### `origins.register(origin, params)`
|
|
186
|
-
|
|
187
|
-
Register a new user or business identity to a specific origin. Supports both individual users (KYC) and businesses (KYB) with various authentication methods:
|
|
188
|
-
|
|
189
|
-
```typescript
|
|
190
|
-
// Register individual with blockchain signature
|
|
191
|
-
const individual = await identity.origins.register('ethereum-mainnet', {
|
|
192
|
-
assertionResult: {
|
|
193
|
-
alias: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
|
|
194
|
-
challengeType: 'SIGNING_CHALLENGE',
|
|
195
|
-
value: {
|
|
196
|
-
signature: '0x1234...',
|
|
197
|
-
alias: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6'
|
|
198
|
-
}
|
|
199
|
-
},
|
|
200
|
-
type: 'individual',
|
|
201
|
-
profile: {
|
|
202
|
-
firstName: 'John',
|
|
203
|
-
lastName: 'Doe',
|
|
204
|
-
email: 'john@example.com'
|
|
205
|
-
}
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
// Register business with API key
|
|
209
|
-
const business = await identity.origins.register('bloque-api', {
|
|
210
|
-
assertionResult: {
|
|
211
|
-
alias: 'business-123',
|
|
212
|
-
challengeType: 'API_KEY',
|
|
213
|
-
value: {
|
|
214
|
-
apiKey: 'sk_live_abc123',
|
|
215
|
-
alias: 'business-123'
|
|
216
|
-
}
|
|
217
|
-
},
|
|
218
|
-
type: 'business',
|
|
219
|
-
profile: {
|
|
220
|
-
legalName: 'Acme Corporation',
|
|
221
|
-
name: 'Acme Corp',
|
|
222
|
-
taxId: '12-3456789',
|
|
223
|
-
type: 'LLC',
|
|
224
|
-
incorporationDate: '2020-01-15',
|
|
225
|
-
addressLine1: '123 Business St',
|
|
226
|
-
city: 'New York',
|
|
227
|
-
state: 'NY',
|
|
228
|
-
postalCode: '10001',
|
|
229
|
-
country: 'United States'
|
|
230
|
-
}
|
|
231
|
-
});
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
**Parameters**:
|
|
235
|
-
- `origin` (string): Origin namespace to register to (e.g., 'ethereum-mainnet', 'bloque-api')
|
|
236
|
-
- `params` (RegisterParams): Registration parameters
|
|
237
|
-
|
|
238
|
-
**Assertion Challenge Types**:
|
|
239
|
-
- `SIGNING_CHALLENGE`: Blockchain signature verification
|
|
240
|
-
- `API_KEY`: Traditional API key authentication
|
|
241
|
-
- `OAUTH_REDIRECT`: OAuth-based flows
|
|
242
|
-
- `WEBAUTHN`: WebAuthn/passkey authentication
|
|
243
|
-
- `OTP`: One-time password verification
|
|
244
|
-
- `PASSWORD`: Password-based authentication
|
|
245
|
-
|
|
246
|
-
**Individual Profile (KYC)**:
|
|
247
|
-
```typescript
|
|
248
|
-
interface UserProfile {
|
|
249
|
-
firstName?: string;
|
|
250
|
-
lastName?: string;
|
|
251
|
-
birthdate?: string; // ISO 8601 (YYYY-MM-DD)
|
|
252
|
-
email?: string;
|
|
253
|
-
phone?: string;
|
|
254
|
-
gender?: string;
|
|
255
|
-
addressLine1?: string;
|
|
256
|
-
addressLine2?: string;
|
|
257
|
-
city?: string;
|
|
258
|
-
state?: string;
|
|
259
|
-
postalCode?: string;
|
|
260
|
-
neighborhood?: string;
|
|
261
|
-
countryOfBirthCode?: string;
|
|
262
|
-
countryOfResidenceCode?: string;
|
|
263
|
-
personalIdType?: string;
|
|
264
|
-
personalIdNumber?: string;
|
|
265
|
-
}
|
|
266
|
-
```
|
|
267
|
-
|
|
268
|
-
**Business Profile (KYB)**:
|
|
269
|
-
```typescript
|
|
270
|
-
interface BusinessProfile {
|
|
271
|
-
// Required fields
|
|
272
|
-
addressLine1: string;
|
|
273
|
-
city: string;
|
|
274
|
-
country: string;
|
|
275
|
-
incorporationDate: string; // YYYY-MM-DD
|
|
276
|
-
legalName: string;
|
|
277
|
-
name: string;
|
|
278
|
-
postalCode: string;
|
|
279
|
-
state: string;
|
|
280
|
-
taxId: string;
|
|
281
|
-
type: string; // LLC, Corporation, etc.
|
|
282
|
-
|
|
283
|
-
// Optional fields
|
|
284
|
-
addressLine2?: string;
|
|
285
|
-
countryCode?: string;
|
|
286
|
-
email?: string;
|
|
287
|
-
logo?: string;
|
|
288
|
-
phone?: string;
|
|
289
|
-
|
|
290
|
-
// Owner information
|
|
291
|
-
ownerName?: string;
|
|
292
|
-
ownerIdType?: string;
|
|
293
|
-
ownerIdNumber?: string;
|
|
294
|
-
ownerAddressLine1?: string;
|
|
295
|
-
ownerAddressLine2?: string;
|
|
296
|
-
ownerCity?: string;
|
|
297
|
-
ownerState?: string;
|
|
298
|
-
ownerPostalCode?: string;
|
|
299
|
-
ownerCountryCode?: string;
|
|
300
|
-
}
|
|
301
|
-
```
|
|
302
|
-
|
|
303
|
-
**Response**:
|
|
304
|
-
```typescript
|
|
305
|
-
interface RegisterResult {
|
|
306
|
-
accessToken: string; // JWT token for authenticated sessions
|
|
307
|
-
}
|
|
308
|
-
```
|
|
309
|
-
|
|
310
|
-
**Returns**: `Promise<RegisterResult>` - Registration result with access token
|
|
311
|
-
|
|
312
|
-
## Examples
|
|
313
|
-
|
|
314
|
-
### Get Email Alias
|
|
315
|
-
|
|
316
|
-
```typescript
|
|
317
|
-
try {
|
|
318
|
-
const alias = await identity.aliases.get('user@example.com');
|
|
319
|
-
|
|
320
|
-
if (alias.status === 'active') {
|
|
321
|
-
console.log('Active user:', alias.urn);
|
|
322
|
-
}
|
|
323
|
-
} catch (error) {
|
|
324
|
-
console.error('Failed to get alias:', error);
|
|
325
|
-
}
|
|
326
|
-
```
|
|
327
|
-
|
|
328
|
-
### Get Phone Alias
|
|
329
|
-
|
|
330
|
-
```typescript
|
|
331
|
-
try {
|
|
332
|
-
const phoneAlias = await identity.aliases.get('+1234567890');
|
|
333
|
-
|
|
334
|
-
console.log('Phone details:', phoneAlias.details.phone);
|
|
335
|
-
console.log('User URN:', phoneAlias.urn);
|
|
336
|
-
} catch (error) {
|
|
337
|
-
console.error('Failed to get phone alias:', error);
|
|
338
|
-
}
|
|
339
|
-
```
|
|
340
|
-
|
|
341
|
-
### Send OTP via WhatsApp
|
|
342
|
-
|
|
343
|
-
```typescript
|
|
344
|
-
import { SDK } from '@bloque/sdk';
|
|
345
|
-
|
|
346
|
-
const bloque = new SDK({
|
|
347
|
-
auth: {
|
|
348
|
-
type: 'apiKey',
|
|
349
|
-
apiKey: process.env.BLOQUE_API_KEY!,
|
|
350
|
-
},
|
|
351
|
-
mode: 'production',
|
|
352
|
-
});
|
|
353
|
-
|
|
354
|
-
try {
|
|
355
|
-
const otp = await bloque.identity.origins.whatsapp.assert('+1234567890');
|
|
356
|
-
|
|
357
|
-
console.log('OTP sent to:', otp.value.phone);
|
|
358
|
-
console.log('Expires at:', new Date(otp.value.expires_at * 1000));
|
|
359
|
-
console.log('Attempts remaining:', otp.params.attempts_remaining);
|
|
360
|
-
|
|
361
|
-
// Now user can verify the OTP code they received
|
|
362
|
-
} catch (error) {
|
|
363
|
-
console.error('Failed to send OTP:', error);
|
|
364
|
-
}
|
|
365
|
-
```
|
|
366
|
-
|
|
367
|
-
### Send OTP via Email
|
|
368
|
-
|
|
369
|
-
```typescript
|
|
370
|
-
import { SDK } from '@bloque/sdk';
|
|
371
|
-
|
|
372
|
-
const bloque = new SDK({
|
|
373
|
-
auth: {
|
|
374
|
-
type: 'apiKey',
|
|
375
|
-
apiKey: process.env.BLOQUE_API_KEY!,
|
|
376
|
-
},
|
|
377
|
-
mode: 'production',
|
|
378
|
-
});
|
|
379
|
-
|
|
380
|
-
try {
|
|
381
|
-
const otp = await bloque.identity.origins.email.assert('user@example.com');
|
|
382
|
-
|
|
383
|
-
console.log('OTP sent to:', otp.value.email);
|
|
384
|
-
console.log('Expires at:', new Date(otp.value.expires_at * 1000));
|
|
385
|
-
console.log('Attempts remaining:', otp.params.attempts_remaining);
|
|
386
|
-
|
|
387
|
-
// Now user can verify the OTP code they received
|
|
388
|
-
} catch (error) {
|
|
389
|
-
console.error('Failed to send OTP:', error);
|
|
390
|
-
}
|
|
391
|
-
```
|
|
392
|
-
|
|
393
|
-
### Complete OTP Flow Example
|
|
394
|
-
|
|
395
|
-
```typescript
|
|
396
|
-
import { SDK } from '@bloque/sdk';
|
|
397
|
-
|
|
398
|
-
const bloque = new SDK({
|
|
399
|
-
auth: {
|
|
400
|
-
type: 'apiKey',
|
|
401
|
-
apiKey: process.env.BLOQUE_API_KEY!,
|
|
402
|
-
},
|
|
403
|
-
mode: 'production',
|
|
404
|
-
});
|
|
405
|
-
|
|
406
|
-
async function authenticateUser(email: string) {
|
|
407
|
-
try {
|
|
408
|
-
// Step 1: Check if user exists
|
|
409
|
-
const alias = await bloque.identity.aliases.get(email);
|
|
410
|
-
|
|
411
|
-
if (alias.status !== 'active') {
|
|
412
|
-
throw new Error('User is not active');
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
// Step 2: Send OTP
|
|
416
|
-
const otp = await bloque.identity.origins.email.assert(email);
|
|
417
|
-
|
|
418
|
-
console.log('OTP sent successfully to:', otp.value.email);
|
|
419
|
-
console.log('User has', otp.params.attempts_remaining, 'attempts remaining');
|
|
420
|
-
console.log('OTP expires at:', new Date(otp.value.expires_at * 1000));
|
|
421
|
-
|
|
422
|
-
// Step 3: User would now verify the OTP code
|
|
423
|
-
// (verification would be done through your app's verification endpoint)
|
|
424
|
-
|
|
425
|
-
return {
|
|
426
|
-
userUrn: alias.urn,
|
|
427
|
-
otpSent: true,
|
|
428
|
-
expiresAt: otp.value.expires_at,
|
|
429
|
-
};
|
|
430
|
-
} catch (error) {
|
|
431
|
-
console.error('Authentication failed:', error);
|
|
432
|
-
throw error;
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
// Usage
|
|
437
|
-
await authenticateUser('user@example.com');
|
|
438
|
-
```
|
|
439
|
-
|
|
440
|
-
### List Available Origins
|
|
441
|
-
|
|
442
|
-
```typescript
|
|
443
|
-
import { SDK } from '@bloque/sdk';
|
|
444
|
-
|
|
445
|
-
const bloque = new SDK({
|
|
446
|
-
auth: {
|
|
447
|
-
type: 'apiKey',
|
|
448
|
-
apiKey: process.env.BLOQUE_API_KEY!,
|
|
449
|
-
},
|
|
450
|
-
mode: 'production',
|
|
451
|
-
});
|
|
452
|
-
|
|
453
|
-
try {
|
|
454
|
-
const origins = await bloque.identity.origins.list();
|
|
455
|
-
|
|
456
|
-
// Filter active origins
|
|
457
|
-
const activeOrigins = origins.filter(o => o.status === 'active');
|
|
458
|
-
console.log(`Found ${activeOrigins.length} active origins`);
|
|
459
|
-
|
|
460
|
-
// Find specific origins
|
|
461
|
-
const whatsappOrigins = origins.filter(o => o.provider === 'whatsapp');
|
|
462
|
-
const evmOrigins = origins.filter(o => o.provider === 'evm');
|
|
463
|
-
|
|
464
|
-
console.log('WhatsApp origins:', whatsappOrigins.map(o => o.namespace));
|
|
465
|
-
console.log('EVM origins:', evmOrigins.map(o => o.namespace));
|
|
466
|
-
|
|
467
|
-
// Get metadata from specific origin
|
|
468
|
-
const auth0Origin = origins.find(o => o.namespace === 'bloque-auth0');
|
|
469
|
-
if (auth0Origin) {
|
|
470
|
-
console.log('Auth0 metadata:', auth0Origin.metadata);
|
|
471
|
-
}
|
|
472
|
-
} catch (error) {
|
|
473
|
-
console.error('Failed to list origins:', error);
|
|
474
|
-
}
|
|
475
|
-
```
|
|
476
|
-
|
|
477
|
-
### Using Custom Origin
|
|
478
|
-
|
|
479
|
-
```typescript
|
|
480
|
-
import { SDK } from '@bloque/sdk';
|
|
481
|
-
|
|
482
|
-
const bloque = new SDK({
|
|
483
|
-
auth: {
|
|
484
|
-
type: 'apiKey',
|
|
485
|
-
apiKey: process.env.BLOQUE_API_KEY!,
|
|
486
|
-
},
|
|
487
|
-
mode: 'production',
|
|
488
|
-
});
|
|
489
|
-
|
|
490
|
-
// Create a custom origin client
|
|
491
|
-
const customOrigin = bloque.identity.origins.custom('my-custom-sms-provider');
|
|
492
|
-
|
|
493
|
-
try {
|
|
494
|
-
const otp = await customOrigin.assert('+1234567890');
|
|
495
|
-
|
|
496
|
-
console.log('OTP sent via custom origin');
|
|
497
|
-
console.log('Attempts remaining:', otp.params.attempts_remaining);
|
|
498
|
-
} catch (error) {
|
|
499
|
-
console.error('Failed to send OTP via custom origin:', error);
|
|
500
|
-
}
|
|
501
|
-
```
|
|
502
|
-
|
|
503
|
-
### Error Handling with Rate Limiting
|
|
504
|
-
|
|
505
|
-
```typescript
|
|
506
|
-
import { SDK } from '@bloque/sdk';
|
|
507
|
-
|
|
508
|
-
const bloque = new SDK({
|
|
509
|
-
auth: {
|
|
510
|
-
type: 'apiKey',
|
|
511
|
-
apiKey: process.env.BLOQUE_API_KEY!,
|
|
512
|
-
},
|
|
513
|
-
mode: 'production',
|
|
514
|
-
});
|
|
515
|
-
|
|
516
|
-
async function sendOTPWithRetry(phone: string, maxRetries = 3) {
|
|
517
|
-
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
518
|
-
try {
|
|
519
|
-
const otp = await bloque.identity.origins.whatsapp.assert(phone);
|
|
520
|
-
|
|
521
|
-
if (otp.params.attempts_remaining === 0) {
|
|
522
|
-
console.warn('No OTP attempts remaining!');
|
|
523
|
-
return null;
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
console.log('OTP sent successfully');
|
|
527
|
-
console.log('Attempts remaining:', otp.params.attempts_remaining);
|
|
528
|
-
|
|
529
|
-
return otp;
|
|
530
|
-
} catch (error) {
|
|
531
|
-
console.error(`Attempt ${attempt} failed:`, error);
|
|
532
|
-
|
|
533
|
-
if (attempt === maxRetries) {
|
|
534
|
-
throw new Error('Max retries reached');
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
// Wait before retrying
|
|
538
|
-
await new Promise(resolve => setTimeout(resolve, 1000 * attempt));
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
await sendOTPWithRetry('+1234567890');
|
|
544
|
-
```
|
|
545
|
-
|
|
546
|
-
### Register Individual User (KYC)
|
|
547
|
-
|
|
548
|
-
```typescript
|
|
549
|
-
import { SDK } from '@bloque/sdk';
|
|
550
|
-
|
|
551
|
-
const bloque = new SDK({
|
|
552
|
-
auth: {
|
|
553
|
-
type: 'apiKey',
|
|
554
|
-
apiKey: process.env.BLOQUE_API_KEY!,
|
|
555
|
-
},
|
|
556
|
-
mode: 'production',
|
|
557
|
-
});
|
|
558
|
-
|
|
559
|
-
try {
|
|
560
|
-
// Register individual with blockchain signature
|
|
561
|
-
const result = await bloque.identity.origins.register('ethereum-mainnet', {
|
|
562
|
-
assertionResult: {
|
|
563
|
-
alias: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
|
|
564
|
-
challengeType: 'SIGNING_CHALLENGE',
|
|
565
|
-
value: {
|
|
566
|
-
signature: '0x1234567890abcdef...',
|
|
567
|
-
alias: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6'
|
|
568
|
-
},
|
|
569
|
-
originalChallengeParams: {
|
|
570
|
-
challenge: 'bloque-challenge-1234567890',
|
|
571
|
-
timestamp: 1640995200
|
|
572
|
-
}
|
|
573
|
-
},
|
|
574
|
-
type: 'individual',
|
|
575
|
-
profile: {
|
|
576
|
-
firstName: 'John',
|
|
577
|
-
lastName: 'Doe',
|
|
578
|
-
email: 'john.doe@example.com',
|
|
579
|
-
phone: '+1234567890',
|
|
580
|
-
birthdate: '1990-01-15',
|
|
581
|
-
city: 'New York',
|
|
582
|
-
state: 'NY',
|
|
583
|
-
postalCode: '10001',
|
|
584
|
-
addressLine1: '123 Main St',
|
|
585
|
-
countryOfBirthCode: 'USA',
|
|
586
|
-
countryOfResidenceCode: 'USA',
|
|
587
|
-
personalIdType: 'SSN',
|
|
588
|
-
personalIdNumber: '123-45-6789'
|
|
589
|
-
}
|
|
590
|
-
});
|
|
591
|
-
|
|
592
|
-
console.log('User registered successfully!');
|
|
593
|
-
console.log('Access token:', result.accessToken);
|
|
594
|
-
|
|
595
|
-
// Use the access token for authenticated API calls
|
|
596
|
-
// Store it securely for the user's session
|
|
597
|
-
} catch (error) {
|
|
598
|
-
console.error('Registration failed:', error);
|
|
599
|
-
}
|
|
600
|
-
```
|
|
601
|
-
|
|
602
|
-
### Register Business (KYB)
|
|
603
|
-
|
|
604
|
-
```typescript
|
|
605
|
-
import { SDK } from '@bloque/sdk';
|
|
606
|
-
|
|
607
|
-
const bloque = new SDK({
|
|
608
|
-
auth: {
|
|
609
|
-
type: 'apiKey',
|
|
610
|
-
apiKey: process.env.BLOQUE_API_KEY!,
|
|
611
|
-
},
|
|
612
|
-
mode: 'production',
|
|
613
|
-
});
|
|
614
|
-
|
|
615
|
-
try {
|
|
616
|
-
// Register business with API key authentication
|
|
617
|
-
const result = await bloque.identity.origins.register('bloque-api', {
|
|
618
|
-
assertionResult: {
|
|
619
|
-
alias: 'business-123',
|
|
620
|
-
challengeType: 'API_KEY',
|
|
621
|
-
value: {
|
|
622
|
-
apiKey: 'sk_live_abc123def456',
|
|
623
|
-
alias: 'business-123'
|
|
624
|
-
}
|
|
625
|
-
},
|
|
626
|
-
type: 'business',
|
|
627
|
-
profile: {
|
|
628
|
-
// Required business information
|
|
629
|
-
legalName: 'Acme Corporation',
|
|
630
|
-
name: 'Acme Corp',
|
|
631
|
-
taxId: '12-3456789',
|
|
632
|
-
type: 'LLC',
|
|
633
|
-
incorporationDate: '2020-01-15',
|
|
634
|
-
addressLine1: '123 Business St',
|
|
635
|
-
city: 'New York',
|
|
636
|
-
state: 'NY',
|
|
637
|
-
postalCode: '10001',
|
|
638
|
-
country: 'United States',
|
|
639
|
-
|
|
640
|
-
// Optional business information
|
|
641
|
-
addressLine2: 'Suite 100',
|
|
642
|
-
countryCode: 'US',
|
|
643
|
-
email: 'contact@acme.com',
|
|
644
|
-
phone: '+1-555-0123',
|
|
645
|
-
logo: 'https://acme.com/logo.png',
|
|
646
|
-
|
|
647
|
-
// Beneficial owner information
|
|
648
|
-
ownerName: 'Jane Smith',
|
|
649
|
-
ownerIdType: 'SSN',
|
|
650
|
-
ownerIdNumber: '123-45-6789',
|
|
651
|
-
ownerAddressLine1: '456 Owner Ave',
|
|
652
|
-
ownerCity: 'New York',
|
|
653
|
-
ownerState: 'NY',
|
|
654
|
-
ownerPostalCode: '10002',
|
|
655
|
-
ownerCountryCode: 'US'
|
|
656
|
-
}
|
|
657
|
-
});
|
|
658
|
-
|
|
659
|
-
console.log('Business registered successfully!');
|
|
660
|
-
console.log('Access token:', result.accessToken);
|
|
661
|
-
|
|
662
|
-
// Use the access token for authenticated API calls
|
|
663
|
-
} catch (error) {
|
|
664
|
-
console.error('Business registration failed:', error);
|
|
665
|
-
}
|
|
666
|
-
```
|
|
667
|
-
|
|
668
|
-
### Multi-Origin Registration Flow
|
|
669
|
-
|
|
670
|
-
```typescript
|
|
671
|
-
import { SDK } from '@bloque/sdk';
|
|
672
|
-
|
|
673
|
-
const bloque = new SDK({
|
|
674
|
-
auth: {
|
|
675
|
-
type: 'apiKey',
|
|
676
|
-
apiKey: process.env.BLOQUE_API_KEY!,
|
|
677
|
-
},
|
|
678
|
-
mode: 'production',
|
|
679
|
-
});
|
|
680
|
-
|
|
681
|
-
async function registerUserAcrossOrigins(userProfile: any) {
|
|
682
|
-
try {
|
|
683
|
-
// Step 1: List available origins
|
|
684
|
-
const origins = await bloque.identity.origins.list();
|
|
685
|
-
const activeOrigins = origins.filter(o => o.status === 'active');
|
|
686
|
-
|
|
687
|
-
console.log(`Found ${activeOrigins.length} active origins`);
|
|
688
|
-
|
|
689
|
-
// Step 2: Register on blockchain origin
|
|
690
|
-
const ethereumOrigin = activeOrigins.find(o => o.namespace === 'ethereum-mainnet');
|
|
691
|
-
|
|
692
|
-
if (ethereumOrigin) {
|
|
693
|
-
const ethereumResult = await bloque.identity.origins.register('ethereum-mainnet', {
|
|
694
|
-
assertionResult: {
|
|
695
|
-
alias: userProfile.walletAddress,
|
|
696
|
-
challengeType: 'SIGNING_CHALLENGE',
|
|
697
|
-
value: {
|
|
698
|
-
signature: userProfile.signature,
|
|
699
|
-
alias: userProfile.walletAddress
|
|
700
|
-
}
|
|
701
|
-
},
|
|
702
|
-
type: 'individual',
|
|
703
|
-
profile: userProfile.personalInfo
|
|
704
|
-
});
|
|
705
|
-
|
|
706
|
-
console.log('Registered on Ethereum:', ethereumResult.accessToken);
|
|
707
|
-
}
|
|
708
|
-
|
|
709
|
-
// Step 3: Register on custom origin
|
|
710
|
-
const customResult = await bloque.identity.origins.register('bloque-custom', {
|
|
711
|
-
assertionResult: {
|
|
712
|
-
alias: userProfile.customId,
|
|
713
|
-
challengeType: 'API_KEY',
|
|
714
|
-
value: {
|
|
715
|
-
apiKey: userProfile.apiKey,
|
|
716
|
-
alias: userProfile.customId
|
|
717
|
-
}
|
|
718
|
-
},
|
|
719
|
-
type: 'individual',
|
|
720
|
-
profile: userProfile.personalInfo
|
|
721
|
-
});
|
|
722
|
-
|
|
723
|
-
console.log('Registered on custom origin:', customResult.accessToken);
|
|
724
|
-
|
|
725
|
-
return {
|
|
726
|
-
ethereum: ethereumOrigin ? true : false,
|
|
727
|
-
custom: true,
|
|
728
|
-
tokens: {
|
|
729
|
-
ethereum: ethereumOrigin ? 'stored' : null,
|
|
730
|
-
custom: 'stored'
|
|
731
|
-
}
|
|
732
|
-
};
|
|
733
|
-
} catch (error) {
|
|
734
|
-
console.error('Multi-origin registration failed:', error);
|
|
735
|
-
throw error;
|
|
736
|
-
}
|
|
737
|
-
}
|
|
738
|
-
|
|
739
|
-
// Usage
|
|
740
|
-
await registerUserAcrossOrigins({
|
|
741
|
-
walletAddress: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
|
|
742
|
-
signature: '0xabcdef...',
|
|
743
|
-
customId: 'user-123',
|
|
744
|
-
apiKey: 'sk_live_abc123',
|
|
745
|
-
personalInfo: {
|
|
746
|
-
firstName: 'Alice',
|
|
747
|
-
lastName: 'Johnson',
|
|
748
|
-
email: 'alice@example.com'
|
|
749
|
-
}
|
|
750
|
-
});
|
|
751
|
-
```
|
|
752
|
-
|
|
753
|
-
## TypeScript Support
|
|
754
|
-
|
|
755
|
-
This package is written in TypeScript and includes complete type definitions:
|
|
756
|
-
|
|
757
|
-
```typescript
|
|
758
|
-
import type {
|
|
759
|
-
Alias,
|
|
760
|
-
Origin,
|
|
761
|
-
OTPAssertionEmail,
|
|
762
|
-
OTPAssertionWhatsApp,
|
|
763
|
-
OTPAssertion,
|
|
764
|
-
IdentityClient,
|
|
765
|
-
AliasesClient,
|
|
766
|
-
OriginsClient,
|
|
767
|
-
OriginClient,
|
|
768
|
-
// Registration types
|
|
769
|
-
RegisterParams,
|
|
770
|
-
IndividualRegisterParams,
|
|
771
|
-
BusinessRegisterParams,
|
|
772
|
-
RegisterResult,
|
|
773
|
-
UserProfile,
|
|
774
|
-
BusinessProfile,
|
|
775
|
-
} from '@bloque/sdk-identity';
|
|
776
|
-
|
|
777
|
-
// Type-safe alias retrieval
|
|
778
|
-
const alias: Alias = await identity.aliases.get('user@example.com');
|
|
779
|
-
|
|
780
|
-
// Type-safe origins list
|
|
781
|
-
const origins: Origin[] = await identity.origins.list();
|
|
782
|
-
|
|
783
|
-
// Type-safe OTP with WhatsApp
|
|
784
|
-
const whatsappOTP: OTPAssertionWhatsApp =
|
|
785
|
-
await identity.origins.whatsapp.assert('+1234567890');
|
|
786
|
-
|
|
787
|
-
// Type-safe OTP with Email
|
|
788
|
-
const emailOTP: OTPAssertionEmail =
|
|
789
|
-
await identity.origins.email.assert('user@example.com');
|
|
790
|
-
|
|
791
|
-
// Generic OTP type
|
|
792
|
-
const otp: OTPAssertion =
|
|
793
|
-
await identity.origins.email.assert('user@example.com');
|
|
794
|
-
|
|
795
|
-
// Custom origin client
|
|
796
|
-
const customOrigin: OriginClient<OTPAssertion> =
|
|
797
|
-
identity.origins.custom('my-origin');
|
|
798
|
-
|
|
799
|
-
// Type-safe individual registration
|
|
800
|
-
const individualParams: IndividualRegisterParams = {
|
|
801
|
-
assertionResult: {
|
|
802
|
-
alias: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
|
|
803
|
-
challengeType: 'SIGNING_CHALLENGE',
|
|
804
|
-
value: {
|
|
805
|
-
signature: '0x123...',
|
|
806
|
-
alias: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6'
|
|
807
|
-
}
|
|
808
|
-
},
|
|
809
|
-
type: 'individual',
|
|
810
|
-
profile: {
|
|
811
|
-
firstName: 'John',
|
|
812
|
-
lastName: 'Doe',
|
|
813
|
-
email: 'john@example.com'
|
|
814
|
-
}
|
|
815
|
-
};
|
|
816
|
-
|
|
817
|
-
const individualResult: RegisterResult =
|
|
818
|
-
await identity.origins.register('ethereum-mainnet', individualParams);
|
|
819
|
-
|
|
820
|
-
// Type-safe business registration
|
|
821
|
-
const businessParams: BusinessRegisterParams = {
|
|
822
|
-
assertionResult: {
|
|
823
|
-
alias: 'business-123',
|
|
824
|
-
challengeType: 'API_KEY',
|
|
825
|
-
value: {
|
|
826
|
-
apiKey: 'sk_live_abc123',
|
|
827
|
-
alias: 'business-123'
|
|
828
|
-
}
|
|
829
|
-
},
|
|
830
|
-
type: 'business',
|
|
831
|
-
profile: {
|
|
832
|
-
legalName: 'Acme Corp',
|
|
833
|
-
name: 'Acme',
|
|
834
|
-
taxId: '12-3456789',
|
|
835
|
-
type: 'LLC',
|
|
836
|
-
incorporationDate: '2020-01-15',
|
|
837
|
-
addressLine1: '123 Business St',
|
|
838
|
-
city: 'New York',
|
|
839
|
-
state: 'NY',
|
|
840
|
-
postalCode: '10001',
|
|
841
|
-
country: 'United States'
|
|
842
|
-
}
|
|
843
|
-
};
|
|
844
|
-
|
|
845
|
-
const businessResult: RegisterResult =
|
|
846
|
-
await identity.origins.register('bloque-api', businessParams);
|
|
847
|
-
```
|
|
848
|
-
|
|
849
|
-
## Use with Main SDK
|
|
850
|
-
|
|
851
|
-
When using through the main `@bloque/sdk` package:
|
|
852
|
-
|
|
853
|
-
```typescript
|
|
854
|
-
import { SDK } from '@bloque/sdk';
|
|
855
|
-
|
|
856
|
-
const bloque = new SDK({
|
|
857
|
-
auth: {
|
|
858
|
-
type: 'apiKey',
|
|
859
|
-
apiKey: process.env.BLOQUE_API_KEY!,
|
|
860
|
-
},
|
|
861
|
-
mode: 'production',
|
|
862
|
-
});
|
|
863
|
-
|
|
864
|
-
// All identity features are available under bloque.identity
|
|
865
|
-
const alias = await bloque.identity.aliases.get('user@example.com');
|
|
866
|
-
const otp = await bloque.identity.origins.whatsapp.assert('+1234567890');
|
|
867
|
-
```
|
|
868
|
-
|
|
869
|
-
## Key Features
|
|
870
|
-
|
|
871
|
-
### Identity Registration
|
|
872
|
-
|
|
873
|
-
- **Individual Registration (KYC)**: Register users with Know Your Customer compliance
|
|
874
|
-
- **Business Registration (KYB)**: Register businesses with Know Your Business compliance
|
|
875
|
-
- **Multi-Method Authentication**: Support for blockchain signatures, API keys, OAuth, WebAuthn, OTP, and passwords
|
|
876
|
-
- **Cross-Origin Support**: Register identities across multiple authentication origins
|
|
877
|
-
- **Secure Token Generation**: Receive JWT access tokens for authenticated sessions
|
|
878
|
-
|
|
879
|
-
### Origin Management
|
|
880
|
-
|
|
881
|
-
- **List Origins**: Retrieve all available authentication origins
|
|
882
|
-
- **Filter by Provider**: Find origins by provider type (evm, auth0, whatsapp, etc.)
|
|
883
|
-
- **Check Status**: Monitor origin availability and status
|
|
884
|
-
- **Custom Registration**: Register to custom authentication providers
|
|
885
|
-
|
|
886
|
-
### OTP Authentication Channels
|
|
887
|
-
|
|
888
|
-
- **WhatsApp**: Send OTP codes via WhatsApp messages
|
|
889
|
-
- **Email**: Send OTP codes via email
|
|
890
|
-
- **Custom Origins**: Integrate custom authentication providers
|
|
891
|
-
|
|
892
|
-
### Rate Limiting & Security
|
|
893
|
-
|
|
894
|
-
OTP assertions include built-in rate limiting:
|
|
895
|
-
- `attempts_remaining`: Track remaining OTP attempts
|
|
896
|
-
- `expires_at`: Unix timestamp for OTP expiration
|
|
897
|
-
- Automatic retry protection
|
|
898
|
-
|
|
899
|
-
### Alias Management
|
|
900
|
-
|
|
901
|
-
- Retrieve user information by email or phone
|
|
902
|
-
- Check user status (active, inactive, revoked)
|
|
903
|
-
- Support for primary and public aliases
|
|
904
|
-
- Rich metadata support
|
|
905
|
-
|
|
906
|
-
### Compliance Support
|
|
907
|
-
|
|
908
|
-
- **KYC (Know Your Customer)**: Complete individual profile fields including identity verification
|
|
909
|
-
- **KYB (Know Your Business)**: Business entity information with beneficial owner details
|
|
910
|
-
- **Data Privacy**: Secure handling of sensitive personal and business information
|
|
911
|
-
|
|
912
|
-
## Requirements
|
|
913
|
-
|
|
914
|
-
- Node.js 22.x or higher / Bun 1.x or higher
|
|
915
|
-
- TypeScript 5.x or higher (for TypeScript projects)
|
|
916
|
-
|
|
917
|
-
## Links
|
|
918
|
-
|
|
919
|
-
- [Homepage](https://www.bloque.app)
|
|
920
|
-
- [Main SDK Documentation](../sdk/README.md)
|
|
921
|
-
- [GitHub Repository](https://github.com/bloque-app/sdk)
|
|
922
|
-
- [Issue Tracker](https://github.com/bloque-app/sdk/issues)
|
|
923
|
-
|
|
924
|
-
## Development
|
|
925
|
-
|
|
926
|
-
```bash
|
|
927
|
-
# Build the package
|
|
928
|
-
bun run build
|
|
929
|
-
|
|
930
|
-
# Watch mode
|
|
931
|
-
bun run dev
|
|
932
|
-
|
|
933
|
-
# Type checking
|
|
934
|
-
bun run typecheck
|
|
935
|
-
|
|
936
|
-
# Code quality checks
|
|
937
|
-
bun run check
|
|
938
|
-
```
|
|
939
|
-
|
|
940
|
-
## License
|
|
941
|
-
|
|
942
|
-
[MIT](../../LICENSE)
|
|
943
|
-
|
|
944
|
-
Copyright (c) 2025-present Bloque Copilot Inc.
|
|
5
|
+
For documentation, please refer to the [main SDK documentation](../sdk/README.md).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bloque/sdk-identity",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.23",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"bloque",
|
|
@@ -34,6 +34,6 @@
|
|
|
34
34
|
"node": ">=22"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@bloque/sdk-core": "0.0.
|
|
37
|
+
"@bloque/sdk-core": "0.0.23"
|
|
38
38
|
}
|
|
39
39
|
}
|