@passkeyme/auth 1.0.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/CHANGELOG.md +93 -0
- package/LICENSE +21 -0
- package/README.md +598 -0
- package/dist/index.esm.js +5660 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/index.js +5680 -0
- package/dist/index.js.map +1 -0
- package/dist/index.umd.js +5686 -0
- package/dist/index.umd.js.map +1 -0
- package/dist/src/api-client.d.ts +56 -0
- package/dist/src/api-client.d.ts.map +1 -0
- package/dist/src/errors.d.ts +61 -0
- package/dist/src/errors.d.ts.map +1 -0
- package/dist/src/http-interceptors.d.ts +28 -0
- package/dist/src/http-interceptors.d.ts.map +1 -0
- package/dist/src/index.d.ts +49 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/passkeyme-auth.d.ts +157 -0
- package/dist/src/passkeyme-auth.d.ts.map +1 -0
- package/dist/src/platform/PasskeySDK.d.ts +112 -0
- package/dist/src/platform/PasskeySDK.d.ts.map +1 -0
- package/dist/src/platform/ReactNativePasskeySDK.d.ts +42 -0
- package/dist/src/platform/ReactNativePasskeySDK.d.ts.map +1 -0
- package/dist/src/platform/WebPasskeySDK.d.ts +25 -0
- package/dist/src/platform/WebPasskeySDK.d.ts.map +1 -0
- package/dist/src/platform/index.d.ts +8 -0
- package/dist/src/platform/index.d.ts.map +1 -0
- package/dist/src/storage/BrowserStorageProvider.d.ts +14 -0
- package/dist/src/storage/BrowserStorageProvider.d.ts.map +1 -0
- package/dist/src/storage/StorageProvider.d.ts +32 -0
- package/dist/src/storage/StorageProvider.d.ts.map +1 -0
- package/dist/src/storage/index.d.ts +6 -0
- package/dist/src/storage/index.d.ts.map +1 -0
- package/dist/src/token-storage.d.ts +46 -0
- package/dist/src/token-storage.d.ts.map +1 -0
- package/dist/src/types.d.ts +217 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/utils/logger.d.ts +23 -0
- package/dist/src/utils/logger.d.ts.map +1 -0
- package/dist/test/platform/PasskeySDK.test.d.ts +5 -0
- package/dist/test/platform/PasskeySDK.test.d.ts.map +1 -0
- package/dist/test/setup.d.ts +13 -0
- package/dist/test/setup.d.ts.map +1 -0
- package/dist/test/storage/BrowserStorageProvider.test.d.ts +5 -0
- package/dist/test/storage/BrowserStorageProvider.test.d.ts.map +1 -0
- package/package.json +72 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
# Changelog
|
|
9
|
+
|
|
10
|
+
All notable changes to this project will be documented in this file.
|
|
11
|
+
|
|
12
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
13
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
14
|
+
|
|
15
|
+
## [1.0.0] - 2025-07-12
|
|
16
|
+
|
|
17
|
+
### 🎉 First Stable Release
|
|
18
|
+
|
|
19
|
+
This marks the first stable release of the PasskeyMe Authentication SDK with enterprise-grade quality and comprehensive feature set.
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
- **Professional Logging System**: Environment-aware structured logging with configurable levels
|
|
24
|
+
- **Enterprise-Grade Build System**: Clean TypeScript compilation with multiple output formats (CommonJS, ESM, UMD)
|
|
25
|
+
- **Comprehensive Test Suite**: 30/30 tests passing with full coverage of core functionality
|
|
26
|
+
- **Code Quality Standards**: Prettier formatting, ESLint linting, and consistent code style
|
|
27
|
+
- **Production-Ready Infrastructure**: Optimized package configuration and publishing setup
|
|
28
|
+
- **TypeScript Documentation**: Comprehensive type definitions and IntelliSense support
|
|
29
|
+
- **Advanced Configuration**: Custom token storage patterns and HTTP interceptor examples
|
|
30
|
+
- **Error Handling**: Robust error handling patterns with custom error types
|
|
31
|
+
- **API Integration**: Comprehensive distribution setup and client integration patterns
|
|
32
|
+
|
|
33
|
+
### Enhanced
|
|
34
|
+
|
|
35
|
+
- **Bundle Optimization**: Minimal dependencies and optimized output sizes
|
|
36
|
+
- **Developer Experience**: Improved debugging capabilities and development workflow
|
|
37
|
+
- **Documentation**: Complete API reference and usage examples
|
|
38
|
+
- **Security**: Enhanced token management and secure storage patterns
|
|
39
|
+
|
|
40
|
+
### Fixed
|
|
41
|
+
|
|
42
|
+
- **Memory Leaks**: Resolved potential memory issues in token management
|
|
43
|
+
- **Type Safety**: Improved TypeScript strict mode compliance
|
|
44
|
+
- **Error Handling**: Comprehensive error boundary implementation
|
|
45
|
+
|
|
46
|
+
## [Unreleased]
|
|
47
|
+
- .npmignore for cleaner package publishing
|
|
48
|
+
|
|
49
|
+
### Enhanced
|
|
50
|
+
|
|
51
|
+
- README with detailed TypeScript usage patterns
|
|
52
|
+
- API documentation with complete type definitions
|
|
53
|
+
- Framework integration examples
|
|
54
|
+
|
|
55
|
+
## [0.2.0-beta.2] - 2024-12-07
|
|
56
|
+
|
|
57
|
+
### Fixed
|
|
58
|
+
|
|
59
|
+
- WebSDK method name compatibility issues
|
|
60
|
+
- Credential serialization for API calls
|
|
61
|
+
- Authentication flow improvements
|
|
62
|
+
|
|
63
|
+
### Changed
|
|
64
|
+
|
|
65
|
+
- Improved error handling
|
|
66
|
+
- Enhanced debugging capabilities
|
|
67
|
+
|
|
68
|
+
## [0.2.0-beta.1] - 2024-11-15
|
|
69
|
+
|
|
70
|
+
### Added
|
|
71
|
+
|
|
72
|
+
- Initial beta release
|
|
73
|
+
- Core authentication functionality
|
|
74
|
+
- OAuth integration (Google, GitHub)
|
|
75
|
+
- Passkey (WebAuthn) support
|
|
76
|
+
- Username/password authentication
|
|
77
|
+
- Hosted authentication pages
|
|
78
|
+
- JWT token management
|
|
79
|
+
- Auto-refresh token handling
|
|
80
|
+
- TypeScript support
|
|
81
|
+
|
|
82
|
+
### Features
|
|
83
|
+
|
|
84
|
+
- Multiple authentication methods
|
|
85
|
+
- Hosted authentication pages
|
|
86
|
+
- Automatic token management
|
|
87
|
+
- Privacy-first design
|
|
88
|
+
- Self-hosted option
|
|
89
|
+
- Lightweight implementation
|
|
90
|
+
|
|
91
|
+
[Unreleased]: https://github.com/passkeyme/sdk/compare/v0.2.0-beta.2...HEAD
|
|
92
|
+
[0.2.0-beta.2]: https://github.com/passkeyme/sdk/compare/v0.2.0-beta.1...v0.2.0-beta.2
|
|
93
|
+
[0.2.0-beta.1]: https://github.com/passkeyme/sdk/releases/tag/v0.2.0-beta.1
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 PasskeyMe
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,598 @@
|
|
|
1
|
+
# @passkeyme/auth
|
|
2
|
+
|
|
3
|
+
A simple, powerful authentication SDK that makes authentication easier than Firebase Auth.
|
|
4
|
+
|
|
5
|
+
## 🚀 Features
|
|
6
|
+
|
|
7
|
+
- **🔐 Multiple Auth Methods**: OAuth (Google, GitHub), Passkeys (WebAuthn), Username/Password
|
|
8
|
+
- **� Hosted Authentication**: Secure, pre-built auth pages - no UI to build
|
|
9
|
+
- **🔄 Automatic Token Management**: Auto-refresh, HTTP interceptors
|
|
10
|
+
- **🏠 Privacy-First**: Self-hosted option, no vendor lock-in
|
|
11
|
+
- **📱 Modern**: Built-in passkey support, TypeScript-first
|
|
12
|
+
- **⚡ Lightweight**: Pure JavaScript, no heavy dependencies
|
|
13
|
+
|
|
14
|
+
## 📦 Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @passkeyme/auth
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## 🔧 Quick Start
|
|
21
|
+
|
|
22
|
+
### 1. Initialize the SDK
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
import { PasskeymeAuth } from "@passkeyme/auth";
|
|
26
|
+
|
|
27
|
+
const auth = new PasskeymeAuth({
|
|
28
|
+
appId: "your-passkeyme-app-id",
|
|
29
|
+
redirectUri: "http://localhost:3000/auth/callback",
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// Initialize on app start
|
|
33
|
+
await auth.init();
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### 2. Choose Your Authentication Approach
|
|
37
|
+
|
|
38
|
+
#### **Approach 1: Hosted Auth Pages** ✨ (Recommended)
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
// Redirects to your branded hosted login page
|
|
42
|
+
// User sees all available login methods (OAuth, Passkey, Username/Password)
|
|
43
|
+
auth.redirectToLogin();
|
|
44
|
+
|
|
45
|
+
// With options
|
|
46
|
+
auth.redirectToLogin({
|
|
47
|
+
authMethod: "passkey", // Pre-select passkey method
|
|
48
|
+
state: "custom-state", // Custom state for callback
|
|
49
|
+
});
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
#### **Approach 2: Direct OAuth** ⚡
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
// Skip hosted page, go directly to OAuth provider
|
|
56
|
+
auth.redirectToOAuth("google");
|
|
57
|
+
auth.redirectToOAuth("github");
|
|
58
|
+
auth.redirectToOAuth("facebook");
|
|
59
|
+
|
|
60
|
+
// With custom redirect URI
|
|
61
|
+
auth.redirectToOAuth("google", "http://localhost:3000/custom/callback");
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
#### **The Key Difference:**
|
|
65
|
+
|
|
66
|
+
- `redirectToLogin()` → Shows your branded page with all auth options
|
|
67
|
+
- `redirectToOAuth('google')` → Goes directly to Google OAuth (skips hosted page)
|
|
68
|
+
|
|
69
|
+
#### Direct OAuth Provider
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
// Skip login page, go directly to OAuth provider
|
|
73
|
+
auth.redirectToOAuth("google");
|
|
74
|
+
auth.redirectToOAuth("github");
|
|
75
|
+
auth.redirectToOAuth("facebook");
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### 3. Handle Authentication Callback
|
|
79
|
+
|
|
80
|
+
On your callback page (`/auth/callback`):
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
// This handles the authentication return and gets the user
|
|
84
|
+
const user = await auth.handleAuthCallback();
|
|
85
|
+
|
|
86
|
+
if (user) {
|
|
87
|
+
// Redirect to your app
|
|
88
|
+
window.location.href = "/dashboard";
|
|
89
|
+
} else {
|
|
90
|
+
// Handle auth failure
|
|
91
|
+
window.location.href = "/login?error=auth_failed";
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### 4. Check Authentication Status
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
// Check if user is logged in
|
|
99
|
+
const user = auth.getCurrentUser();
|
|
100
|
+
|
|
101
|
+
if (user) {
|
|
102
|
+
console.log("Logged in as:", user.email);
|
|
103
|
+
} else {
|
|
104
|
+
console.log("Not logged in");
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Or check auth state
|
|
108
|
+
console.log("Auth state:", auth.state);
|
|
109
|
+
|
|
110
|
+
// Check on page load
|
|
111
|
+
await auth.init(); // This will restore session if available
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### 5. Logout
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
await auth.logout();
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## 🔗 HTTP Client Integration
|
|
121
|
+
|
|
122
|
+
Automatically add auth headers to your API calls:
|
|
123
|
+
|
|
124
|
+
### With Axios
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
import axios from "axios";
|
|
128
|
+
import { setupHttpInterceptor } from "@passkeyme/auth";
|
|
129
|
+
|
|
130
|
+
const apiClient = axios.create({
|
|
131
|
+
baseURL: "https://your-api.com",
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// Setup automatic token management
|
|
135
|
+
const cleanup = setupHttpInterceptor(auth, apiClient);
|
|
136
|
+
|
|
137
|
+
// Now all requests automatically include auth headers
|
|
138
|
+
const response = await apiClient.get("/protected-data");
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### With Fetch
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
import { createAuthenticatedFetch } from "@passkeyme/auth";
|
|
145
|
+
|
|
146
|
+
const authenticatedFetch = createAuthenticatedFetch(auth);
|
|
147
|
+
|
|
148
|
+
// Use like regular fetch, but with automatic auth headers
|
|
149
|
+
const response = await authenticatedFetch("/api/protected-data");
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Manual Header Management
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
import { addAuthHeader } from "@passkeyme/auth";
|
|
156
|
+
|
|
157
|
+
const headers = await addAuthHeader(auth, {
|
|
158
|
+
"Content-Type": "application/json",
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
fetch("/api/data", { headers });
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## 🎭 Event Handling
|
|
165
|
+
|
|
166
|
+
Listen to authentication events:
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
const unsubscribe = auth.addEventListener((event) => {
|
|
170
|
+
switch (event.type) {
|
|
171
|
+
case "login":
|
|
172
|
+
console.log("User logged in:", event.user);
|
|
173
|
+
break;
|
|
174
|
+
case "logout":
|
|
175
|
+
console.log("User logged out");
|
|
176
|
+
break;
|
|
177
|
+
case "token_refresh":
|
|
178
|
+
console.log("Token refreshed");
|
|
179
|
+
break;
|
|
180
|
+
case "error":
|
|
181
|
+
console.error("Auth error:", event.error);
|
|
182
|
+
break;
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
// Clean up when done
|
|
187
|
+
unsubscribe();
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## ⚙️ Configuration Options
|
|
191
|
+
|
|
192
|
+
### Basic Configuration
|
|
193
|
+
|
|
194
|
+
```typescript
|
|
195
|
+
const auth = new PasskeymeAuth({
|
|
196
|
+
appId: "your-app-id", // Required: From PasskeyMe dashboard
|
|
197
|
+
redirectUri: "http://localhost:3000/callback", // Optional: Default callback URL
|
|
198
|
+
debug: true, // Optional: Enable debug logging
|
|
199
|
+
});
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Custom Domain Configuration
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
const auth = new PasskeymeAuth({
|
|
206
|
+
appId: "your-app-id",
|
|
207
|
+
apiUrl: "https://auth.yourdomain.com", // Your custom domain
|
|
208
|
+
redirectUri: "https://yourapp.com/callback",
|
|
209
|
+
});
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Self-Hosted Configuration
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
const auth = new PasskeymeAuth({
|
|
216
|
+
appId: "your-app-id",
|
|
217
|
+
apiUrl: "http://localhost:8000", // Your self-hosted server
|
|
218
|
+
redirectUri: "http://localhost:3000/callback",
|
|
219
|
+
debug: true, // Helpful for development
|
|
220
|
+
});
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Storage Configuration
|
|
224
|
+
|
|
225
|
+
```typescript
|
|
226
|
+
import { PasskeymeAuth, BrowserStorageProvider } from "@passkeyme/auth";
|
|
227
|
+
|
|
228
|
+
// Default behavior (localStorage)
|
|
229
|
+
const auth = new PasskeymeAuth({
|
|
230
|
+
appId: "your-app-id",
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
// Use sessionStorage instead
|
|
234
|
+
const auth = new PasskeymeAuth({
|
|
235
|
+
appId: "your-app-id",
|
|
236
|
+
storage: new BrowserStorageProvider(true), // true = use sessionStorage
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
// Custom storage implementation
|
|
240
|
+
class CustomStorageProvider {
|
|
241
|
+
async getItem(key) {
|
|
242
|
+
/* your implementation */
|
|
243
|
+
}
|
|
244
|
+
async setItem(key, value) {
|
|
245
|
+
/* your implementation */
|
|
246
|
+
}
|
|
247
|
+
async removeItem(key) {
|
|
248
|
+
/* your implementation */
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const auth = new PasskeymeAuth({
|
|
253
|
+
appId: "your-app-id",
|
|
254
|
+
storage: new CustomStorageProvider(),
|
|
255
|
+
});
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### State Subscription
|
|
259
|
+
|
|
260
|
+
```typescript
|
|
261
|
+
// Subscribe to authentication state changes
|
|
262
|
+
const unsubscribe = auth.subscribe((state) => {
|
|
263
|
+
console.log("Auth state changed:", state);
|
|
264
|
+
// { user, loading, error, isAuthenticated }
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
// Get current state
|
|
268
|
+
const currentState = auth.getState();
|
|
269
|
+
|
|
270
|
+
// Clean up when done
|
|
271
|
+
unsubscribe();
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
## 🆚 vs Firebase Auth
|
|
275
|
+
|
|
276
|
+
| Feature | PasskeyMe Auth | Firebase Auth |
|
|
277
|
+
| -------------------- | -------------------------- | --------------------------- |
|
|
278
|
+
| **Setup Complexity** | ✅ Single provider | ❌ Multiple services needed |
|
|
279
|
+
| **Hosted Auth UI** | ✅ Pre-built, customizable | ❌ Build your own |
|
|
280
|
+
| **Passkey Support** | ✅ Built-in WebAuthn | ❌ Manual implementation |
|
|
281
|
+
| **Self-Hosting** | ✅ Full control | ❌ Google-only |
|
|
282
|
+
| **Vendor Lock-in** | ✅ Standard JWT | ❌ Firebase-specific |
|
|
283
|
+
| **Privacy** | ✅ Your data | ❌ Google's servers |
|
|
284
|
+
| **Bundle Size** | ✅ Lightweight | ❌ Heavy SDK |
|
|
285
|
+
|
|
286
|
+
## 📋 API Reference
|
|
287
|
+
|
|
288
|
+
### PasskeymeAuth Class
|
|
289
|
+
|
|
290
|
+
```typescript
|
|
291
|
+
class PasskeymeAuth {
|
|
292
|
+
// Properties
|
|
293
|
+
readonly state: AuthState;
|
|
294
|
+
|
|
295
|
+
// Methods
|
|
296
|
+
init(): Promise<void>;
|
|
297
|
+
redirectToLogin(options?: RedirectOptions): void;
|
|
298
|
+
redirectToOAuth(
|
|
299
|
+
provider: "google" | "github" | "facebook",
|
|
300
|
+
options?: RedirectOptions
|
|
301
|
+
): void;
|
|
302
|
+
handleAuthCallback(): Promise<User | null>;
|
|
303
|
+
logout(): Promise<void>;
|
|
304
|
+
getCurrentUser(): User | null;
|
|
305
|
+
getAccessToken(): Promise<string | null>;
|
|
306
|
+
refreshToken(): Promise<string>;
|
|
307
|
+
addEventListener(listener: AuthEventListener): () => void;
|
|
308
|
+
removeEventListener(listener: AuthEventListener): void;
|
|
309
|
+
}
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### Types
|
|
313
|
+
|
|
314
|
+
```typescript
|
|
315
|
+
interface User {
|
|
316
|
+
id: string;
|
|
317
|
+
email?: string;
|
|
318
|
+
name?: string;
|
|
319
|
+
picture?: string;
|
|
320
|
+
provider?: string;
|
|
321
|
+
createdAt?: string;
|
|
322
|
+
lastLoginAt?: string;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
interface AuthState {
|
|
326
|
+
user: User | null;
|
|
327
|
+
loading: boolean;
|
|
328
|
+
error: string | null;
|
|
329
|
+
isAuthenticated: boolean;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
interface RedirectOptions {
|
|
333
|
+
redirectTo?: string; // Where to go after successful auth
|
|
334
|
+
state?: string; // Custom state parameter
|
|
335
|
+
}
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
## 🔧 Advanced Usage
|
|
339
|
+
|
|
340
|
+
### Handling the Complete Flow
|
|
341
|
+
|
|
342
|
+
```typescript
|
|
343
|
+
// 1. App initialization
|
|
344
|
+
const auth = new PasskeymeAuth({
|
|
345
|
+
appId: "your-app-id",
|
|
346
|
+
redirectUri: "http://localhost:3000/auth/callback",
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
await auth.init();
|
|
350
|
+
|
|
351
|
+
// 2. Login button click
|
|
352
|
+
document.getElementById("login-btn").addEventListener("click", () => {
|
|
353
|
+
auth.redirectToLogin({ redirectTo: "/dashboard" });
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
// 3. On callback page (/auth/callback)
|
|
357
|
+
const user = await auth.handleAuthCallback();
|
|
358
|
+
if (user) {
|
|
359
|
+
// Redirect to the intended page
|
|
360
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
361
|
+
const redirectTo = urlParams.get("redirectTo") || "/";
|
|
362
|
+
window.location.href = redirectTo;
|
|
363
|
+
}
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
## 🔗 TypeScript Integration
|
|
367
|
+
|
|
368
|
+
This package is written in TypeScript and provides comprehensive type definitions.
|
|
369
|
+
|
|
370
|
+
### Type Imports
|
|
371
|
+
|
|
372
|
+
```typescript
|
|
373
|
+
import type {
|
|
374
|
+
PasskeymeConfig,
|
|
375
|
+
User,
|
|
376
|
+
AuthTokens,
|
|
377
|
+
OAuthProvider,
|
|
378
|
+
PasskeyCredential,
|
|
379
|
+
AuthState,
|
|
380
|
+
TokenStorage,
|
|
381
|
+
HttpInterceptor,
|
|
382
|
+
} from "@passkeyme/auth";
|
|
383
|
+
|
|
384
|
+
// Configuration interface
|
|
385
|
+
interface PasskeymeConfig {
|
|
386
|
+
appId: string;
|
|
387
|
+
baseUrl?: string; // Default: 'https://auth.passkeyme.com'
|
|
388
|
+
redirectUri: string;
|
|
389
|
+
debug?: boolean; // Enable debug logging
|
|
390
|
+
tokenStorage?: TokenStorage; // Custom token storage
|
|
391
|
+
httpInterceptors?: HttpInterceptor[]; // Custom HTTP interceptors
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// User object structure
|
|
395
|
+
interface User {
|
|
396
|
+
id: string;
|
|
397
|
+
email: string;
|
|
398
|
+
name?: string;
|
|
399
|
+
avatar?: string;
|
|
400
|
+
emailVerified: boolean;
|
|
401
|
+
createdAt: string;
|
|
402
|
+
lastLoginAt: string;
|
|
403
|
+
metadata?: Record<string, any>;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// Authentication tokens
|
|
407
|
+
interface AuthTokens {
|
|
408
|
+
accessToken: string;
|
|
409
|
+
refreshToken: string;
|
|
410
|
+
expiresAt: number;
|
|
411
|
+
tokenType: string;
|
|
412
|
+
}
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
### Advanced Configuration
|
|
416
|
+
|
|
417
|
+
```typescript
|
|
418
|
+
import { PasskeymeAuth, LocalStorageTokenStorage } from "@passkeyme/auth";
|
|
419
|
+
|
|
420
|
+
// Custom token storage implementation
|
|
421
|
+
class SecureTokenStorage implements TokenStorage {
|
|
422
|
+
async setTokens(tokens: AuthTokens): Promise<void> {
|
|
423
|
+
// Store in encrypted storage or secure keychain
|
|
424
|
+
await secureStorage.set("auth_tokens", encrypt(tokens));
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
async getTokens(): Promise<AuthTokens | null> {
|
|
428
|
+
const encrypted = await secureStorage.get("auth_tokens");
|
|
429
|
+
return encrypted ? decrypt(encrypted) : null;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
async clearTokens(): Promise<void> {
|
|
433
|
+
await secureStorage.remove("auth_tokens");
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// HTTP interceptor for API calls
|
|
438
|
+
const apiInterceptor: HttpInterceptor = {
|
|
439
|
+
request: async (config) => {
|
|
440
|
+
// Add custom headers or modify requests
|
|
441
|
+
config.headers = {
|
|
442
|
+
...config.headers,
|
|
443
|
+
"X-Client-Version": "1.0.0",
|
|
444
|
+
"X-Client-Platform": "web",
|
|
445
|
+
};
|
|
446
|
+
return config;
|
|
447
|
+
},
|
|
448
|
+
|
|
449
|
+
response: async (response) => {
|
|
450
|
+
// Handle responses globally
|
|
451
|
+
if (response.status === 401) {
|
|
452
|
+
// Handle unauthorized responses
|
|
453
|
+
await auth.logout();
|
|
454
|
+
window.location.href = "/login";
|
|
455
|
+
}
|
|
456
|
+
return response;
|
|
457
|
+
},
|
|
458
|
+
};
|
|
459
|
+
|
|
460
|
+
const auth = new PasskeymeAuth({
|
|
461
|
+
appId: "your-app-id",
|
|
462
|
+
redirectUri: "https://yourapp.com/auth/callback",
|
|
463
|
+
debug: process.env.NODE_ENV === "development",
|
|
464
|
+
tokenStorage: new SecureTokenStorage(),
|
|
465
|
+
httpInterceptors: [apiInterceptor],
|
|
466
|
+
});
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
### API Client Integration
|
|
470
|
+
|
|
471
|
+
```typescript
|
|
472
|
+
import { PasskeymeAuth } from "@passkeyme/auth";
|
|
473
|
+
|
|
474
|
+
class ApiClient {
|
|
475
|
+
private auth: PasskeymeAuth;
|
|
476
|
+
|
|
477
|
+
constructor(auth: PasskeymeAuth) {
|
|
478
|
+
this.auth = auth;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
async makeAuthenticatedRequest<T>(
|
|
482
|
+
url: string,
|
|
483
|
+
options: RequestInit = {}
|
|
484
|
+
): Promise<T> {
|
|
485
|
+
const authHeader = await this.auth.getAuthHeader();
|
|
486
|
+
|
|
487
|
+
const response = await fetch(url, {
|
|
488
|
+
...options,
|
|
489
|
+
headers: {
|
|
490
|
+
...options.headers,
|
|
491
|
+
Authorization: authHeader,
|
|
492
|
+
"Content-Type": "application/json",
|
|
493
|
+
},
|
|
494
|
+
});
|
|
495
|
+
|
|
496
|
+
if (!response.ok) {
|
|
497
|
+
if (response.status === 401) {
|
|
498
|
+
// Try to refresh token
|
|
499
|
+
await this.auth.refreshToken();
|
|
500
|
+
// Retry request with new token
|
|
501
|
+
return this.makeAuthenticatedRequest(url, options);
|
|
502
|
+
}
|
|
503
|
+
throw new Error(`API Error: ${response.status}`);
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
return response.json();
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
// Type-safe API methods
|
|
510
|
+
async getUserProfile(): Promise<User> {
|
|
511
|
+
return this.makeAuthenticatedRequest<User>("/api/user/profile");
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
async updateUserProfile(updates: Partial<User>): Promise<User> {
|
|
515
|
+
return this.makeAuthenticatedRequest<User>("/api/user/profile", {
|
|
516
|
+
method: "PATCH",
|
|
517
|
+
body: JSON.stringify(updates),
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
### Framework Integration Examples
|
|
524
|
+
|
|
525
|
+
#### Vanilla JavaScript (SPA)
|
|
526
|
+
|
|
527
|
+
```typescript
|
|
528
|
+
// main.js
|
|
529
|
+
const auth = new PasskeymeAuth({
|
|
530
|
+
appId: "your-app-id",
|
|
531
|
+
redirectUri: window.location.origin + "/auth/callback",
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
await auth.init();
|
|
535
|
+
|
|
536
|
+
// Router logic
|
|
537
|
+
if (window.location.pathname === "/auth/callback") {
|
|
538
|
+
const user = await auth.handleAuthCallback();
|
|
539
|
+
if (user) {
|
|
540
|
+
window.location.href = "/dashboard";
|
|
541
|
+
}
|
|
542
|
+
} else if (!auth.getCurrentUser() && window.location.pathname !== "/login") {
|
|
543
|
+
window.location.href = "/login";
|
|
544
|
+
}
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
#### Next.js Pages Router
|
|
548
|
+
|
|
549
|
+
```typescript
|
|
550
|
+
// pages/auth/callback.js
|
|
551
|
+
import { useEffect } from "react";
|
|
552
|
+
import { useRouter } from "next/router";
|
|
553
|
+
import { auth } from "../lib/auth";
|
|
554
|
+
|
|
555
|
+
export default function AuthCallback() {
|
|
556
|
+
const router = useRouter();
|
|
557
|
+
|
|
558
|
+
useEffect(() => {
|
|
559
|
+
auth.handleAuthCallback().then((user) => {
|
|
560
|
+
if (user) {
|
|
561
|
+
router.push("/dashboard");
|
|
562
|
+
} else {
|
|
563
|
+
router.push("/login?error=auth_failed");
|
|
564
|
+
}
|
|
565
|
+
});
|
|
566
|
+
}, []);
|
|
567
|
+
|
|
568
|
+
return <div>Completing authentication...</div>;
|
|
569
|
+
}
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
## 🛠️ Development
|
|
573
|
+
|
|
574
|
+
This package is part of the PasskeyMe project. For development:
|
|
575
|
+
|
|
576
|
+
```bash
|
|
577
|
+
# Install dependencies
|
|
578
|
+
npm install
|
|
579
|
+
|
|
580
|
+
# Build the package
|
|
581
|
+
npm run build
|
|
582
|
+
|
|
583
|
+
# Run tests
|
|
584
|
+
npm test
|
|
585
|
+
|
|
586
|
+
# Development mode (watch)
|
|
587
|
+
npm run dev
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
## 📄 License
|
|
591
|
+
|
|
592
|
+
MIT - see LICENSE file for details.
|
|
593
|
+
|
|
594
|
+
## 🤝 Support
|
|
595
|
+
|
|
596
|
+
- **Documentation**: https://passkeyme.com/docs
|
|
597
|
+
- **Issues**: https://github.com/passkeyme/passkeyme/issues
|
|
598
|
+
- **Discord**: https://discord.gg/passkeyme
|