@pelican-identity/auth-core 1.2.7 → 1.2.9

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 CHANGED
@@ -1,570 +1,174 @@
1
- # Pelican Auth SDK
1
+ This documentation provides a comprehensive guide for using the Pelican Identity Vanilla SDK. It covers three integration paths: using the pre-built UI via CDN, using the UI wrapper via NPM, and building a custom UI using the Core Engine.
2
2
 
3
- A modern, event-driven JavaScript/TypeScript SDK for integrating Pelican Vault authentication into your web applications.
3
+ ---
4
4
 
5
- ## Features
5
+ # Pelican Identity Vanilla SDK
6
6
 
7
- - 🎯 **Event-Driven Architecture** - Subscribe to authentication lifecycle events
8
- - 🔄 **Continuous Mode** - Automatic session restart for repeated authentication
9
- - 📱 **Multi-Platform** - Supports both QR code (desktop) and deep linking (mobile)
10
- - 🔐 **Secure** - End-to-end encrypted authentication using TweetNaCl
11
- - 🔌 **WebSocket Transport** - Real-time communication with Pelican Vault
12
- - 🎨 **Framework Agnostic** - Works with React, Vue, Svelte, or vanilla JS
13
- - 📦 **Type-Safe** - Full TypeScript support with comprehensive type definitions
7
+ The Vanilla SDK provides a framework-agnostic way to integrate Pelican authentication. It includes a high-level UI wrapper that mirrors the React experience and a low-level Core Engine for custom implementations.
14
8
 
15
9
  ## Installation
16
10
 
17
- ```bash
18
- npm @pelican-identity/sdk
19
- # or
20
- yarn add @pelican-identity/sdk
21
- # or
22
- pnpm add @pelican-identity/sdk
23
- ```
24
-
25
- ## Quick Start
26
-
27
- ### Basic Usage
28
-
29
- ```typescript
30
- import { PelicanAuth } from "@pelican-identity/sdk";
31
-
32
- // Initialize the SDK
33
- const auth = new PelicanAuth({
34
- publicKey: "your-public-key",
35
- projectId: "your-project-id",
36
- authType: "login", // 'login' | 'signup' | 'id-verification'
37
- });
38
-
39
- // Listen for authentication success
40
- auth.on("success", (identity) => {
41
- console.log("User authenticated:", identity);
42
- // Handle successful authentication
43
- });
44
-
45
- // Listen for errors
46
- auth.on("error", (error) => {
47
- console.error("Authentication failed:", error);
48
- });
49
-
50
- // Listen for QR code (desktop) or deep link (mobile)
51
- auth.on("qr", (qrDataUrl) => {
52
- // Display QR code image
53
- document.getElementById("qr").src = qrDataUrl;
54
- });
55
-
56
- auth.on("deeplink", (url) => {
57
- // Redirect to Pelican Vault app
58
- window.location.href = url;
59
- });
60
-
61
- // Start authentication
62
- auth.start();
63
- ```
64
-
65
- ## API Reference
66
-
67
- ### Constructor
68
-
69
- ```typescript
70
- new PelicanAuth(config: PelicanAuthConfig)
71
- ```
72
-
73
- #### Configuration Options
11
+ ### 1. Via CDN (Easiest)
74
12
 
75
- | Option | Type | Required | Default | Description |
76
- | ---------------- | ------------------------------------------ | -------- | ------- | ------------------------------------ |
77
- | `publicKey` | `string` | ✅ Yes | - | Your Pelican Vault public key |
78
- | `projectId` | `string` | ✅ Yes | - | Your project identifier |
79
- | `authType` | `'login' \| 'signup' \| 'id-verification'` | ✅ Yes | - | Type of authentication flow |
80
- | `continuousMode` | `boolean` | ❌ No | `false` | Auto-restart after successful auth |
81
- | `forceQRCode` | `boolean` | ❌ No | `false` | Force QR code even on mobile devices |
13
+ Ideal for projects without a build step. Includes the UI and logic in a single file.
82
14
 
83
- ### Methods
15
+ ```html
16
+ <link
17
+ rel="stylesheet"
18
+ href="https://cdn.jsdelivr.net/npm/@pelican-identity/vanilla@1.0.2/dist/pelican.css"
19
+ />
84
20
 
85
- #### `start(): Promise<void>`
21
+ <script src="https://cdn.jsdelivr.net/npm/@pelican-identity/vanilla@1.0.2/dist/index.min.js"></script>
86
22
 
87
- Initiates the authentication flow.
88
-
89
- ```typescript
90
- await auth.start();
91
- ```
92
-
93
- #### `stop(): void`
94
-
95
- Stops the authentication flow and cleans up resources.
96
-
97
- ```typescript
98
- auth.stop();
99
- ```
23
+ <div id="pelican-auth-root"></div>
100
24
 
101
- #### `on<K>(event: K, callback: Listener<K>): () => void`
102
-
103
- Subscribe to authentication events. Returns an unsubscribe function.
104
-
105
- ```typescript
106
- const unsubscribe = auth.on("success", (identity) => {
107
- console.log(identity);
108
- });
109
-
110
- // Later: unsubscribe
111
- unsubscribe();
112
- ```
113
-
114
- #### `destroy(): void`
115
-
116
- Completely destroys the SDK instance, removing all listeners and cleanup.
117
-
118
- ```typescript
119
- auth.destroy();
25
+ <script>
26
+ const auth = Pelican.createPelicanAuth("pelican-auth-root", {
27
+ publicKey: "your-business-public-key",
28
+ projectId: "your-project-id",
29
+ authType: "login",
30
+ onSuccess: (data) => console.log("Success:", data),
31
+ onError: (err) => console.error("Error:", err),
32
+ });
33
+ </script>
120
34
  ```
121
35
 
122
- ### Events
36
+ ### 2. Via NPM/PNPM
123
37
 
124
- The SDK emits the following events:
38
+ Ideal for modern web apps (Vue, Svelte, or Vanilla TS) using a bundler like Vite or Webpack.
125
39
 
126
- #### `state`
127
-
128
- Emitted when the authentication state changes.
40
+ ```bash
41
+ npm install @pelican-identity/vanilla
129
42
 
130
- ```typescript
131
- auth.on("state", (state) => {
132
- console.log("Current state:", state);
133
- });
134
43
  ```
135
44
 
136
- **States:**
137
-
138
- - `idle` - Initial state
139
- - `initializing` - Fetching relay server
140
- - `awaiting-pair` - Waiting for mobile device to scan
141
- - `paired` - Device connected
142
- - `authenticated` - User authenticated
143
- - `confirmed` - Authentication confirmed
144
- - `terminated` - Session ended
145
- - `error` - Error occurred
146
-
147
- #### `success`
148
-
149
- Emitted when authentication succeeds.
150
-
151
45
  ```typescript
152
- auth.on("success", (identity: IdentityResult) => {
153
- console.log("User ID:", identity.user_id);
154
- console.log("Email:", identity.user_data.email.value);
155
- console.log("Phone:", identity.user_data.phone.number);
156
- console.log("First Name:", identity.user_data.first_name);
46
+ import { createPelicanAuth } from "@pelican-identity/vanilla";
47
+ import "@pelican-identity/vanilla/dist/pelican.css";
157
48
 
158
- console.log("ID Verification:", identity.id_verification);
49
+ const cleanup = createPelicanAuth("container-id", {
50
+ publicKey: "...",
51
+ projectId: "...",
52
+ authType: "login",
53
+ onSuccess: (identity) => {
54
+ console.log(identity.user_id);
55
+ },
159
56
  });
160
- ```
161
-
162
- **IdentityResult:**
163
-
164
- ```typescript
165
- interface IdentityResult {
166
- user_id: string;
167
- user_data: IUserData;
168
- id_verification: IKycData;
169
- id_downloadurls?: { front_of_card?: string; back_of_card?: string };
170
- }
171
- ```
172
-
173
- #### `error`
174
-
175
- Emitted when an error occurs.
176
57
 
177
- ```typescript
178
- auth.on("error", (error: Error) => {
179
- console.error("Error:", error.message);
180
- });
58
+ // To stop and cleanup the instance
59
+ // cleanup();
181
60
  ```
182
61
 
183
- #### `qr`
62
+ ---
184
63
 
185
- Emitted on desktop with QR code data URL.
64
+ ## UI Wrapper API Reference (`createPelicanAuth`)
186
65
 
187
- ```typescript
188
- auth.on("qr", (dataUrl: string) => {
189
- // Display in an <img> tag
190
- document.getElementById("qr").src = dataUrl;
191
- });
192
- ```
66
+ The `createPelicanAuth` function initializes the Pelican UI inside a target DOM element.
193
67
 
194
- #### `deeplink`
68
+ | Option | Type | Required | Description |
69
+ | ---------------- | ---------- | -------- | --------------------------------------------- |
70
+ | `publicKey` | `string` | ✅ | Business public key from Pelican dashboard |
71
+ | `projectId` | `string` | ✅ | Project ID from Pelican dashboard |
72
+ | `authType` | `AuthType` | ✅ | `"signup"`, `"login"`, or `"id-verification"` |
73
+ | `onSuccess` | `Function` | ✅ | Callback with `IdentityResult` |
74
+ | `onError` | `Function` | ❌ | Callback for errors |
75
+ | `onClose` | `Function` | ❌ | Callback when the user closes the modal |
76
+ | `continuousMode` | `boolean` | ❌ | Auto-restart auth after completion |
77
+ | `forceQRCode` | `boolean` | ❌ | Always show QR even on mobile |
78
+ | `buttonText` | `string` | ❌ | Custom text for the Pelican button |
195
79
 
196
- Emitted on mobile with deep link URL.
80
+ ---
197
81
 
198
- ```typescript
199
- auth.on("deeplink", (url: string) => {
200
- // Open Pelican Vault app
201
- window.location.href = url;
202
- // Or use as href in a button
203
- document.getElementById("login-btn").href = url;
204
- });
205
- ```
82
+ ## Low-Level Core Usage (Custom UI)
206
83
 
207
- ## Usage Examples
84
+ If you want to build your own UI from scratch, use the `@pelican-identity/auth-core` package directly. This provides the event-driven state machine without any HTML/CSS.
208
85
 
209
- ### React Hook
86
+ ### Basic Implementation
210
87
 
211
88
  ```typescript
212
- import { useEffect, useState } from "react";
213
- import { PelicanAuth } from "@pelican-identity/sdk";
214
-
215
- function usePelicanAuth(config) {
216
- const [state, setState] = useState("idle");
217
- const [qrCode, setQrCode] = useState(null);
218
- const [deepLink, setDeepLink] = useState(null);
219
- const [error, setError] = useState(null);
220
-
221
- useEffect(() => {
222
- const auth = new PelicanAuth(config);
223
-
224
- auth.on("state", setState);
225
- auth.on("qr", setQrCode);
226
- auth.on("deeplink", setDeepLink);
227
- auth.on("error", setError);
89
+ import { PelicanAuthentication } from "@pelican-identity/auth-core";
228
90
 
229
- auth.on("success", (identity) => {
230
- console.log("Authenticated:", identity);
231
- config.onSuccess?.(identity);
232
- });
233
-
234
- return () => auth.destroy();
235
- }, []);
236
-
237
- return { state, qrCode, deepLink, error };
238
- }
239
-
240
- // Usage
241
- function LoginButton() {
242
- const { state, qrCode, deepLink } = usePelicanAuth({
243
- publicKey: "your-key",
244
- projectId: "your-project",
245
- authType: "login",
246
- onSuccess: (identity) => {
247
- // Handle login
248
- },
249
- });
250
-
251
- if (qrCode) {
252
- return <img src={qrCode} alt="Scan to login" />;
253
- }
254
-
255
- if (deepLink) {
256
- return <a href={deepLink}>Open Pelican App</a>;
257
- }
258
-
259
- return <button onClick={() => auth.start()}>Login</button>;
260
- }
261
- ```
262
-
263
- ### Vue Composition API
264
-
265
- ```vue
266
- <script setup>
267
- import { ref, onMounted, onUnmounted } from "vue";
268
- import { PelicanAuth } from "@pelican-identity/pelican-sdk";
269
-
270
- const props = defineProps(["publicKey", "projectId", "authType"]);
271
- const emit = defineEmits(["success", "error"]);
272
-
273
- const state = ref("idle");
274
- const qrCode = ref(null);
275
- const deepLink = ref(null);
276
-
277
- let auth;
278
-
279
- onMounted(() => {
280
- auth = new PelicanAuth({
281
- publicKey: props.publicKey,
282
- projectId: props.projectId,
283
- authType: props.authType,
284
- });
285
-
286
- auth.on("state", (s) => (state.value = s));
287
- auth.on("qr", (qr) => (qrCode.value = qr));
288
- auth.on("deeplink", (link) => (deepLink.value = link));
289
- auth.on("success", (identity) => emit("success", identity));
290
- auth.on("error", (err) => emit("error", err));
291
-
292
- auth.start();
293
- });
294
-
295
- onUnmounted(() => {
296
- auth?.destroy();
297
- });
298
- </script>
299
-
300
- <template>
301
- <div>
302
- <img v-if="qrCode" :src="qrCode" alt="QR Code" />
303
- <a v-else-if="deepLink" :href="deepLink">Open App</a>
304
- <p v-else>{{ state }}</p>
305
- </div>
306
- </template>
307
- ```
308
-
309
- ### Vanilla JavaScript
310
-
311
- ```javascript
312
- import { PelicanAuth } from "@pelican-identity/sdk";
313
-
314
- // Create container
315
- const container = document.getElementById("auth-container");
316
-
317
- // Initialize
318
- const auth = new PelicanAuth({
91
+ const pelican = new PelicanAuthentication({
319
92
  publicKey: "your-key",
320
- projectId: "your-project",
93
+ projectId: "your-id",
321
94
  authType: "login",
322
95
  });
323
96
 
324
- // Handle QR code
325
- auth.on("qr", (dataUrl) => {
326
- container.innerHTML = `
327
- <img src="${dataUrl}" alt="Scan to login" />
328
- <p>Scan with Pelican Vault app</p>
329
- `;
97
+ // 1. Listen for the QR code
98
+ pelican.on("qr", (qrDataUrl) => {
99
+ document.getElementById("my-qr").src = qrDataUrl;
330
100
  });
331
101
 
332
- // Handle deep link
333
- auth.on("deeplink", (url) => {
334
- container.innerHTML = `
335
- <a href="${url}" class="btn">Open Pelican App</a>
336
- `;
102
+ // 2. Listen for Mobile Deep Links
103
+ pelican.on("deeplink", (url) => {
104
+ document.getElementById("mobile-link").href = url;
337
105
  });
338
106
 
339
- // Handle success
340
- auth.on("success", (identity) => {
341
- console.log("Logged in as:", identity.user_id);
342
- // Redirect or update UI
343
- window.location.href = "/dashboard";
107
+ // 3. Track State Changes
108
+ pelican.on("state", (state) => {
109
+ console.log("Current state:", state); // 'initializing', 'paired', etc.
344
110
  });
345
111
 
346
- // Handle errors
347
- auth.on("error", (error) => {
348
- container.innerHTML = `
349
- <p class="error">${error.message}</p>
350
- <button onclick="auth.start()">Retry</button>
351
- `;
112
+ // 4. Handle Completion
113
+ pelican.on("success", (identity) => {
114
+ alert(`Welcome ${identity.user_id}`);
352
115
  });
353
116
 
354
- // Start authentication
355
- auth.start();
356
-
357
- // Cleanup on page unload
358
- window.addEventListener("beforeunload", () => {
359
- auth.destroy();
360
- });
117
+ // Start the engine
118
+ pelican.start();
361
119
  ```
362
120
 
363
- ## Advanced Features
121
+ ---
364
122
 
365
- ### Continuous Mode
123
+ ## Authentication Flow logic
366
124
 
367
- Automatically restart authentication sessions after completion. Useful for kiosks or multi-user scenarios.
125
+ The SDK manages the transition between Desktop and Mobile automatically:
368
126
 
369
- ```typescript
370
- const auth = new PelicanAuth({
371
- publicKey: "your-key",
372
- projectId: "your-project",
373
- authType: "login",
374
- continuousMode: true, // Enable continuous mode
375
- });
127
+ 1. **Desktop:** Emits a `qr` event containing a Base64 Data URL.
128
+ 2. **Mobile:** Emits a `deeplink` event. Browsers should provide a "Open App" button using this URL.
129
+ 3. **Paired:** Once the user scans/clicks, the state moves to `paired`.
130
+ 4. **Success:** After biometric/PIN approval in the Pelican app, the `success` event fires with user data.
376
131
 
377
- auth.on("success", (identity) => {
378
- // Process user
379
- console.log("User authenticated:", identity);
380
- // Session will automatically restart after ~300ms
381
- });
132
+ ---
382
133
 
383
- auth.start();
384
- ```
385
-
386
- ### Force QR Code on Mobile
134
+ ## Identity Result Structure
387
135
 
388
- By default, mobile devices use deep links. Force QR code display instead:
136
+ Regardless of which integration path you choose, the successful authentication returns this object:
389
137
 
390
138
  ```typescript
391
- const auth = new PelicanAuth({
392
- publicKey: "your-key",
393
- projectId: "your-project",
394
- authType: "login",
395
- forceQRCode: true, // Show QR even on mobile
396
- });
397
- ```
398
-
399
- ### Session Recovery
400
-
401
- The SDK automatically handles session recovery when users return from the Pelican Vault app:
402
-
403
- ```typescript
404
- // Session is automatically cached when deep link is opened
405
- auth.on("deeplink", (url) => {
406
- // User clicks and goes to Pelican app
407
- window.location.href = url;
408
- });
409
-
410
- // When user returns (visibility change), session is recovered automatically
411
- // Success event will fire if authentication completed
412
- auth.on("success", (identity) => {
413
- console.log("Recovered session:", identity);
414
- });
415
- ```
416
-
417
- ### State Machine Tracking
418
-
419
- Track the complete authentication lifecycle:
420
-
421
- ```typescript
422
- auth.on("state", (state) => {
423
- switch (state) {
424
- case "idle":
425
- console.log("Ready to start");
426
- break;
427
- case "initializing":
428
- console.log("Connecting to server...");
429
- break;
430
- case "awaiting-pair":
431
- console.log("Waiting for device...");
432
- break;
433
- case "paired":
434
- console.log("Device connected!");
435
- break;
436
- case "authenticated":
437
- console.log("User authenticated!");
438
- break;
439
- case "confirmed":
440
- console.log("Session confirmed");
441
- break;
442
- case "error":
443
- console.log("Error occurred");
444
- break;
445
- }
446
- });
447
- ```
448
-
449
- ## Error Handling
450
-
451
- The SDK provides detailed error information:
452
-
453
- ```typescript
454
- auth.on("error", (error) => {
455
- console.error("Error type:", error.message);
456
-
457
- // Common errors:
458
- // - "Failed to fetch relay URL" - Server connection issue
459
- // - "WebSocket connection failed" - Network issue
460
- // - "Invalid authentication payload" - Data corruption
461
- // - "Failed to decrypt authentication data" - Crypto error
462
- // - "Authenticating device terminated the connection" - User cancelled
463
- // - "Session recovery failed" - Invalid cached session
464
- });
139
+ interface IdentityResult {
140
+ user_id: string; // Unique business-scoped identifier
141
+ user_data?: {
142
+ first_name?: string;
143
+ email?: { value: string; verified: boolean };
144
+ phone?: { number: string; verified: boolean };
145
+ };
146
+ id_verification?: {
147
+ status: "Approved" | "Declined";
148
+ document_type: string;
149
+ };
150
+ }
465
151
  ```
466
152
 
467
- ## Security Considerations
468
-
469
- 1. **Public Key and Project ID**: It is recommended to use environment variables or fetch from a secure server for production.
470
- 2. **HTTPS Required**: Always use HTTPS in production
471
- 3. **Session Expiry**: Sessions expire after 5 minutes by default
472
- 4. **End-to-End Encryption**: All data is encrypted using TweetNaCl (NaCl crypto)
473
- 5. **No Password Storage**: Authentication happens entirely through the Pelican Vault app
474
-
475
- ## Browser Support
476
-
477
- - Chrome/Edge 90+
478
- - Firefox 88+
479
- - Safari 14+
480
- - Opera 76+
481
-
482
- **Required APIs:**
483
-
484
- - WebSocket
485
- - Crypto API (`crypto.randomUUID()`)
486
- - sessionStorage
487
- - Visibility API
153
+ ---
488
154
 
489
155
  ## Troubleshooting
490
156
 
491
- ### QR Code Not Displaying
492
-
493
- ```typescript
494
- auth.on("qr", (dataUrl) => {
495
- if (!dataUrl) {
496
- console.error("QR code generation failed");
497
- }
498
- });
499
- ```
157
+ ### `crypto.randomUUID is not a function`
500
158
 
501
- ### WebSocket Connection Issues
502
-
503
- ```typescript
504
- // Check network connectivity
505
- auth.on("error", (error) => {
506
- if (error.message.includes("WebSocket")) {
507
- console.log("Check network connection");
508
- // Retry logic
509
- setTimeout(() => auth.start(), 5000);
510
- }
511
- });
512
- ```
513
-
514
- ### Session Recovery Not Working
515
-
516
- Ensure visibility change detection is working:
517
-
518
- ```typescript
519
- document.addEventListener("visibilitychange", () => {
520
- console.log("Visibility changed:", document.visibilityState);
521
- });
522
- ```
523
-
524
- ## TypeScript Support
525
-
526
- Full TypeScript definitions included:
527
-
528
- ```typescript
529
- import type {
530
- IEmail,
531
- IKycData,
532
- IPhone,
533
- IUserData,
534
- IdentityResult,
535
- IdCardTypes,
536
- } from "@pelican-identity/sdk";
537
- import {
538
- AuthType,
539
- ISocketMessage,
540
- PelicanAuthConfig,
541
- PelicanAuthEventMap,
542
- PelicanAuthState,
543
- } from "@pelican-identity/sdk";
544
-
545
- const config: PelicanAuthConfig = {
546
- publicKey: "your-key",
547
- projectId: "your-project",
548
- authType: "login",
549
- };
550
-
551
- const auth = new PelicanAuth(config);
552
-
553
- auth.on("success", (identity: IdentityResult) => {
554
- const userId: string = identity.user_id;
555
- });
556
- ```
159
+ **Cause:** Browsers only allow the Crypto API in **Secure Contexts** (HTTPS or localhost).
160
+ **Fix:** Ensure you are serving your site over HTTPS or using `http://localhost`.
557
161
 
558
- ## License
162
+ ### QR Code not showing
559
163
 
560
- MIT
164
+ **Cause:** The engine might be in `initializing` state or the domain isn't whitelisted.
165
+ **Fix:** Check your Pelican Dashboard and ensure your current domain (including port if applicable) is added to the project whitelist.
561
166
 
562
- ## Support
167
+ ### Styles not applying
563
168
 
564
- - Documentation: https://docs.pelicanidentity.com
565
- - Issues: https://github.com/pelican-identity/sdk/issues
566
- - Email: support@pelicanidentity.com
169
+ **Cause:** The CSS file is missing.
170
+ **Fix:** If using NPM, ensure you import `@pelican-identity/vanilla/dist/pelican.css`. If using the CDN `.min.js` version with `injectStyle: true`, this should be automatic.
567
171
 
568
- ## Changelog
172
+ ---
569
173
 
570
- See [CHANGELOG.md](CHANGELOG.md) for release history.
174
+ **Would you like me to help you create a "Getting Started" guide specifically for the Pelican Dashboard setup to complement this SDK documentation?**
@@ -0,0 +1,2 @@
1
+ export declare const BASEURL = "https://identityapi.pelicanidentity.com";
2
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,OAAO,4CAA4C,CAAC"}
@@ -0,0 +1,2 @@
1
+ export const BASEURL = "https://identityapi.pelicanidentity.com";
2
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,OAAO,GAAG,yCAAyC,CAAC"}