w3pk 0.1.0 → 0.3.0

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
@@ -2,174 +2,83 @@
2
2
 
3
3
  WebAuthn SDK for passwordless authentication with client-side encrypted Ethereum wallets.
4
4
 
5
- ---
6
-
7
5
  ## Install
8
6
 
9
7
  ```bash
10
8
  npm install w3pk
11
- # or
12
- pnpm add w3pk
13
- # or
14
- yarn add w3pk
15
9
  ```
16
10
 
17
- ---
18
-
19
- ## Integration
20
-
21
- ### Basic Setup
11
+ ## Quick Start
22
12
 
23
13
  ```typescript
24
14
  import { createWeb3Passkey } from 'w3pk'
15
+ import { startRegistration, startAuthentication } from '@simplewebauthn/browser'
25
16
 
26
17
  const w3pk = createWeb3Passkey({
27
18
  apiBaseUrl: 'https://webauthn.w3hc.org'
28
19
  })
29
- ```
30
20
 
31
- ### Configuration Options
21
+ // Generate wallet
22
+ const wallet = await w3pk.generateWallet()
23
+ console.log('Backup this mnemonic:', wallet.mnemonic)
32
24
 
33
- ```typescript
34
- const w3pk = createWeb3Passkey({
35
- apiBaseUrl: string, // Required: Backend API URL
36
- timeout?: number, // Optional: Request timeout (default: 30000ms)
37
- debug?: boolean, // Optional: Enable debug logs (default: false)
38
- onError?: (error) => void, // Optional: Global error handler
39
- onAuthStateChanged?: (isAuth, user?) => void // Optional: Auth state callback
25
+ // Register
26
+ const beginRes = await fetch('https://webauthn.w3hc.org/webauthn/register/begin', {
27
+ method: 'POST',
28
+ headers: { 'Content-Type': 'application/json' },
29
+ body: JSON.stringify({ username: 'alice', ethereumAddress: wallet.address })
40
30
  })
41
- ```
31
+ const { data } = await beginRes.json()
32
+ const credential = await startRegistration(data.options)
42
33
 
43
- ### Complete Integration Example
34
+ await w3pk.register({
35
+ username: 'alice',
36
+ ethereumAddress: wallet.address,
37
+ mnemonic: wallet.mnemonic,
38
+ credentialId: credential.id,
39
+ challenge: data.options.challenge
40
+ })
44
41
 
45
- ```typescript
46
- import { createWeb3Passkey } from 'w3pk'
47
- import { startRegistration, startAuthentication } from '@simplewebauthn/browser'
42
+ // Login
43
+ const result = await w3pk.login()
44
+ console.log('Logged in:', result.user?.username)
48
45
 
49
- // Initialize SDK
50
- const w3pk = createWeb3Passkey({
51
- apiBaseUrl: 'https://webauthn.w3hc.org',
52
- debug: true,
53
- onAuthStateChanged: (isAuthenticated, user) => {
54
- console.log('Auth state:', isAuthenticated, user?.username)
55
- },
56
- onError: (error) => {
57
- console.error('SDK Error:', error.message)
58
- }
46
+ // Sign message
47
+ const authBeginRes = await fetch('https://webauthn.w3hc.org/webauthn/authenticate/usernameless/begin', {
48
+ method: 'POST'
59
49
  })
50
+ const authData = await authBeginRes.json()
51
+ const authCredential = await startAuthentication(authData.data.options)
60
52
 
61
- // 1. Registration Flow
62
- async function registerUser(username: string) {
63
- try {
64
- // Generate BIP39 wallet
65
- const wallet = await w3pk.generateWallet()
66
-
67
- // IMPORTANT: Show mnemonic to user for backup
68
- alert(`⚠️ BACKUP THIS MNEMONIC:\n\n${wallet.mnemonic}\n\nYou will need it to recover your wallet!`)
69
-
70
- // Get registration options from backend
71
- const beginResponse = await fetch('https://webauthn.w3hc.org/webauthn/register/begin', {
72
- method: 'POST',
73
- headers: { 'Content-Type': 'application/json' },
74
- body: JSON.stringify({
75
- username,
76
- ethereumAddress: wallet.address
77
- })
78
- })
79
- const { data } = await beginResponse.json()
80
-
81
- // Create WebAuthn credential (triggers biometric prompt)
82
- const credential = await startRegistration(data.options)
83
-
84
- // Register with w3pk SDK
85
- await w3pk.register({
86
- username,
87
- ethereumAddress: wallet.address,
88
- mnemonic: wallet.mnemonic,
89
- credentialId: credential.id,
90
- challenge: data.options.challenge
91
- })
92
-
93
- console.log('✅ Registration successful!')
94
- console.log('Address:', wallet.address)
95
- } catch (error) {
96
- console.error('Registration failed:', error)
97
- }
98
- }
99
-
100
- // 2. Login Flow (Usernameless)
101
- async function login() {
102
- try {
103
- const result = await w3pk.authenticateUsernameless()
104
-
105
- if (result.verified && result.user) {
106
- console.log('✅ Logged in as:', result.user.username)
107
- console.log('Address:', result.user.ethereumAddress)
108
- }
109
- } catch (error) {
110
- console.error('Login failed:', error)
111
- }
112
- }
113
-
114
- // 3. Message Signing Flow
115
- async function signMessage(message: string) {
116
- try {
117
- // Get fresh authentication challenge
118
- const beginResponse = await fetch('https://webauthn.w3hc.org/webauthn/authenticate/usernameless/begin', {
119
- method: 'POST'
120
- })
121
- const { data } = await beginResponse.json()
122
-
123
- // Authenticate user (triggers biometric prompt)
124
- const credential = await startAuthentication(data.options)
125
-
126
- // Sign message with encrypted wallet
127
- const signature = await w3pk.signMessage(
128
- message,
129
- credential.id,
130
- data.options.challenge
131
- )
132
-
133
- console.log('✅ Message signed!')
134
- console.log('Signature:', signature)
135
-
136
- return signature
137
- } catch (error) {
138
- console.error('Signing failed:', error)
139
- }
140
- }
141
-
142
- // 4. Logout
143
- function logout() {
144
- w3pk.logout()
145
- console.log('✅ Logged out')
146
- }
147
-
148
- // Usage
149
- await registerUser('alice')
150
- await login()
151
- await signMessage('Hello, Web3!')
152
- logout()
53
+ const signature = await w3pk.signMessage(
54
+ 'Hello, Web3!',
55
+ authCredential.id,
56
+ authData.data.options.challenge
57
+ )
153
58
  ```
154
59
 
155
- ### API Reference
60
+ ## API
156
61
 
157
- #### Wallet Methods
62
+ ### Configuration
158
63
 
159
64
  ```typescript
160
- // Generate new BIP39 wallet (12-word mnemonic)
161
- const wallet = await w3pk.generateWallet()
162
- // Returns: { address: string, mnemonic: string }
163
-
164
- // Check if wallet exists for current user (browser only)
165
- const hasWallet = await w3pk.hasWallet()
166
- // Returns: boolean
65
+ createWeb3Passkey({
66
+ apiBaseUrl: string, // Required: Backend URL
67
+ timeout?: number, // Optional: Request timeout (default: 30000ms)
68
+ debug?: boolean, // Optional: Enable logs (default: false)
69
+ onError?: (error) => void, // Optional: Error handler
70
+ onAuthStateChanged?: (isAuth, user?) => void // Optional: Auth callback
71
+ })
167
72
  ```
168
73
 
169
- #### Authentication Methods
74
+ ### Methods
170
75
 
171
76
  ```typescript
172
- // Register new user (browser only)
77
+ // Generate BIP39 wallet (12-word mnemonic)
78
+ await w3pk.generateWallet()
79
+ // Returns: { address: string, mnemonic: string }
80
+
81
+ // Register new user
173
82
  await w3pk.register({
174
83
  username: string,
175
84
  ethereumAddress: string,
@@ -178,42 +87,37 @@ await w3pk.register({
178
87
  challenge: string
179
88
  })
180
89
 
181
- // Login without username (browser only)
182
- const result = await w3pk.authenticateUsernameless()
90
+ // Login (usernameless)
91
+ await w3pk.login()
183
92
  // Returns: { verified: boolean, user?: { id, username, ethereumAddress } }
184
93
 
185
- // Login with specific address (browser only)
186
- const result = await w3pk.authenticate(ethereumAddress: string)
187
- // Returns: { verified: boolean, user?: { id, username, ethereumAddress } }
94
+ // Authenticate with address
95
+ await w3pk.authenticate(ethereumAddress: string)
188
96
 
189
- // Logout current user
190
- w3pk.logout()
191
- ```
97
+ // Sign message (requires fresh auth)
98
+ await w3pk.signMessage(message: string, credentialId: string, challenge: string)
99
+ // Returns: string (signature)
192
100
 
193
- #### Message Signing
101
+ // Logout
102
+ w3pk.logout()
194
103
 
195
- ```typescript
196
- // Sign message with encrypted wallet (browser only, requires fresh auth)
197
- const signature = await w3pk.signMessage(
198
- message: string,
199
- credentialId: string,
200
- challenge: string
201
- )
202
- // Returns: string (Ethereum signature)
104
+ // Check wallet exists
105
+ await w3pk.hasWallet()
106
+ // Returns: boolean
203
107
  ```
204
108
 
205
- #### Properties
109
+ ### Properties
206
110
 
207
111
  ```typescript
208
- w3pk.isAuthenticated // boolean - Current auth state
209
- w3pk.user // UserInfo | null - Current user info
210
- w3pk.version // string - SDK version
211
- w3pk.isBrowserEnvironment // boolean - Check if running in browser
112
+ w3pk.isAuthenticated // boolean
113
+ w3pk.user // UserInfo | null
114
+ w3pk.version // string
115
+ w3pk.isBrowserEnvironment // boolean
212
116
  ```
213
117
 
214
- ### Backend Integration
118
+ ## Backend
215
119
 
216
- This SDK requires a WebAuthn backend API. Use [nestjs-webauthn](https://github.com/w3hc/nestjs-webauthn):
120
+ Requires [nestjs-webauthn](https://github.com/w3hc/nestjs-webauthn):
217
121
 
218
122
  ```bash
219
123
  git clone https://github.com/w3hc/nestjs-webauthn
@@ -222,240 +126,33 @@ pnpm install
222
126
  pnpm start:dev
223
127
  ```
224
128
 
225
- Configure your backend URL in the SDK:
226
-
227
- ```typescript
228
- const w3pk = createWeb3Passkey({
229
- apiBaseUrl: 'http://localhost:3000' // Your backend URL
230
- })
231
- ```
232
-
233
- ### Environment Support
234
-
235
- | Feature | Node.js | Browser |
236
- |---------|---------|---------|
237
- | Wallet Generation | ✅ | ✅ |
238
- | WebAuthn Registration | ❌ | ✅ |
239
- | WebAuthn Authentication | ❌ | ✅ |
240
- | Message Signing | ❌ | ✅ |
241
- | Encrypted Storage | ❌ | ✅ |
242
-
243
- The SDK gracefully handles non-browser environments and will show appropriate warnings.
244
-
245
- ### Security Notes
246
-
247
- ⚠️ **Critical Security Information:**
248
-
249
- - **Mnemonics are encrypted client-side** using keys derived from WebAuthn credentials
250
- - **Private keys never leave the browser** - all cryptographic operations happen locally
251
- - **Users MUST backup their 12-word mnemonic** during registration
252
- - **No mnemonic backup = no wallet recovery** - if the device is lost, the wallet is lost
253
- - **Each device stores its own encrypted wallet** in IndexedDB
254
- - **Message signing requires fresh WebAuthn authentication** for security
255
-
256
- ### Browser Support
257
-
258
- - Chrome 67+ (all platforms)
259
- - Firefox 60+ (all platforms)
260
- - Safari 14+ (macOS, iOS)
261
- - Edge 18+ (Windows)
262
-
263
- WebAuthn/FIDO2 compatible authenticators required (biometrics, security keys, etc.)
264
-
265
- ---
266
-
267
- ## Contribute
268
-
269
- ### Prerequisites
270
-
271
- ```bash
272
- pnpm install
273
- ```
274
-
275
- ### Development
129
+ ## Security
276
130
 
277
- ```bash
278
- # Watch mode (rebuilds on changes)
279
- pnpm dev
131
+ - ✅ Client-side AES-GCM-256 encryption
132
+ - PBKDF2 key derivation from WebAuthn credentials
133
+ - ✅ Private keys never leave the browser
134
+ - ✅ IndexedDB encrypted storage per device
135
+ - ⚠️ Users MUST backup their 12-word mnemonic
280
136
 
281
- # Build for production
282
- pnpm build
283
- ```
284
-
285
- ### Testing
286
-
287
- #### Node.js Tests (Wallet Generation)
288
-
289
- Run the Node.js test to verify wallet generation works:
137
+ ## Testing
290
138
 
291
139
  ```bash
140
+ # Node.js test (wallet generation)
292
141
  pnpm test
293
- ```
294
142
 
295
- **Expected output:**
296
- ```
297
- w3pk: Running in non-browser environment, some features disabled
298
- SDK initialized successfully
299
- Is authenticated: false
300
- Current user: null
301
- SDK version: 0.1.0
302
- Wallet generated: 0x304d39f46FbD7464Fa799034629bD93091ACe0EA
303
- Wallet generated:
304
- Address: 0x304d39f46FbD7464Fa799034629bD93091ACe0EA
305
- Mnemonic: tortoise barrel margin object loyal cart mechanic suffer scorpion athlete tide city
306
- ```
307
-
308
- #### Browser Tests (Full Features)
309
-
310
- Test all features including WebAuthn authentication and message signing:
311
-
312
- 1. **Start your backend:**
313
- ```bash
314
- cd nestjs-webauthn
315
- pnpm start:dev
316
- ```
317
-
318
- 2. **Serve the test files:**
319
- ```bash
320
- pnpm test:browser
321
- ```
322
-
323
- 3. **Open in browser:**
324
- ```
325
- http://localhost:3000/test/browser-test.html
326
- ```
327
-
328
- 4. **Test the features:**
329
- - Click "Generate Wallet" - Creates a new BIP39 wallet
330
- - Click "Register" - Creates WebAuthn credential and encrypts mnemonic
331
- - Click "Login (Usernameless)" - Authenticates with biometric/passkey
332
- - Click "Logout" - Clears authentication state
333
-
334
- **Browser test features:**
335
- - ✅ Real WebAuthn credential creation
336
- - ✅ Biometric authentication prompts
337
- - ✅ Wallet encryption/decryption
338
- - ✅ IndexedDB storage
339
- - ✅ Message signing with encrypted keys
340
-
341
- ### Project Structure
342
-
343
- ```
344
- w3pk/
345
- ├── src/
346
- │ ├── auth/ # WebAuthn authentication flows
347
- │ │ ├── authenticate.ts
348
- │ │ ├── register.ts
349
- │ │ ├── types.ts
350
- │ │ └── usernameless.ts
351
- │ ├── core/ # SDK core
352
- │ │ ├── config.ts
353
- │ │ ├── errors.ts
354
- │ │ └── sdk.ts
355
- │ ├── wallet/ # Wallet & crypto
356
- │ │ ├── crypto.ts # AES-GCM encryption
357
- │ │ ├── generate.ts # BIP39 generation
358
- │ │ ├── signing.ts # Message signing
359
- │ │ ├── storage.ts # IndexedDB
360
- │ │ └── types.ts
361
- │ ├── utils/ # Utilities
362
- │ │ ├── api.ts # API client
363
- │ │ └── validation.ts # Input validation
364
- │ ├── types/ # Shared types
365
- │ │ └── index.ts
366
- │ └── index.ts # Main export
367
- ├── test/
368
- │ ├── test.ts # Node.js tests
369
- │ └── browser-test.html # Browser tests
370
- ├── dist/ # Built files
371
- ├── package.json
372
- ├── tsconfig.json
373
- └── tsup.config.ts
374
- ```
375
-
376
- ### Making Changes
377
-
378
- 1. **Fork the repository**
379
- 2. **Create a feature branch:**
380
- ```bash
381
- git checkout -b feature/my-feature
382
- ```
383
-
384
- 3. **Make your changes in `src/`**
385
-
386
- 4. **Test your changes:**
387
- ```bash
388
- pnpm build
389
- pnpm test
390
- pnpm test:browser
391
- ```
392
-
393
- 5. **Commit and push:**
394
- ```bash
395
- git add .
396
- git commit -m "feat: add my feature"
397
- git push origin feature/my-feature
398
- ```
399
-
400
- 6. **Open a Pull Request**
401
-
402
- ### Publishing
403
-
404
- ```bash
405
- # Bump version
406
- npm version patch|minor|major
407
-
408
- # Build and publish
143
+ # Build
409
144
  pnpm build
410
- npm publish
411
- ```
412
-
413
- ### Code Style
414
-
415
- - **TypeScript** with strict mode
416
- - **ESM + CommonJS** dual package
417
- - **Functional** where possible
418
- - **Clear error messages** for debugging
419
- - **JSDoc comments** for public APIs
420
145
 
421
- ---
422
-
423
- ## Features
424
-
425
- - 🔐 **Passwordless Authentication** - WebAuthn/FIDO2 biometric login
426
- - 💼 **BIP39 HD Wallets** - Standard 12-word mnemonics, BIP44 derivation (m/44'/60'/0'/0/0)
427
- - 🔒 **Client-Side Encryption** - AES-GCM-256 with PBKDF2 key derivation
428
- - 💾 **IndexedDB Storage** - Encrypted wallets stored locally per device
429
- - ✍️ **Message Signing** - Ethereum message signing with encrypted keys
430
- - 🌐 **Zero Server Trust** - Private keys never leave the client
431
- - 🔄 **Usernameless Auth** - Streamlined authentication flow
432
-
433
- ---
434
-
435
- ## License
436
-
437
- GPL-3.0-or-later
438
-
439
- ---
440
-
441
- ## Links
442
-
443
- - **GitHub:** https://github.com/w3hc/w3pk
444
- - **Backend API:** https://github.com/w3hc/nestjs-webauthn
445
- - **Issues:** https://github.com/w3hc/w3pk/issues
446
- - **NPM:** https://www.npmjs.com/package/w3pk
447
-
448
- ---
146
+ # Watch mode
147
+ pnpm dev
148
+ ```
449
149
 
450
150
  ## Support
451
151
 
452
- Reach out to [Julien Béranger](https://github.com/julienbrg):
453
-
152
+ Contact [Julien Béranger](https://github.com/julienbrg):
454
153
  - Element: [@julienbrg:matrix.org](https://matrix.to/#/@julienbrg:matrix.org)
455
154
  - Farcaster: [julien-](https://warpcast.com/julien-)
456
155
  - Telegram: [@julienbrg](https://t.me/julienbrg)
457
156
  - Twitter: [@julienbrg](https://twitter.com/julienbrg)
458
- - Discord: [julienbrg](https://discordapp.com/users/julienbrg)
459
- - LinkedIn: [julienberanger](https://www.linkedin.com/in/julienberanger/)
460
157
 
461
- <img src="https://bafkreid5xwxz4bed67bxb2wjmwsec4uhlcjviwy7pkzwoyu5oesjd3sp64.ipfs.w3s.link" alt="built-with-ethereum-w3hc" width="100"/>
158
+ <img src="https://bafkreid5xwxz4bed67bxb2wjmwsec4uhlcjviwy7pkzwoyu5oesjd3sp64.ipfs.w3s.link" alt="built-with-ethereum-w3hc" width="100"/>
package/dist/index.d.mts CHANGED
@@ -4,6 +4,7 @@
4
4
  interface UserInfo {
5
5
  id: string;
6
6
  username: string;
7
+ displayName: string;
7
8
  ethereumAddress: string;
8
9
  }
9
10
  interface WalletInfo {
@@ -70,22 +71,13 @@ interface Web3PasskeyConfig {
70
71
  }
71
72
 
72
73
  /**
73
- * Authentication-related types
74
+ * Main Web3Passkey SDK class
74
75
  */
75
76
 
76
77
  interface AuthResult {
77
78
  verified: boolean;
78
- user?: {
79
- id: string;
80
- username: string;
81
- ethereumAddress: string;
82
- };
79
+ user?: UserInfo;
83
80
  }
84
-
85
- /**
86
- * Main Web3Passkey SDK class
87
- */
88
-
89
81
  declare class Web3Passkey {
90
82
  private config;
91
83
  private apiClient;
@@ -99,6 +91,7 @@ declare class Web3Passkey {
99
91
  private saveAuthState;
100
92
  private clearAuthState;
101
93
  private notifyAuthStateChange;
94
+ private createUserInfo;
102
95
  /**
103
96
  * Generate a new BIP39 wallet
104
97
  * @returns Wallet info with mnemonic (user MUST backup)
@@ -110,39 +103,37 @@ declare class Web3Passkey {
110
103
  hasWallet(): Promise<boolean>;
111
104
  /**
112
105
  * Register a new user with WebAuthn
106
+ * Handles the complete registration flow internally
107
+ * Automatically generates wallet if not provided
108
+ *
113
109
  * @param username Username for the account
114
- * @param ethereumAddress Ethereum address from generated wallet
115
- * @param mnemonic BIP39 mnemonic to encrypt and store
116
- * @param credentialId WebAuthn credential ID (from registration response)
117
- * @param challenge Challenge used in registration
110
+ * @param ethereumAddress Optional: Ethereum address (will generate if not provided)
111
+ * @param mnemonic Optional: BIP39 mnemonic (will generate if not provided)
112
+ * @returns Object containing ethereumAddress and mnemonic (only if generated)
118
113
  */
119
114
  register(options: {
120
115
  username: string;
116
+ ethereumAddress?: string;
117
+ mnemonic?: string;
118
+ }): Promise<{
121
119
  ethereumAddress: string;
122
- mnemonic: string;
123
- credentialId: string;
124
- challenge: string;
125
- }): Promise<void>;
126
- /**
127
- * Authenticate with Ethereum address
128
- */
129
- authenticate(ethereumAddress: string): Promise<AuthResult>;
120
+ mnemonic?: string;
121
+ }>;
130
122
  /**
131
123
  * Authenticate without username (usernameless flow)
132
124
  */
133
- authenticateUsernameless(): Promise<AuthResult>;
125
+ login(): Promise<AuthResult>;
134
126
  /**
135
127
  * Logout current user
136
128
  */
137
129
  logout(): void;
138
130
  /**
139
131
  * Sign a message with encrypted wallet
140
- * Requires fresh WebAuthn authentication
132
+ * Handles fresh WebAuthn authentication internally
133
+ *
141
134
  * @param message Message to sign
142
- * @param credentialId WebAuthn credential ID (from fresh auth)
143
- * @param challenge Challenge from fresh auth
144
135
  */
145
- signMessage(message: string, credentialId: string, challenge: string): Promise<string>;
136
+ signMessage(message: string): Promise<string>;
146
137
  /**
147
138
  * Check if user is authenticated
148
139
  */
@@ -168,4 +159,4 @@ declare class Web3Passkey {
168
159
 
169
160
  declare function createWeb3Passkey(config: Web3PasskeyConfig): Web3Passkey;
170
161
 
171
- export { ApiError, type AuthResult, AuthenticationError, CryptoError, RegistrationError, StorageError, type UserInfo, WalletError, type WalletInfo, Web3Passkey, type Web3PasskeyConfig, Web3PasskeyError, createWeb3Passkey, createWeb3Passkey as default };
162
+ export { ApiError, AuthenticationError, CryptoError, RegistrationError, StorageError, type UserInfo, WalletError, type WalletInfo, Web3Passkey, type Web3PasskeyConfig, Web3PasskeyError, createWeb3Passkey, createWeb3Passkey as default };