@rockerone/xprnkit 0.3.2 → 0.3.3
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 +141 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -519,6 +519,147 @@ function ExistingComponent() {
|
|
|
519
519
|
}
|
|
520
520
|
```
|
|
521
521
|
|
|
522
|
+
## Authentication Persistence and SSR
|
|
523
|
+
|
|
524
|
+
### Overview
|
|
525
|
+
|
|
526
|
+
XPRNKit automatically restores **wallet sessions** via the `restoreSession` config option, but **authentication data** (tokens, permissions, etc.) is **not automatically persisted** to give you full control over your security model.
|
|
527
|
+
|
|
528
|
+
This design is intentional:
|
|
529
|
+
- ✅ **Wallet Connection** = Handled by XPRNKit (via Proton Web SDK)
|
|
530
|
+
- ❌ **Authentication State** = Your responsibility (localStorage, cookies, server sessions, etc.)
|
|
531
|
+
|
|
532
|
+
### Storage Helper Utilities
|
|
533
|
+
|
|
534
|
+
XPRNKit provides optional helper utilities:
|
|
535
|
+
|
|
536
|
+
```typescript
|
|
537
|
+
import { authStorage } from 'xprnkit';
|
|
538
|
+
|
|
539
|
+
// Save authentication data
|
|
540
|
+
authStorage.save('user@proton', {
|
|
541
|
+
actor: 'user@proton',
|
|
542
|
+
publicKey: 'PUB_K1_...',
|
|
543
|
+
data: { token: 'jwt-token' },
|
|
544
|
+
expiresAt: Date.now() + 86400000,
|
|
545
|
+
});
|
|
546
|
+
|
|
547
|
+
// Load/clear/list
|
|
548
|
+
const auth = authStorage.load('user@proton');
|
|
549
|
+
authStorage.clear('user@proton');
|
|
550
|
+
authStorage.clearAll();
|
|
551
|
+
const actors = authStorage.listActors();
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
### Implementation Patterns
|
|
555
|
+
|
|
556
|
+
#### Pattern 1: Client-Side (localStorage)
|
|
557
|
+
|
|
558
|
+
**Use Case:** Simple apps, prototypes
|
|
559
|
+
|
|
560
|
+
```typescript
|
|
561
|
+
import { useXPRN, authStorage } from 'xprnkit';
|
|
562
|
+
|
|
563
|
+
function MyApp() {
|
|
564
|
+
const { session, authenticate } = useXPRN();
|
|
565
|
+
|
|
566
|
+
const handleAuth = () => {
|
|
567
|
+
authenticate(
|
|
568
|
+
(authData) => {
|
|
569
|
+
authStorage.save(session.auth.actor.toString(), {
|
|
570
|
+
actor: session.auth.actor.toString(),
|
|
571
|
+
publicKey: session.publicKey.toString(),
|
|
572
|
+
data: authData,
|
|
573
|
+
expiresAt: Date.now() + 86400000,
|
|
574
|
+
});
|
|
575
|
+
},
|
|
576
|
+
(error) => console.error(error)
|
|
577
|
+
);
|
|
578
|
+
};
|
|
579
|
+
}
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
#### Pattern 2: SSR with Cookies (Next.js)
|
|
583
|
+
|
|
584
|
+
**Use Case:** Next.js apps, production
|
|
585
|
+
|
|
586
|
+
**Client:**
|
|
587
|
+
```typescript
|
|
588
|
+
'use client';
|
|
589
|
+
import { useXPRN } from 'xprnkit';
|
|
590
|
+
|
|
591
|
+
function MyApp() {
|
|
592
|
+
const { session, authenticate } = useXPRN();
|
|
593
|
+
|
|
594
|
+
const handleAuth = () => {
|
|
595
|
+
authenticate(
|
|
596
|
+
async (authData) => {
|
|
597
|
+
await fetch('/api/auth/session', {
|
|
598
|
+
method: 'POST',
|
|
599
|
+
body: JSON.stringify({ actor: session.auth.actor, authData }),
|
|
600
|
+
});
|
|
601
|
+
},
|
|
602
|
+
(error) => console.error(error)
|
|
603
|
+
);
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
```
|
|
607
|
+
|
|
608
|
+
**Server:**
|
|
609
|
+
```typescript
|
|
610
|
+
// app/api/auth/session/route.ts
|
|
611
|
+
import { NextResponse } from 'next/server';
|
|
612
|
+
|
|
613
|
+
export async function POST(request: Request) {
|
|
614
|
+
const body = await request.json();
|
|
615
|
+
const response = NextResponse.json({ success: true });
|
|
616
|
+
|
|
617
|
+
response.cookies.set('xprn_session', createToken(body), {
|
|
618
|
+
httpOnly: true,
|
|
619
|
+
secure: process.env.NODE_ENV === 'production',
|
|
620
|
+
maxAge: 86400,
|
|
621
|
+
});
|
|
622
|
+
|
|
623
|
+
return response;
|
|
624
|
+
}
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
#### Pattern 3: Server Sessions (Redis/DB)
|
|
628
|
+
|
|
629
|
+
**Use Case:** Scalable production apps
|
|
630
|
+
|
|
631
|
+
```typescript
|
|
632
|
+
// app/api/session/create/route.ts
|
|
633
|
+
import { redis } from '@/lib/redis';
|
|
634
|
+
import { randomUUID } from 'crypto';
|
|
635
|
+
|
|
636
|
+
export async function POST(request: Request) {
|
|
637
|
+
const body = await request.json();
|
|
638
|
+
const sessionId = randomUUID();
|
|
639
|
+
|
|
640
|
+
await redis.setex(\`session:\${sessionId}\`, 86400, JSON.stringify(body));
|
|
641
|
+
|
|
642
|
+
const response = NextResponse.json({ success: true });
|
|
643
|
+
response.cookies.set('session_id', sessionId, { httpOnly: true });
|
|
644
|
+
return response;
|
|
645
|
+
}
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
### Comparison
|
|
649
|
+
|
|
650
|
+
| Approach | Security | SSR | Best For |
|
|
651
|
+
|----------|----------|-----|----------|
|
|
652
|
+
| **localStorage** | Medium | ❌ | Client apps |
|
|
653
|
+
| **Cookies** | High | ✅ | SSR apps |
|
|
654
|
+
| **Server Sessions** | Very High | ✅ | Production |
|
|
655
|
+
|
|
656
|
+
### Full Examples
|
|
657
|
+
|
|
658
|
+
See the `examples/` directory for complete implementations:
|
|
659
|
+
- `auth-localstorage.example.tsx` - Client-side with localStorage
|
|
660
|
+
- `auth-cookies-ssr.example.tsx` - SSR with httpOnly cookies
|
|
661
|
+
- `auth-server-session.example.tsx` - Server sessions with Redis/PostgreSQL
|
|
662
|
+
|
|
522
663
|
# Components Documentation
|
|
523
664
|
|
|
524
665
|
# XRPNContainer
|