kentucky-signer-viem 0.1.1 → 0.1.4
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 +207 -219
- package/dist/index.d.mts +802 -7
- package/dist/index.d.ts +802 -7
- package/dist/index.js +964 -37
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +955 -37
- package/dist/index.mjs.map +1 -1
- package/dist/react/index.d.mts +61 -3
- package/dist/react/index.d.ts +61 -3
- package/dist/react/index.js +1286 -173
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +1288 -174
- package/dist/react/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/account.ts +111 -22
- package/src/auth.ts +16 -6
- package/src/client.ts +438 -18
- package/src/ephemeral.ts +407 -0
- package/src/index.ts +56 -0
- package/src/react/context.tsx +360 -45
- package/src/react/hooks.ts +11 -0
- package/src/react/index.ts +1 -0
- package/src/secure-client.ts +417 -0
- package/src/types.ts +332 -0
package/README.md
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
# kentucky-signer-viem
|
|
2
2
|
|
|
3
|
-
A custom Viem account integration for the Kentucky Signer service, enabling EVM transaction signing using passkey (WebAuthn) or password authentication.
|
|
3
|
+
A custom Viem account integration for the Kentucky Signer service, enabling EVM transaction signing using passkey (WebAuthn) or password authentication with optional two-factor authentication (TOTP/PIN).
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
|
-
- Custom Viem
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
7
|
+
- **Custom Viem Account** - Full Viem compatibility for signing transactions, messages, and typed data
|
|
8
|
+
- **Multiple Authentication Methods**
|
|
9
|
+
- Passkey (WebAuthn) for browser environments
|
|
10
|
+
- Password authentication for browser and Node.js
|
|
11
|
+
- JWT token authentication for server environments
|
|
12
|
+
- **Secure Mode** - Ephemeral key signing with client-side key generation
|
|
13
|
+
- **Two-Factor Authentication** - TOTP (authenticator app) and PIN support
|
|
14
|
+
- **Guardian Recovery** - Social recovery with trusted guardians
|
|
15
|
+
- **React Integration** - Hooks and context for easy React app integration
|
|
16
|
+
- **TypeScript Support** - Full type definitions included
|
|
17
|
+
- **Session Management** - Automatic refresh and persistence options
|
|
15
18
|
|
|
16
19
|
## Installation
|
|
17
20
|
|
|
@@ -63,67 +66,36 @@ const hash = await walletClient.sendTransaction({
|
|
|
63
66
|
to: '0x...',
|
|
64
67
|
value: parseEther('0.1'),
|
|
65
68
|
})
|
|
66
|
-
console.log('Transaction hash:', hash)
|
|
67
69
|
```
|
|
68
70
|
|
|
69
|
-
### Password Authentication
|
|
71
|
+
### Password Authentication
|
|
70
72
|
|
|
71
73
|
```typescript
|
|
72
|
-
import { createWalletClient, http, parseEther } from 'viem'
|
|
73
|
-
import { mainnet } from 'viem/chains'
|
|
74
74
|
import {
|
|
75
|
-
createKentuckySignerAccount,
|
|
76
75
|
authenticateWithPassword,
|
|
77
76
|
createAccountWithPassword,
|
|
78
77
|
} from 'kentucky-signer-viem'
|
|
79
78
|
|
|
80
|
-
//
|
|
79
|
+
// Create a new account
|
|
81
80
|
const newAccount = await createAccountWithPassword({
|
|
82
81
|
baseUrl: 'https://signer.example.com',
|
|
83
82
|
password: 'your-secure-password',
|
|
84
83
|
confirmation: 'your-secure-password',
|
|
85
84
|
})
|
|
86
|
-
console.log('Account ID:', newAccount.account_id)
|
|
87
|
-
console.log('EVM Address:', newAccount.addresses.evm)
|
|
88
85
|
|
|
89
|
-
//
|
|
86
|
+
// Or authenticate with existing account
|
|
90
87
|
const session = await authenticateWithPassword({
|
|
91
88
|
baseUrl: 'https://signer.example.com',
|
|
92
|
-
accountId:
|
|
89
|
+
accountId: 'existing_account_id',
|
|
93
90
|
password: 'your-secure-password',
|
|
94
91
|
})
|
|
95
|
-
|
|
96
|
-
// Create Kentucky Signer account
|
|
97
|
-
const account = createKentuckySignerAccount({
|
|
98
|
-
config: {
|
|
99
|
-
baseUrl: 'https://signer.example.com',
|
|
100
|
-
accountId: session.accountId,
|
|
101
|
-
},
|
|
102
|
-
session,
|
|
103
|
-
defaultChainId: 1,
|
|
104
|
-
})
|
|
105
|
-
|
|
106
|
-
// Use with Viem
|
|
107
|
-
const walletClient = createWalletClient({
|
|
108
|
-
account,
|
|
109
|
-
chain: mainnet,
|
|
110
|
-
transport: http('https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY'),
|
|
111
|
-
})
|
|
112
|
-
|
|
113
|
-
const hash = await walletClient.sendTransaction({
|
|
114
|
-
to: '0x...',
|
|
115
|
-
value: parseEther('0.1'),
|
|
116
|
-
})
|
|
117
92
|
```
|
|
118
93
|
|
|
119
94
|
### Node.js (with JWT Token)
|
|
120
95
|
|
|
121
96
|
```typescript
|
|
122
|
-
import { createWalletClient, http, parseEther } from 'viem'
|
|
123
|
-
import { mainnet } from 'viem/chains'
|
|
124
97
|
import { createServerAccount } from 'kentucky-signer-viem'
|
|
125
98
|
|
|
126
|
-
// Create account with existing JWT token
|
|
127
99
|
const account = createServerAccount(
|
|
128
100
|
'https://signer.example.com',
|
|
129
101
|
'account_id_hex',
|
|
@@ -131,18 +103,6 @@ const account = createServerAccount(
|
|
|
131
103
|
'0xYourEvmAddress',
|
|
132
104
|
1 // chainId
|
|
133
105
|
)
|
|
134
|
-
|
|
135
|
-
// Use with Viem
|
|
136
|
-
const walletClient = createWalletClient({
|
|
137
|
-
account,
|
|
138
|
-
chain: mainnet,
|
|
139
|
-
transport: http('https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY'),
|
|
140
|
-
})
|
|
141
|
-
|
|
142
|
-
const hash = await walletClient.sendTransaction({
|
|
143
|
-
to: '0x...',
|
|
144
|
-
value: parseEther('0.1'),
|
|
145
|
-
})
|
|
146
106
|
```
|
|
147
107
|
|
|
148
108
|
## React Integration
|
|
@@ -158,6 +118,7 @@ function App() {
|
|
|
158
118
|
baseUrl="https://signer.example.com"
|
|
159
119
|
defaultChainId={1}
|
|
160
120
|
persistSession={true}
|
|
121
|
+
useEphemeralKeys={true} // Enable secure mode
|
|
161
122
|
>
|
|
162
123
|
<YourApp />
|
|
163
124
|
</KentuckySignerProvider>
|
|
@@ -168,29 +129,24 @@ function App() {
|
|
|
168
129
|
### Authentication Hook
|
|
169
130
|
|
|
170
131
|
```tsx
|
|
171
|
-
import { useKentuckySigner
|
|
132
|
+
import { useKentuckySigner } from 'kentucky-signer-viem/react'
|
|
172
133
|
|
|
173
134
|
function LoginButton() {
|
|
174
|
-
const { isAuthenticated, account } = useKentuckySigner()
|
|
175
|
-
const { login, isLoading, error } = usePasskeyAuth()
|
|
176
|
-
const [accountId, setAccountId] = useState('')
|
|
135
|
+
const { isAuthenticated, account, authenticate, logout } = useKentuckySigner()
|
|
177
136
|
|
|
178
137
|
if (isAuthenticated && account) {
|
|
179
|
-
return
|
|
138
|
+
return (
|
|
139
|
+
<div>
|
|
140
|
+
<span>Connected: {account.address}</span>
|
|
141
|
+
<button onClick={logout}>Logout</button>
|
|
142
|
+
</div>
|
|
143
|
+
)
|
|
180
144
|
}
|
|
181
145
|
|
|
182
146
|
return (
|
|
183
|
-
<
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
value={accountId}
|
|
187
|
-
onChange={(e) => setAccountId(e.target.value)}
|
|
188
|
-
/>
|
|
189
|
-
<button onClick={() => login(accountId)} disabled={isLoading}>
|
|
190
|
-
{isLoading ? 'Authenticating...' : 'Login with Passkey'}
|
|
191
|
-
</button>
|
|
192
|
-
{error && <div className="error">{error.message}</div>}
|
|
193
|
-
</div>
|
|
147
|
+
<button onClick={() => authenticate('account_id')}>
|
|
148
|
+
Login with Passkey
|
|
149
|
+
</button>
|
|
194
150
|
)
|
|
195
151
|
}
|
|
196
152
|
```
|
|
@@ -200,159 +156,173 @@ function LoginButton() {
|
|
|
200
156
|
```tsx
|
|
201
157
|
import { useWalletClient, useIsReady } from 'kentucky-signer-viem/react'
|
|
202
158
|
import { mainnet } from 'viem/chains'
|
|
203
|
-
import { parseEther } from 'viem'
|
|
204
159
|
|
|
205
160
|
function SendTransaction() {
|
|
206
161
|
const isReady = useIsReady()
|
|
207
|
-
const walletClient = useWalletClient({
|
|
208
|
-
chain: mainnet,
|
|
209
|
-
rpcUrl: 'https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY',
|
|
210
|
-
})
|
|
162
|
+
const walletClient = useWalletClient({ chain: mainnet })
|
|
211
163
|
|
|
212
164
|
async function send() {
|
|
213
165
|
if (!walletClient) return
|
|
214
|
-
|
|
215
166
|
const hash = await walletClient.sendTransaction({
|
|
216
167
|
to: '0x...',
|
|
217
168
|
value: parseEther('0.1'),
|
|
218
169
|
})
|
|
219
|
-
console.log('Transaction hash:', hash)
|
|
220
170
|
}
|
|
221
171
|
|
|
222
|
-
return
|
|
223
|
-
<button onClick={send} disabled={!isReady}>
|
|
224
|
-
Send 0.1 ETH
|
|
225
|
-
</button>
|
|
226
|
-
)
|
|
172
|
+
return <button onClick={send} disabled={!isReady}>Send</button>
|
|
227
173
|
}
|
|
228
174
|
```
|
|
229
175
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
```tsx
|
|
233
|
-
import { useSignMessage } from 'kentucky-signer-viem/react'
|
|
234
|
-
|
|
235
|
-
function SignMessageDemo() {
|
|
236
|
-
const { signMessage, isLoading, isAvailable } = useSignMessage()
|
|
237
|
-
const [signature, setSignature] = useState('')
|
|
238
|
-
|
|
239
|
-
async function sign() {
|
|
240
|
-
const sig = await signMessage('Hello, Kentucky Signer!')
|
|
241
|
-
setSignature(sig)
|
|
242
|
-
}
|
|
176
|
+
## Secure Mode (Ephemeral Keys)
|
|
243
177
|
|
|
244
|
-
|
|
245
|
-
<div>
|
|
246
|
-
<button onClick={sign} disabled={isLoading || !isAvailable}>
|
|
247
|
-
{isLoading ? 'Signing...' : 'Sign Message'}
|
|
248
|
-
</button>
|
|
249
|
-
{signature && <pre>{signature}</pre>}
|
|
250
|
-
</div>
|
|
251
|
-
)
|
|
252
|
-
}
|
|
253
|
-
```
|
|
178
|
+
Secure mode adds an extra layer of security by requiring client-side ephemeral key signatures for all operations:
|
|
254
179
|
|
|
255
|
-
|
|
180
|
+
```typescript
|
|
181
|
+
import { SecureKentuckySignerClient, EphemeralKeyManager } from 'kentucky-signer-viem'
|
|
256
182
|
|
|
257
|
-
|
|
183
|
+
// Create ephemeral key manager
|
|
184
|
+
const keyManager = new EphemeralKeyManager()
|
|
258
185
|
|
|
259
|
-
|
|
186
|
+
// Create secure client
|
|
187
|
+
const secureClient = new SecureKentuckySignerClient({
|
|
188
|
+
baseUrl: 'https://signer.example.com',
|
|
189
|
+
ephemeralKeyManager: keyManager,
|
|
190
|
+
})
|
|
260
191
|
|
|
261
|
-
|
|
192
|
+
// Authenticate with ephemeral key binding
|
|
193
|
+
const session = await authenticateWithPasskey({
|
|
194
|
+
baseUrl: 'https://signer.example.com',
|
|
195
|
+
accountId: 'account_id',
|
|
196
|
+
ephemeralPublicKey: await keyManager.getPublicKey(),
|
|
197
|
+
})
|
|
262
198
|
|
|
263
|
-
|
|
199
|
+
// Create account with secure client
|
|
264
200
|
const account = createKentuckySignerAccount({
|
|
265
|
-
config: {
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
},
|
|
269
|
-
session: AuthSession, // Authenticated session
|
|
270
|
-
defaultChainId?: number, // Default chain ID (default: 1)
|
|
271
|
-
onSessionExpired?: () => Promise<AuthSession>, // Session refresh callback
|
|
201
|
+
config: { baseUrl, accountId },
|
|
202
|
+
session,
|
|
203
|
+
secureClient, // Uses ephemeral key signing
|
|
272
204
|
})
|
|
273
205
|
```
|
|
274
206
|
|
|
275
|
-
|
|
207
|
+
## Two-Factor Authentication
|
|
276
208
|
|
|
277
|
-
|
|
209
|
+
### Setup TOTP (Authenticator App)
|
|
278
210
|
|
|
279
211
|
```typescript
|
|
280
|
-
|
|
281
|
-
baseUrl: string, // Kentucky Signer API URL
|
|
282
|
-
accountId: string, // Account ID to authenticate
|
|
283
|
-
rpId?: string, // WebAuthn Relying Party ID
|
|
284
|
-
allowCredentials?: string[], // Allowed credential IDs
|
|
285
|
-
})
|
|
286
|
-
```
|
|
212
|
+
import { KentuckySignerClient } from 'kentucky-signer-viem'
|
|
287
213
|
|
|
288
|
-
|
|
214
|
+
const client = new KentuckySignerClient({ baseUrl })
|
|
289
215
|
|
|
290
|
-
|
|
216
|
+
// Start TOTP setup - returns QR code URI
|
|
217
|
+
const setup = await client.setupTOTP(token)
|
|
218
|
+
console.log('Scan this QR code:', setup.uri)
|
|
219
|
+
console.log('Or enter manually:', setup.secret)
|
|
291
220
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
baseUrl: string, // Kentucky Signer API URL
|
|
295
|
-
accountId: string, // Account ID to authenticate
|
|
296
|
-
password: string, // Account password
|
|
297
|
-
})
|
|
298
|
-
```
|
|
221
|
+
// Enable TOTP with verification code
|
|
222
|
+
await client.enableTOTP('123456', token)
|
|
299
223
|
|
|
300
|
-
|
|
224
|
+
// Check 2FA status
|
|
225
|
+
const status = await client.get2FAStatus(token)
|
|
226
|
+
// { totp_enabled: true, pin_enabled: false, pin_length: 0 }
|
|
227
|
+
```
|
|
301
228
|
|
|
302
|
-
|
|
229
|
+
### Setup PIN
|
|
303
230
|
|
|
304
231
|
```typescript
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
// Returns: { account_id, addresses: { evm, bitcoin, solana } }
|
|
232
|
+
// Setup 4 or 6 digit PIN
|
|
233
|
+
await client.setupPIN('123456', token)
|
|
234
|
+
|
|
235
|
+
// Disable PIN (requires current PIN)
|
|
236
|
+
await client.disablePIN('123456', token)
|
|
311
237
|
```
|
|
312
238
|
|
|
313
|
-
|
|
239
|
+
### Signing with 2FA
|
|
314
240
|
|
|
315
|
-
|
|
241
|
+
When 2FA is enabled, signing operations will automatically prompt for codes:
|
|
316
242
|
|
|
317
|
-
```
|
|
318
|
-
|
|
319
|
-
'https://signer.example.com',
|
|
320
|
-
'account_id',
|
|
321
|
-
'jwt_token',
|
|
322
|
-
Date.now() + 3600000 // Optional expiration
|
|
323
|
-
)
|
|
324
|
-
```
|
|
243
|
+
```tsx
|
|
244
|
+
import { useKentuckySigner } from 'kentucky-signer-viem/react'
|
|
325
245
|
|
|
326
|
-
|
|
246
|
+
function App() {
|
|
247
|
+
const { twoFactorPrompt, submit2FA, cancel2FA } = useKentuckySigner()
|
|
248
|
+
|
|
249
|
+
// The 2FA prompt appears automatically when signing requires it
|
|
250
|
+
if (twoFactorPrompt.isVisible) {
|
|
251
|
+
return (
|
|
252
|
+
<TwoFactorModal
|
|
253
|
+
totpRequired={twoFactorPrompt.totpRequired}
|
|
254
|
+
pinRequired={twoFactorPrompt.pinRequired}
|
|
255
|
+
pinLength={twoFactorPrompt.pinLength}
|
|
256
|
+
onSubmit={(codes) => submit2FA(codes)}
|
|
257
|
+
onCancel={() => cancel2FA()}
|
|
258
|
+
/>
|
|
259
|
+
)
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
return <YourApp />
|
|
263
|
+
}
|
|
264
|
+
```
|
|
327
265
|
|
|
328
|
-
|
|
266
|
+
## Guardian Recovery
|
|
329
267
|
|
|
330
|
-
|
|
268
|
+
Set up trusted guardians for account recovery:
|
|
331
269
|
|
|
332
270
|
```typescript
|
|
333
|
-
const client = new KentuckySignerClient({ baseUrl
|
|
271
|
+
const client = new KentuckySignerClient({ baseUrl })
|
|
272
|
+
|
|
273
|
+
// Add a guardian (requires WebAuthn attestation from guardian's device)
|
|
274
|
+
const { guardian_index, guardian_count } = await client.addGuardian({
|
|
275
|
+
attestation_object: guardianAttestationBase64url,
|
|
276
|
+
label: 'My Friend',
|
|
277
|
+
}, token)
|
|
278
|
+
|
|
279
|
+
// List guardians
|
|
280
|
+
const { guardians } = await client.getGuardians(token)
|
|
281
|
+
// guardians: [{ index: 1, label: 'My Friend' }, ...]
|
|
282
|
+
|
|
283
|
+
// Initiate recovery (when locked out - register new passkey first)
|
|
284
|
+
const recovery = await client.initiateRecovery(
|
|
285
|
+
accountId,
|
|
286
|
+
newPasskeyAttestationObject,
|
|
287
|
+
'New Owner Passkey'
|
|
288
|
+
)
|
|
289
|
+
// Returns: { challenges, guardian_count, threshold, timelock_seconds }
|
|
290
|
+
|
|
291
|
+
// Guardian signs their challenge with their passkey
|
|
292
|
+
await client.verifyGuardian({
|
|
293
|
+
account_id: accountId,
|
|
294
|
+
guardian_index: 1,
|
|
295
|
+
authenticator_data: authDataBase64url,
|
|
296
|
+
client_data_json: clientDataBase64url,
|
|
297
|
+
signature: signatureBase64url,
|
|
298
|
+
})
|
|
334
299
|
|
|
335
|
-
//
|
|
336
|
-
const
|
|
300
|
+
// Check recovery status
|
|
301
|
+
const status = await client.getRecoveryStatus(accountId)
|
|
302
|
+
// { verified_count, threshold, can_complete, timelock_remaining }
|
|
337
303
|
|
|
338
|
-
//
|
|
339
|
-
|
|
304
|
+
// Complete recovery after threshold met and timelock expired
|
|
305
|
+
await client.completeRecovery(accountId)
|
|
306
|
+
```
|
|
340
307
|
|
|
341
|
-
|
|
342
|
-
const signature = await client.signEvmTransaction(
|
|
343
|
-
{ tx_hash: '0x...', chain_id: 1 },
|
|
344
|
-
jwtToken
|
|
345
|
-
)
|
|
308
|
+
## API Reference
|
|
346
309
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
310
|
+
### Core Functions
|
|
311
|
+
|
|
312
|
+
| Function | Description |
|
|
313
|
+
|----------|-------------|
|
|
314
|
+
| `createKentuckySignerAccount(options)` | Create a Viem-compatible account |
|
|
315
|
+
| `createServerAccount(...)` | Create account with JWT token (Node.js) |
|
|
316
|
+
| `authenticateWithPasskey(options)` | Authenticate using WebAuthn |
|
|
317
|
+
| `authenticateWithPassword(options)` | Authenticate using password |
|
|
318
|
+
| `createAccountWithPassword(options)` | Create new account with password |
|
|
319
|
+
| `authenticateWithToken(...)` | Create session from JWT token |
|
|
350
320
|
|
|
351
321
|
### React Hooks
|
|
352
322
|
|
|
353
323
|
| Hook | Description |
|
|
354
324
|
|------|-------------|
|
|
355
|
-
| `useKentuckySigner()` | Access auth state and
|
|
325
|
+
| `useKentuckySigner()` | Access auth state, actions, and 2FA |
|
|
356
326
|
| `useKentuckySignerAccount()` | Get the current account |
|
|
357
327
|
| `useWalletClient(options)` | Create a Viem WalletClient |
|
|
358
328
|
| `usePasskeyAuth()` | Authentication flow with loading state |
|
|
@@ -361,42 +331,43 @@ const info = await client.getAccountInfo(accountId, jwtToken)
|
|
|
361
331
|
| `useIsReady()` | Check if signer is ready |
|
|
362
332
|
| `useAddress()` | Get connected address |
|
|
363
333
|
|
|
364
|
-
###
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
-
|
|
387
|
-
-
|
|
388
|
-
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
334
|
+
### Client Methods
|
|
335
|
+
|
|
336
|
+
#### Authentication
|
|
337
|
+
- `getChallenge(accountId)` - Get WebAuthn challenge
|
|
338
|
+
- `authenticatePasskey(accountId, credential, ephemeralPublicKey?)` - Authenticate with passkey
|
|
339
|
+
- `authenticatePassword(request)` - Authenticate with password (`{ account_id, password }`)
|
|
340
|
+
- `refreshToken(token)` - Refresh JWT token
|
|
341
|
+
- `logout(token)` - Invalidate session
|
|
342
|
+
|
|
343
|
+
#### Signing
|
|
344
|
+
- `signEvmTransaction(request, token)` - Sign EVM transaction hash
|
|
345
|
+
- `signEvmTransactionWith2FA(request, token)` - Sign with 2FA codes
|
|
346
|
+
|
|
347
|
+
#### Account Management
|
|
348
|
+
- `getAccountInfo(accountId, token)` - Get account info
|
|
349
|
+
- `getAccountInfoExtended(accountId, token)` - Get account info with auth config
|
|
350
|
+
- `addPassword(accountId, request, token)` - Add password auth
|
|
351
|
+
- `addPasskey(accountId, request, token)` - Add passkey
|
|
352
|
+
- `removePasskey(accountId, passkeyIndex, token)` - Remove passkey by index
|
|
353
|
+
|
|
354
|
+
#### Two-Factor Authentication
|
|
355
|
+
- `get2FAStatus(token)` - Get 2FA status
|
|
356
|
+
- `setupTOTP(token)` - Start TOTP setup
|
|
357
|
+
- `enableTOTP(code, token)` - Enable TOTP
|
|
358
|
+
- `disableTOTP(code, token)` - Disable TOTP
|
|
359
|
+
- `setupPIN(pin, token)` - Setup PIN
|
|
360
|
+
- `disablePIN(pin, token)` - Disable PIN
|
|
361
|
+
|
|
362
|
+
#### Guardian Recovery
|
|
363
|
+
- `addGuardian(request, token)` - Add guardian passkey
|
|
364
|
+
- `removeGuardian(guardianIndex, token)` - Remove guardian
|
|
365
|
+
- `getGuardians(token)` - List guardians
|
|
366
|
+
- `initiateRecovery(accountId, attestationObject, label?)` - Start recovery
|
|
367
|
+
- `verifyGuardian(request)` - Submit guardian signature
|
|
368
|
+
- `getRecoveryStatus(accountId)` - Check recovery status
|
|
369
|
+
- `completeRecovery(accountId)` - Complete recovery
|
|
370
|
+
- `cancelRecovery(token)` - Cancel recovery (owner only)
|
|
400
371
|
|
|
401
372
|
## Error Handling
|
|
402
373
|
|
|
@@ -407,21 +378,38 @@ try {
|
|
|
407
378
|
await authenticate(accountId)
|
|
408
379
|
} catch (error) {
|
|
409
380
|
if (error instanceof KentuckySignerError) {
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
381
|
+
switch (error.code) {
|
|
382
|
+
case 'WEBAUTHN_NOT_AVAILABLE':
|
|
383
|
+
// WebAuthn not supported
|
|
384
|
+
break
|
|
385
|
+
case 'USER_CANCELLED':
|
|
386
|
+
// User cancelled authentication
|
|
387
|
+
break
|
|
388
|
+
case 'SESSION_EXPIRED':
|
|
389
|
+
// JWT token expired
|
|
390
|
+
break
|
|
391
|
+
case '2FA_REQUIRED':
|
|
392
|
+
// 2FA verification needed
|
|
393
|
+
break
|
|
394
|
+
case '2FA_CANCELLED':
|
|
395
|
+
// User cancelled 2FA input
|
|
396
|
+
break
|
|
397
|
+
// ... handle other codes
|
|
398
|
+
}
|
|
413
399
|
}
|
|
414
400
|
}
|
|
415
401
|
```
|
|
416
402
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
-
|
|
422
|
-
-
|
|
423
|
-
-
|
|
424
|
-
-
|
|
403
|
+
## Documentation
|
|
404
|
+
|
|
405
|
+
For detailed documentation, see the [docs](./docs) folder:
|
|
406
|
+
|
|
407
|
+
- [Authentication](./docs/authentication.md) - Passkey, password, and token auth
|
|
408
|
+
- [Secure Mode](./docs/secure-mode.md) - Ephemeral key signing
|
|
409
|
+
- [Two-Factor Authentication](./docs/two-factor-auth.md) - TOTP and PIN setup
|
|
410
|
+
- [Guardian Recovery](./docs/guardian-recovery.md) - Social recovery setup
|
|
411
|
+
- [React Integration](./docs/react-integration.md) - Hooks and context usage
|
|
412
|
+
- [API Reference](./docs/api-reference.md) - Complete API documentation
|
|
425
413
|
|
|
426
414
|
## License
|
|
427
415
|
|