@stacknet/userutils 0.2.55 → 0.2.56
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 +0 -150
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -164,30 +164,6 @@ export function Header() {
|
|
|
164
164
|
}
|
|
165
165
|
```
|
|
166
166
|
|
|
167
|
-
## Auth Flow
|
|
168
|
-
|
|
169
|
-
```
|
|
170
|
-
1. User clicks wallet button in ConnectWidget
|
|
171
|
-
2. useStackAuth calls StackNet: POST /api/v2/stacks/{stackId}/auth/web3/challenge
|
|
172
|
-
3. User signs the challenge message with their wallet
|
|
173
|
-
4. Client POSTs signature to your /api/auth/callback
|
|
174
|
-
5. Server verifies with StackNet, re-signs JWT with AUTH_SECRET
|
|
175
|
-
6. Server sets three cookies:
|
|
176
|
-
- stackauth_jwt (HttpOnly) — server-side session validation
|
|
177
|
-
- stackauth_session (readable) — client-side UI state
|
|
178
|
-
- __csrf — CSRF protection token
|
|
179
|
-
7. useSession() reads stackauth_session cookie → isAuthenticated: true
|
|
180
|
-
8. UI updates to show authenticated state
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
## Cookies
|
|
184
|
-
|
|
185
|
-
| Cookie | HttpOnly | Purpose |
|
|
186
|
-
|--------|----------|---------|
|
|
187
|
-
| `stackauth_jwt` | Yes | Server-side JWT (15 min, auto-refreshes) |
|
|
188
|
-
| `stackauth_session` | No | Public session for UI (userId, address, chain, expiresAt) |
|
|
189
|
-
| `__csrf` | No | CSRF double-submit token |
|
|
190
|
-
|
|
191
167
|
The JWT auto-refreshes when `/api/auth/session` is called and the token is within 5 minutes of expiry.
|
|
192
168
|
|
|
193
169
|
## Hooks
|
|
@@ -229,50 +205,6 @@ const {
|
|
|
229
205
|
})
|
|
230
206
|
```
|
|
231
207
|
|
|
232
|
-
### useAuthBridge(opts?)
|
|
233
|
-
|
|
234
|
-
Cross-domain auth state detection via iframe.
|
|
235
|
-
|
|
236
|
-
```typescript
|
|
237
|
-
const bridge = useAuthBridge()
|
|
238
|
-
|
|
239
|
-
// bridge.ready — iframe loaded
|
|
240
|
-
// bridge.known — previous auth found
|
|
241
|
-
// bridge.identity — { address, chain, method, stackCount }
|
|
242
|
-
// bridge.resolvedStackId — last stackId used on this domain
|
|
243
|
-
// bridge.reportConnected({ address, chain, method, stackId })
|
|
244
|
-
// bridge.reportDisconnected({ address, chain, stackId })
|
|
245
|
-
```
|
|
246
|
-
|
|
247
|
-
The bridge never transmits JWTs — only public metadata (address, chain, method, stackId).
|
|
248
|
-
|
|
249
|
-
### useWeb3Wallet()
|
|
250
|
-
|
|
251
|
-
Low-level wallet connection. Used internally by useStackAuth.
|
|
252
|
-
|
|
253
|
-
```typescript
|
|
254
|
-
const { wallet, connectSolana, connectEVM, signMessage, disconnect } = useWeb3Wallet()
|
|
255
|
-
```
|
|
256
|
-
|
|
257
|
-
### useCSRFToken(cookieName?, headerName?)
|
|
258
|
-
|
|
259
|
-
Reads CSRF token for mutation requests.
|
|
260
|
-
|
|
261
|
-
```typescript
|
|
262
|
-
const { token, headers } = useCSRFToken()
|
|
263
|
-
// headers = { 'x-csrf-token': '...' }
|
|
264
|
-
```
|
|
265
|
-
|
|
266
|
-
### Billing hooks
|
|
267
|
-
|
|
268
|
-
```typescript
|
|
269
|
-
const { plans, loading } = usePlans(apiBaseUrl?)
|
|
270
|
-
const { subscription, subscribe, cancel } = useSubscription(apiBaseUrl?)
|
|
271
|
-
const { usage, refresh } = useUsage(apiBaseUrl?)
|
|
272
|
-
const { purchase, verifySession } = usePrepaidCheckout(apiBaseUrl?)
|
|
273
|
-
const { records, refresh } = useBillingHistory(apiBaseUrl?, { limit, offset })
|
|
274
|
-
```
|
|
275
|
-
|
|
276
208
|
## Components
|
|
277
209
|
|
|
278
210
|
### ConnectWidget
|
|
@@ -300,88 +232,6 @@ React context provider. Wrap your app with this.
|
|
|
300
232
|
</UserUtilsProvider>
|
|
301
233
|
```
|
|
302
234
|
|
|
303
|
-
## Server Exports
|
|
304
|
-
|
|
305
|
-
```typescript
|
|
306
|
-
import {
|
|
307
|
-
// Auth route handlers
|
|
308
|
-
createAuthCallback, // POST /api/auth/callback
|
|
309
|
-
createSessionHandler, // GET /api/auth/session
|
|
310
|
-
createLogoutHandler, // POST /api/auth/logout
|
|
311
|
-
createOTPHandler, // POST /api/auth/otp
|
|
312
|
-
|
|
313
|
-
// Billing proxy
|
|
314
|
-
createBillingProxy, // All billing routes
|
|
315
|
-
createWebhookHandler, // Stripe webhooks
|
|
316
|
-
|
|
317
|
-
// JWT utilities
|
|
318
|
-
signJWT,
|
|
319
|
-
verifyJWT,
|
|
320
|
-
verifyJWTSignature,
|
|
321
|
-
decodeJWTPayload,
|
|
322
|
-
maybeRefreshJWT,
|
|
323
|
-
extractJwt,
|
|
324
|
-
|
|
325
|
-
// Security
|
|
326
|
-
createCSRFProtection,
|
|
327
|
-
securityHeaders,
|
|
328
|
-
withSecurityHeaders,
|
|
329
|
-
nextSecurityHeaders,
|
|
330
|
-
extractIP,
|
|
331
|
-
generateToken,
|
|
332
|
-
|
|
333
|
-
// StackNet proxy
|
|
334
|
-
buildStackNetHeaders,
|
|
335
|
-
resignForStackNet,
|
|
336
|
-
|
|
337
|
-
// Rate limiting
|
|
338
|
-
createInMemoryRateLimiter,
|
|
339
|
-
createInMemoryReplayStore,
|
|
340
|
-
} from '@stacknet/userutils/server'
|
|
341
|
-
```
|
|
342
|
-
|
|
343
|
-
## Server Config
|
|
344
|
-
|
|
345
|
-
```typescript
|
|
346
|
-
interface ServerConfig {
|
|
347
|
-
authSecret: string // HMAC-SHA256 secret for signing JWTs
|
|
348
|
-
stacknetUrl: string // https://stacknet.magma-rpc.com
|
|
349
|
-
stackId: string // Your stack ID
|
|
350
|
-
stacknetJwtSecret?: string // For re-signing to StackNet (defaults to authSecret)
|
|
351
|
-
cookieDomain?: string // For subdomain sharing (e.g. '.geoff.ai')
|
|
352
|
-
secureCookies?: boolean // Secure flag on cookies (default: true)
|
|
353
|
-
sessionMaxAge?: number // Session duration in seconds (default: 604800 = 7 days)
|
|
354
|
-
jwtExpiry?: number // JWT expiry in seconds (default: 900 = 15 min)
|
|
355
|
-
}
|
|
356
|
-
```
|
|
357
|
-
|
|
358
|
-
## Auth Bridge
|
|
359
|
-
|
|
360
|
-
The auth bridge enables cross-domain session detection via an invisible iframe loaded from `https://stacknet.magma-rpc.com/auth/bridge`.
|
|
361
|
-
|
|
362
|
-
When a user authenticates on one stack app, the bridge stores their public identity (address, chain, method). When they visit another stack app, `useAuthBridge()` detects the known identity and can auto-trigger wallet connection if `autoConnect: true`.
|
|
363
|
-
|
|
364
|
-
The bridge uses postMessage with the `stacknet-auth-bridge` protocol. It never stores or transmits JWTs.
|
|
365
|
-
|
|
366
|
-
## Proxying to StackNet
|
|
367
|
-
|
|
368
|
-
If your app needs to call StackNet APIs on behalf of the user, store the original StackNet JWT in a separate cookie during callback:
|
|
369
|
-
|
|
370
|
-
```typescript
|
|
371
|
-
// In your custom /api/auth/callback handler:
|
|
372
|
-
const originalJwt = sessionData.jwt
|
|
373
|
-
headers.append('Set-Cookie',
|
|
374
|
-
`stacknet_jwt=${originalJwt}; Path=/; HttpOnly; SameSite=Lax; Max-Age=604800${secureSuffix}`
|
|
375
|
-
)
|
|
376
|
-
|
|
377
|
-
// In your proxy routes:
|
|
378
|
-
import { extractJwt } from '@stacknet/userutils/server'
|
|
379
|
-
|
|
380
|
-
const jwt = extractJwt(request) // reads stackauth_jwt cookie
|
|
381
|
-
const headers = buildStackNetHeaders(jwt, process.env.STACKNET_JWT_SECRET!)
|
|
382
|
-
await fetch(`https://stacknet.magma-rpc.com/api/...`, { headers })
|
|
383
|
-
```
|
|
384
|
-
|
|
385
235
|
## Security
|
|
386
236
|
|
|
387
237
|
- **HttpOnly cookies** prevent XSS token theft
|