handshake-auth 0.1.0 → 0.2.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 +230 -16
- package/dist/index.d.ts +18 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -1
- package/dist/index.js.map +1 -1
- package/dist/middleware/express.d.ts +67 -0
- package/dist/middleware/express.d.ts.map +1 -1
- package/dist/middleware/express.js +69 -0
- package/dist/middleware/express.js.map +1 -1
- package/dist/middleware/index.d.ts +2 -2
- package/dist/middleware/index.d.ts.map +1 -1
- package/dist/middleware/index.js +1 -1
- package/dist/middleware/index.js.map +1 -1
- package/dist/strategies/discord.d.ts +99 -0
- package/dist/strategies/discord.d.ts.map +1 -0
- package/dist/strategies/discord.js +85 -0
- package/dist/strategies/discord.js.map +1 -0
- package/dist/strategies/github.d.ts +112 -0
- package/dist/strategies/github.d.ts.map +1 -0
- package/dist/strategies/github.js +110 -0
- package/dist/strategies/github.js.map +1 -0
- package/dist/strategies/google.d.ts +91 -0
- package/dist/strategies/google.d.ts.map +1 -0
- package/dist/strategies/google.js +77 -0
- package/dist/strategies/google.js.map +1 -0
- package/dist/strategies/index.d.ts +16 -0
- package/dist/strategies/index.d.ts.map +1 -1
- package/dist/strategies/index.js +10 -0
- package/dist/strategies/index.js.map +1 -1
- package/dist/strategies/magic-link.d.ts +141 -0
- package/dist/strategies/magic-link.d.ts.map +1 -0
- package/dist/strategies/magic-link.js +186 -0
- package/dist/strategies/magic-link.js.map +1 -0
- package/dist/strategies/microsoft.d.ts +127 -0
- package/dist/strategies/microsoft.d.ts.map +1 -0
- package/dist/strategies/microsoft.js +98 -0
- package/dist/strategies/microsoft.js.map +1 -0
- package/dist/strategies/oauth-base.d.ts +162 -0
- package/dist/strategies/oauth-base.d.ts.map +1 -0
- package/dist/strategies/oauth-base.js +243 -0
- package/dist/strategies/oauth-base.js.map +1 -0
- package/dist/strategies/password.d.ts +69 -6
- package/dist/strategies/password.d.ts.map +1 -1
- package/dist/strategies/password.js +73 -24
- package/dist/strategies/password.js.map +1 -1
- package/dist/strategies/twitter-x.d.ts +130 -0
- package/dist/strategies/twitter-x.d.ts.map +1 -0
- package/dist/strategies/twitter-x.js +275 -0
- package/dist/strategies/twitter-x.js.map +1 -0
- package/dist/strategies/username-password.d.ts +38 -0
- package/dist/strategies/username-password.d.ts.map +1 -0
- package/dist/strategies/username-password.js +61 -0
- package/dist/strategies/username-password.js.map +1 -0
- package/package.json +2 -2
package/ReadMe.md
CHANGED
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
Lightweight, storage-agnostic authentication for Express.js.
|
|
4
4
|
|
|
5
|
-
> **Work in Progress** - This library is under active development and not yet ready for production use.
|
|
6
|
-
|
|
7
5
|
## Overview
|
|
8
6
|
|
|
9
7
|
Handshake Auth is a lightweight authentication library that follows the strategy pattern similar to Passport.js, but without requiring a database connection. You provide callbacks for all storage operations (Inversion of Control), giving you complete control over how accounts are stored and retrieved.
|
|
@@ -14,13 +12,47 @@ Handshake Auth is a lightweight authentication library that follows the strategy
|
|
|
14
12
|
|
|
15
13
|
The library handles the "handshakes" and "proofs" without demanding a seat at your database table. After successful authentication, you receive an Account object and decide what to do with it.
|
|
16
14
|
|
|
15
|
+
## Why Handshake Auth?
|
|
16
|
+
|
|
17
|
+
### vs Passport.js
|
|
18
|
+
|
|
19
|
+
Passport is the de facto standard but shows its age:
|
|
20
|
+
|
|
21
|
+
| Passport.js | Handshake Auth |
|
|
22
|
+
|-------------|----------------|
|
|
23
|
+
| Middleware hides control flow (magic redirects) | Explicit control flow (you call `authenticate()`, you handle the result) |
|
|
24
|
+
| Sessions are the assumed default | Session-agnostic (works with `cookie-session`, no server-side state) |
|
|
25
|
+
| `serializeUser`/`deserializeUser` are global singletons | Callbacks are per-instance, not global |
|
|
26
|
+
| Callback-based API (`done(err, user, info)`) | `async`/`await` throughout |
|
|
27
|
+
| OAuth flows are opaque | OAuth phases are explicit and visible |
|
|
28
|
+
| Hundreds of strategies with inconsistent quality | Small, auditable codebase with built-in strategies |
|
|
29
|
+
|
|
30
|
+
### vs better-auth
|
|
31
|
+
|
|
32
|
+
better-auth is feature-rich but opinionated:
|
|
33
|
+
|
|
34
|
+
| better-auth | Handshake Auth |
|
|
35
|
+
|-------------|----------------|
|
|
36
|
+
| **Requires database connection** | **No database connection** - you provide callbacks |
|
|
37
|
+
| Creates and manages auth tables | You own your schema |
|
|
38
|
+
| All-in-one (sessions, email verification, etc.) | Auth only - does one thing well |
|
|
39
|
+
| Great for rapid prototyping | Full control over persistence |
|
|
40
|
+
|
|
41
|
+
### The Sweet Spot
|
|
42
|
+
|
|
43
|
+
If you want Passport's flexibility with modern ergonomics, without better-auth's database coupling, Handshake Auth is for you.
|
|
44
|
+
|
|
17
45
|
## Features
|
|
18
46
|
|
|
19
47
|
- **Storage-agnostic** - You provide callbacks, you own your data
|
|
20
48
|
- **Express-only** - Focused on Express.js with `cookie-session`
|
|
21
49
|
- **TypeScript-first** - Full type safety with generics
|
|
22
50
|
- **Modern** - async/await throughout, ESM-first
|
|
23
|
-
- **Strategies included
|
|
51
|
+
- **Strategies included:**
|
|
52
|
+
- Password (simple password-only for self-hosted apps)
|
|
53
|
+
- Username/Password (traditional email + password)
|
|
54
|
+
- Magic Link (passwordless via email)
|
|
55
|
+
- OAuth: Google, GitHub, Discord, Microsoft, Twitter/X
|
|
24
56
|
|
|
25
57
|
## Installation
|
|
26
58
|
|
|
@@ -31,7 +63,7 @@ npm install handshake-auth
|
|
|
31
63
|
## Basic Usage
|
|
32
64
|
|
|
33
65
|
```typescript
|
|
34
|
-
import { Handshake,
|
|
66
|
+
import { Handshake, UsernamePasswordStrategy } from 'handshake-auth';
|
|
35
67
|
|
|
36
68
|
// Define your account type
|
|
37
69
|
interface Account {
|
|
@@ -52,11 +84,11 @@ const hs = new Handshake<Account>({
|
|
|
52
84
|
},
|
|
53
85
|
});
|
|
54
86
|
|
|
55
|
-
// Register the password strategy
|
|
56
|
-
hs.use(new
|
|
87
|
+
// Register the username-password strategy
|
|
88
|
+
hs.use(new UsernamePasswordStrategy());
|
|
57
89
|
|
|
58
90
|
// Authenticate
|
|
59
|
-
const result = await hs.authenticate('password', 'user@example.com', 'their-password');
|
|
91
|
+
const result = await hs.authenticate('username-password', 'user@example.com', 'their-password');
|
|
60
92
|
|
|
61
93
|
if (result.account) {
|
|
62
94
|
// Authentication successful
|
|
@@ -76,11 +108,12 @@ import express from 'express';
|
|
|
76
108
|
import cookieSession from 'cookie-session';
|
|
77
109
|
import {
|
|
78
110
|
Handshake,
|
|
79
|
-
|
|
111
|
+
UsernamePasswordStrategy,
|
|
80
112
|
handshakeMiddleware,
|
|
81
113
|
login,
|
|
82
114
|
logout,
|
|
83
|
-
|
|
115
|
+
requireAuth,
|
|
116
|
+
requireGuest,
|
|
84
117
|
} from 'handshake-auth';
|
|
85
118
|
|
|
86
119
|
const app = express();
|
|
@@ -98,7 +131,7 @@ const hs = new Handshake<Account>({
|
|
|
98
131
|
findAccount: async (email) => db.accounts.findByEmail(email),
|
|
99
132
|
verifyPassword: async (account, password) => bcrypt.compare(password, account.passwordHash),
|
|
100
133
|
});
|
|
101
|
-
hs.use(new
|
|
134
|
+
hs.use(new UsernamePasswordStrategy());
|
|
102
135
|
|
|
103
136
|
// Add middleware (attaches authenticate helper to req)
|
|
104
137
|
app.use(handshakeMiddleware(hs));
|
|
@@ -106,7 +139,7 @@ app.use(handshakeMiddleware(hs));
|
|
|
106
139
|
// Login route
|
|
107
140
|
app.post('/login', async (req, res) => {
|
|
108
141
|
const { email, password } = req.body;
|
|
109
|
-
const result = await hs.authenticate('password', email, password);
|
|
142
|
+
const result = await hs.authenticate('username-password', email, password);
|
|
110
143
|
|
|
111
144
|
if (result.account) {
|
|
112
145
|
login(req, result.account);
|
|
@@ -122,15 +155,196 @@ app.post('/logout', (req, res) => {
|
|
|
122
155
|
res.json({ success: true });
|
|
123
156
|
});
|
|
124
157
|
|
|
125
|
-
// Protected route
|
|
126
|
-
app.get('/me', (req, res) => {
|
|
127
|
-
if (!isLoggedIn(req)) {
|
|
128
|
-
return res.status(401).json({ error: 'Not logged in' });
|
|
129
|
-
}
|
|
158
|
+
// Protected route (API style - returns 401 JSON if not authenticated)
|
|
159
|
+
app.get('/api/me', requireAuth(), (req, res) => {
|
|
130
160
|
res.json({ accountId: req.session?.accountId });
|
|
131
161
|
});
|
|
162
|
+
|
|
163
|
+
// Protected route (Web style - redirects to /login if not authenticated)
|
|
164
|
+
app.get('/dashboard', requireAuth({ redirectTo: '/login' }), (req, res) => {
|
|
165
|
+
res.send('Welcome to your dashboard!');
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
// Guest-only route (redirects to /dashboard if already logged in)
|
|
169
|
+
app.get('/login', requireGuest({ redirectTo: '/dashboard' }), (req, res) => {
|
|
170
|
+
res.send('<form>...</form>');
|
|
171
|
+
});
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Magic Link Authentication
|
|
175
|
+
|
|
176
|
+
Passwordless authentication via email:
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
import { Handshake, useMagicLink, login } from 'handshake-auth';
|
|
180
|
+
|
|
181
|
+
// In-memory token storage (use a database in production)
|
|
182
|
+
const tokens = new Map<string, { email: string; expiresAt: Date }>();
|
|
183
|
+
|
|
184
|
+
const hs = new Handshake<Account>({
|
|
185
|
+
findAccount: async (email) => db.accounts.findByEmail(email),
|
|
186
|
+
storeMagicToken: async (email, token, expiresAt) => {
|
|
187
|
+
tokens.set(token, { email, expiresAt });
|
|
188
|
+
},
|
|
189
|
+
verifyMagicToken: async (token) => {
|
|
190
|
+
const record = tokens.get(token);
|
|
191
|
+
if (!record || record.expiresAt < new Date()) return null;
|
|
192
|
+
tokens.delete(token); // One-time use
|
|
193
|
+
return { email: record.email };
|
|
194
|
+
},
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
// Register magic link strategy
|
|
198
|
+
useMagicLink(hs, {
|
|
199
|
+
baseUrl: 'http://localhost:3000',
|
|
200
|
+
sendMagicLink: async (email, token, url) => {
|
|
201
|
+
// Send email with the magic link URL
|
|
202
|
+
console.log(`Magic link for ${email}: ${url}`);
|
|
203
|
+
},
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
// Request magic link
|
|
207
|
+
app.post('/auth/magic', async (req, res) => {
|
|
208
|
+
const result = await hs.authenticate('magic:send', req.body.email);
|
|
209
|
+
if (!result.error) {
|
|
210
|
+
res.json({ message: 'Check your email!' });
|
|
211
|
+
} else {
|
|
212
|
+
res.status(400).json({ error: result.error });
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
// Verify magic link
|
|
217
|
+
app.get('/auth/magic/callback', async (req, res) => {
|
|
218
|
+
const result = await hs.authenticate('magic:verify', req.query.token);
|
|
219
|
+
if (result.account) {
|
|
220
|
+
login(req, result.account);
|
|
221
|
+
res.redirect('/dashboard');
|
|
222
|
+
} else {
|
|
223
|
+
res.status(401).send('Invalid or expired link');
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## OAuth Authentication
|
|
229
|
+
|
|
230
|
+
Handshake Auth supports OAuth providers with a simple, consistent API:
|
|
231
|
+
|
|
232
|
+
```typescript
|
|
233
|
+
import {
|
|
234
|
+
Handshake,
|
|
235
|
+
GoogleStrategy,
|
|
236
|
+
GitHubStrategy,
|
|
237
|
+
DiscordStrategy,
|
|
238
|
+
MicrosoftStrategy,
|
|
239
|
+
TwitterXStrategy,
|
|
240
|
+
login,
|
|
241
|
+
} from 'handshake-auth';
|
|
242
|
+
|
|
243
|
+
const hs = new Handshake<Account>({
|
|
244
|
+
findAccount: async (email) => db.accounts.findByEmail(email),
|
|
245
|
+
findOrCreateFromOAuth: async (provider, profile) => {
|
|
246
|
+
// Find existing account or create new one
|
|
247
|
+
let account = await db.accounts.findByProviderId(provider, profile.id);
|
|
248
|
+
if (!account) {
|
|
249
|
+
account = await db.accounts.create({
|
|
250
|
+
email: profile.email,
|
|
251
|
+
name: profile.name,
|
|
252
|
+
provider,
|
|
253
|
+
providerId: profile.id,
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
return account;
|
|
257
|
+
},
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
// Register OAuth strategies (only the ones you need)
|
|
261
|
+
if (process.env.GOOGLE_CLIENT_ID) {
|
|
262
|
+
hs.use(new GoogleStrategy({
|
|
263
|
+
clientId: process.env.GOOGLE_CLIENT_ID,
|
|
264
|
+
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
|
|
265
|
+
redirectUri: 'http://localhost:3000/auth/google/callback',
|
|
266
|
+
}));
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if (process.env.GITHUB_CLIENT_ID) {
|
|
270
|
+
hs.use(new GitHubStrategy({
|
|
271
|
+
clientId: process.env.GITHUB_CLIENT_ID,
|
|
272
|
+
clientSecret: process.env.GITHUB_CLIENT_SECRET!,
|
|
273
|
+
redirectUri: 'http://localhost:3000/auth/github/callback',
|
|
274
|
+
}));
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// Generic OAuth routes
|
|
278
|
+
app.get('/auth/:provider', async (req, res) => {
|
|
279
|
+
const result = await hs.authenticate(req.params.provider, req, res, 'redirect');
|
|
280
|
+
if ('redirectUrl' in result) {
|
|
281
|
+
res.redirect(result.redirectUrl);
|
|
282
|
+
} else {
|
|
283
|
+
res.status(400).send(result.error);
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
app.get('/auth/:provider/callback', async (req, res) => {
|
|
288
|
+
const result = await hs.authenticate(req.params.provider, req, res, 'callback');
|
|
289
|
+
if (result.account) {
|
|
290
|
+
login(req, result.account);
|
|
291
|
+
res.redirect('/dashboard');
|
|
292
|
+
} else {
|
|
293
|
+
res.status(401).send(result.error);
|
|
294
|
+
}
|
|
295
|
+
});
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### Supported OAuth Providers
|
|
299
|
+
|
|
300
|
+
| Provider | Strategy | Notes |
|
|
301
|
+
|----------|----------|-------|
|
|
302
|
+
| Google | `GoogleStrategy` | OpenID Connect |
|
|
303
|
+
| GitHub | `GitHubStrategy` | Fetches email from `/user/emails` if needed |
|
|
304
|
+
| Discord | `DiscordStrategy` | Standard OAuth2 |
|
|
305
|
+
| Microsoft | `MicrosoftStrategy` | Supports tenant configuration |
|
|
306
|
+
| Twitter/X | `TwitterXStrategy` | OAuth 2.0 with PKCE (no email provided) |
|
|
307
|
+
|
|
308
|
+
## Documentation
|
|
309
|
+
|
|
310
|
+
For detailed documentation, see the [docs/](./docs/) folder:
|
|
311
|
+
|
|
312
|
+
- **[API Reference](./docs/api.md)** - Handshake class and core types
|
|
313
|
+
- **[Express Middleware](./docs/middleware.md)** - Middleware functions, route guards, session helpers
|
|
314
|
+
- **Strategies:**
|
|
315
|
+
- [Password](./docs/strategies/password.md) - Simple password-only authentication
|
|
316
|
+
- [Username/Password](./docs/strategies/username-password.md) - Email/username + password
|
|
317
|
+
- [Magic Link](./docs/strategies/magic-link.md) - Passwordless email authentication
|
|
318
|
+
- [Google](./docs/strategies/google.md) - Google OAuth
|
|
319
|
+
- [GitHub](./docs/strategies/github.md) - GitHub OAuth
|
|
320
|
+
- [Discord](./docs/strategies/discord.md) - Discord OAuth
|
|
321
|
+
- [Microsoft](./docs/strategies/microsoft.md) - Microsoft OAuth
|
|
322
|
+
- [Twitter/X](./docs/strategies/twitter-x.md) - Twitter/X OAuth
|
|
323
|
+
|
|
324
|
+
## Example Application
|
|
325
|
+
|
|
326
|
+
See the [examples/express-app](./examples/express-app) directory for a complete working example with all authentication strategies.
|
|
327
|
+
|
|
328
|
+
```bash
|
|
329
|
+
cd examples/express-app
|
|
330
|
+
npm install
|
|
331
|
+
cp .env.example .env
|
|
332
|
+
npm run dev
|
|
132
333
|
```
|
|
133
334
|
|
|
335
|
+
## What This Library Does NOT Do
|
|
336
|
+
|
|
337
|
+
- **No account management** - No account model, no persistence, no database integrations
|
|
338
|
+
- **No session management** - Uses `cookie-session` but doesn't manage server-side sessions
|
|
339
|
+
- **No route ownership** - No automatic `/login`, `/callback`, or `/logout` routes
|
|
340
|
+
- **No email sending** - Magic links require user-supplied delivery
|
|
341
|
+
- **No UI** - No forms, no opinionated UX
|
|
342
|
+
|
|
343
|
+
## ChangeLog
|
|
344
|
+
|
|
345
|
+
- **0.2.0** - All strategies implemented (Password, Username/Password, Magic Link, Google, GitHub, Discord, Microsoft, Twitter/X), Express middleware with route guards, comprehensive documentation
|
|
346
|
+
- **0.1.0** - Initial development release
|
|
347
|
+
|
|
134
348
|
## License
|
|
135
349
|
|
|
136
350
|
ISC
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,22 @@
|
|
|
1
1
|
export type { AuthResult, Strategy, HandshakeCallbacks, HandshakeOptions, OAuthProfile, } from './types.js';
|
|
2
2
|
export { Handshake } from './handshake.js';
|
|
3
3
|
export { PasswordStrategy } from './strategies/index.js';
|
|
4
|
-
export {
|
|
5
|
-
export
|
|
4
|
+
export type { PasswordStrategyOptions } from './strategies/index.js';
|
|
5
|
+
export { UsernamePasswordStrategy } from './strategies/index.js';
|
|
6
|
+
export { MagicLinkStrategy, MagicLinkSendStrategy, MagicLinkVerifyStrategy, useMagicLink, } from './strategies/index.js';
|
|
7
|
+
export type { MagicLinkOptions, MagicLinkSendResult } from './strategies/index.js';
|
|
8
|
+
export { OAuthStrategy, isOAuthRedirect } from './strategies/index.js';
|
|
9
|
+
export type { OAuthConfig, OAuthRedirectResult, OAuthTokenResponse, OAuthAuthResult, } from './strategies/index.js';
|
|
10
|
+
export { GoogleStrategy } from './strategies/index.js';
|
|
11
|
+
export type { GoogleProfile, GoogleStrategyOptions } from './strategies/index.js';
|
|
12
|
+
export { GitHubStrategy } from './strategies/index.js';
|
|
13
|
+
export type { GitHubProfile, GitHubEmail, GitHubStrategyOptions } from './strategies/index.js';
|
|
14
|
+
export { DiscordStrategy } from './strategies/index.js';
|
|
15
|
+
export type { DiscordProfile, DiscordStrategyOptions } from './strategies/index.js';
|
|
16
|
+
export { MicrosoftStrategy } from './strategies/index.js';
|
|
17
|
+
export type { MicrosoftProfile, MicrosoftTenant, MicrosoftStrategyOptions } from './strategies/index.js';
|
|
18
|
+
export { TwitterXStrategy } from './strategies/index.js';
|
|
19
|
+
export type { TwitterXProfile, TwitterXStrategyOptions } from './strategies/index.js';
|
|
20
|
+
export { handshakeMiddleware, login, logout, isLoggedIn, getSessionAccountId, requireAuth, requireGuest, } from './middleware/index.js';
|
|
21
|
+
export type { HandshakeSession, RequestWithAuth, RequireAuthOptions, RequireGuestOptions, } from './middleware/index.js';
|
|
6
22
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,UAAU,EACV,QAAQ,EACR,kBAAkB,EAClB,gBAAgB,EAChB,YAAY,GACb,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAG3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,UAAU,EACV,QAAQ,EACR,kBAAkB,EAClB,gBAAgB,EAChB,YAAY,GACb,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAG3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,YAAY,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AACrE,OAAO,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,uBAAuB,EACvB,YAAY,GACb,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAGnF,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACvE,YAAY,EACV,WAAW,EACX,mBAAmB,EACnB,kBAAkB,EAClB,eAAe,GAChB,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,YAAY,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAElF,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAE/F,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,YAAY,EAAE,cAAc,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAEpF,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AAEzG,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,YAAY,EAAE,eAAe,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAGtF,OAAO,EACL,mBAAmB,EACnB,KAAK,EACL,MAAM,EACN,UAAU,EACV,mBAAmB,EACnB,WAAW,EACX,YAAY,GACb,MAAM,uBAAuB,CAAC;AAE/B,YAAY,EACV,gBAAgB,EAChB,eAAe,EACf,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,uBAAuB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
export { Handshake } from './handshake.js';
|
|
3
3
|
// Strategies
|
|
4
4
|
export { PasswordStrategy } from './strategies/index.js';
|
|
5
|
+
export { UsernamePasswordStrategy } from './strategies/index.js';
|
|
6
|
+
export { MagicLinkStrategy, MagicLinkSendStrategy, MagicLinkVerifyStrategy, useMagicLink, } from './strategies/index.js';
|
|
7
|
+
// OAuth base
|
|
8
|
+
export { OAuthStrategy, isOAuthRedirect } from './strategies/index.js';
|
|
9
|
+
// OAuth providers
|
|
10
|
+
export { GoogleStrategy } from './strategies/index.js';
|
|
11
|
+
export { GitHubStrategy } from './strategies/index.js';
|
|
12
|
+
export { DiscordStrategy } from './strategies/index.js';
|
|
13
|
+
export { MicrosoftStrategy } from './strategies/index.js';
|
|
14
|
+
export { TwitterXStrategy } from './strategies/index.js';
|
|
5
15
|
// Express middleware
|
|
6
|
-
export { handshakeMiddleware, login, logout, isLoggedIn, getSessionAccountId, } from './middleware/index.js';
|
|
16
|
+
export { handshakeMiddleware, login, logout, isLoggedIn, getSessionAccountId, requireAuth, requireGuest, } from './middleware/index.js';
|
|
7
17
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AASA,aAAa;AACb,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,aAAa;AACb,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEzD,qBAAqB;AACrB,OAAO,EACL,mBAAmB,EACnB,KAAK,EACL,MAAM,EACN,UAAU,EACV,mBAAmB,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AASA,aAAa;AACb,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,aAAa;AACb,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEzD,OAAO,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,uBAAuB,EACvB,YAAY,GACb,MAAM,uBAAuB,CAAC;AAG/B,aAAa;AACb,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAQvE,kBAAkB;AAClB,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAGvD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAGvD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAGxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAG1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAGzD,qBAAqB;AACrB,OAAO,EACL,mBAAmB,EACnB,KAAK,EACL,MAAM,EACN,UAAU,EACV,mBAAmB,EACnB,WAAW,EACX,YAAY,GACb,MAAM,uBAAuB,CAAC"}
|
|
@@ -74,4 +74,71 @@ export declare function getSessionAccountId(req: Request): string | undefined;
|
|
|
74
74
|
export interface RequestWithAuth<TAccount> extends Request {
|
|
75
75
|
authenticate: (strategyName: string, ...args: unknown[]) => Promise<AuthResult<TAccount>>;
|
|
76
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* Options for requireAuth middleware.
|
|
79
|
+
*/
|
|
80
|
+
export interface RequireAuthOptions {
|
|
81
|
+
/**
|
|
82
|
+
* URL to redirect to if not authenticated.
|
|
83
|
+
* If not provided, returns 401 JSON response.
|
|
84
|
+
* @example '/login'
|
|
85
|
+
*/
|
|
86
|
+
redirectTo?: string;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Options for requireGuest middleware.
|
|
90
|
+
*/
|
|
91
|
+
export interface RequireGuestOptions {
|
|
92
|
+
/**
|
|
93
|
+
* URL to redirect to if already authenticated.
|
|
94
|
+
* If not provided, returns 403 JSON response.
|
|
95
|
+
* @example '/dashboard'
|
|
96
|
+
*/
|
|
97
|
+
redirectTo?: string;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Route guard middleware that requires authentication.
|
|
101
|
+
* Use this to protect routes that should only be accessible to logged-in users.
|
|
102
|
+
*
|
|
103
|
+
* @param options - Configuration options
|
|
104
|
+
* @param options.redirectTo - URL to redirect to if not authenticated (for web apps)
|
|
105
|
+
* @returns Express middleware function
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```typescript
|
|
109
|
+
* // API style - returns 401 JSON if not authenticated
|
|
110
|
+
* app.get('/api/profile', requireAuth(), (req, res) => {
|
|
111
|
+
* res.json({ accountId: req.session.accountId });
|
|
112
|
+
* });
|
|
113
|
+
*
|
|
114
|
+
* // Web style - redirects to login page if not authenticated
|
|
115
|
+
* app.get('/dashboard', requireAuth({ redirectTo: '/login' }), (req, res) => {
|
|
116
|
+
* res.render('dashboard');
|
|
117
|
+
* });
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
120
|
+
export declare function requireAuth(options?: RequireAuthOptions): (req: Request, res: Response, next: NextFunction) => void;
|
|
121
|
+
/**
|
|
122
|
+
* Route guard middleware that requires the user to be a guest (not logged in).
|
|
123
|
+
* Use this to protect routes that should only be accessible to non-authenticated users,
|
|
124
|
+
* such as login and registration pages.
|
|
125
|
+
*
|
|
126
|
+
* @param options - Configuration options
|
|
127
|
+
* @param options.redirectTo - URL to redirect to if already authenticated (for web apps)
|
|
128
|
+
* @returns Express middleware function
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* ```typescript
|
|
132
|
+
* // API style - returns 403 JSON if already authenticated
|
|
133
|
+
* app.post('/api/login', requireGuest(), (req, res) => {
|
|
134
|
+
* // Handle login
|
|
135
|
+
* });
|
|
136
|
+
*
|
|
137
|
+
* // Web style - redirects to dashboard if already logged in
|
|
138
|
+
* app.get('/login', requireGuest({ redirectTo: '/dashboard' }), (req, res) => {
|
|
139
|
+
* res.render('login');
|
|
140
|
+
* });
|
|
141
|
+
* ```
|
|
142
|
+
*/
|
|
143
|
+
export declare function requireGuest(options?: RequireGuestOptions): (req: Request, res: Response, next: NextFunction) => void;
|
|
77
144
|
//# sourceMappingURL=express.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"express.d.ts","sourceRoot":"","sources":["../../src/middleware/express.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,EAAE,EAAE,SAAS,CAAC,QAAQ,CAAC,IAC3D,KAAK,OAAO,EAAE,MAAM,QAAQ,EAAE,MAAM,YAAY,KAAG,IAAI,CAWhE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,KAAK,CAAC,QAAQ,SAAS;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,EACnD,GAAG,EAAE,OAAO,EACZ,OAAO,EAAE,QAAQ,GAChB,IAAI,CAKN;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,MAAM,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAEzC;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAEhD;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAEpE;AAED;;GAEG;AACH,MAAM,WAAW,eAAe,CAAC,QAAQ,CAAE,SAAQ,OAAO;IACxD,YAAY,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC;CAC3F"}
|
|
1
|
+
{"version":3,"file":"express.d.ts","sourceRoot":"","sources":["../../src/middleware/express.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,EAAE,EAAE,SAAS,CAAC,QAAQ,CAAC,IAC3D,KAAK,OAAO,EAAE,MAAM,QAAQ,EAAE,MAAM,YAAY,KAAG,IAAI,CAWhE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,KAAK,CAAC,QAAQ,SAAS;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,EACnD,GAAG,EAAE,OAAO,EACZ,OAAO,EAAE,QAAQ,GAChB,IAAI,CAKN;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,MAAM,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAEzC;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAEhD;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAEpE;AAED;;GAEG;AACH,MAAM,WAAW,eAAe,CAAC,QAAQ,CAAE,SAAQ,OAAO;IACxD,YAAY,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC;CAC3F;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,WAAW,CAAC,OAAO,CAAC,EAAE,kBAAkB,IAC9C,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,KAAG,IAAI,CAS/D;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,YAAY,CAAC,OAAO,CAAC,EAAE,mBAAmB,IAChD,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,KAAG,IAAI,CAS/D"}
|
|
@@ -74,4 +74,73 @@ export function isLoggedIn(req) {
|
|
|
74
74
|
export function getSessionAccountId(req) {
|
|
75
75
|
return req.session?.accountId;
|
|
76
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* Route guard middleware that requires authentication.
|
|
79
|
+
* Use this to protect routes that should only be accessible to logged-in users.
|
|
80
|
+
*
|
|
81
|
+
* @param options - Configuration options
|
|
82
|
+
* @param options.redirectTo - URL to redirect to if not authenticated (for web apps)
|
|
83
|
+
* @returns Express middleware function
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```typescript
|
|
87
|
+
* // API style - returns 401 JSON if not authenticated
|
|
88
|
+
* app.get('/api/profile', requireAuth(), (req, res) => {
|
|
89
|
+
* res.json({ accountId: req.session.accountId });
|
|
90
|
+
* });
|
|
91
|
+
*
|
|
92
|
+
* // Web style - redirects to login page if not authenticated
|
|
93
|
+
* app.get('/dashboard', requireAuth({ redirectTo: '/login' }), (req, res) => {
|
|
94
|
+
* res.render('dashboard');
|
|
95
|
+
* });
|
|
96
|
+
* ```
|
|
97
|
+
*/
|
|
98
|
+
export function requireAuth(options) {
|
|
99
|
+
return (req, res, next) => {
|
|
100
|
+
if (isLoggedIn(req)) {
|
|
101
|
+
next();
|
|
102
|
+
}
|
|
103
|
+
else if (options?.redirectTo) {
|
|
104
|
+
res.redirect(options.redirectTo);
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
res.status(401).json({ error: 'Authentication required' });
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Route guard middleware that requires the user to be a guest (not logged in).
|
|
113
|
+
* Use this to protect routes that should only be accessible to non-authenticated users,
|
|
114
|
+
* such as login and registration pages.
|
|
115
|
+
*
|
|
116
|
+
* @param options - Configuration options
|
|
117
|
+
* @param options.redirectTo - URL to redirect to if already authenticated (for web apps)
|
|
118
|
+
* @returns Express middleware function
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* ```typescript
|
|
122
|
+
* // API style - returns 403 JSON if already authenticated
|
|
123
|
+
* app.post('/api/login', requireGuest(), (req, res) => {
|
|
124
|
+
* // Handle login
|
|
125
|
+
* });
|
|
126
|
+
*
|
|
127
|
+
* // Web style - redirects to dashboard if already logged in
|
|
128
|
+
* app.get('/login', requireGuest({ redirectTo: '/dashboard' }), (req, res) => {
|
|
129
|
+
* res.render('login');
|
|
130
|
+
* });
|
|
131
|
+
* ```
|
|
132
|
+
*/
|
|
133
|
+
export function requireGuest(options) {
|
|
134
|
+
return (req, res, next) => {
|
|
135
|
+
if (!isLoggedIn(req)) {
|
|
136
|
+
next();
|
|
137
|
+
}
|
|
138
|
+
else if (options?.redirectTo) {
|
|
139
|
+
res.redirect(options.redirectTo);
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
res.status(403).json({ error: 'Already logged in' });
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
}
|
|
77
146
|
//# sourceMappingURL=express.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"express.js","sourceRoot":"","sources":["../../src/middleware/express.ts"],"names":[],"mappings":"AAaA;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,mBAAmB,CAAW,EAAuB;IACnE,OAAO,CAAC,GAAY,EAAE,IAAc,EAAE,IAAkB,EAAQ,EAAE;QAChE,wCAAwC;QACvC,GAAiC,CAAC,YAAY,GAAG,KAAK,EACrD,YAAoB,EACpB,GAAG,IAAe,EACa,EAAE;YACjC,OAAO,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,GAAG,IAAI,CAAC,CAAC;QAChD,CAAC,CAAC;QAEF,IAAI,EAAE,CAAC;IACT,CAAC,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,KAAK,CACnB,GAAY,EACZ,OAAiB;IAEjB,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,2EAA2E,CAAC,CAAC;IAC/F,CAAC;IACD,GAAG,CAAC,OAAO,CAAC,SAAS,GAAG,OAAO,CAAC,EAAE,CAAC;AACrC,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,MAAM,CAAC,GAAY;IACjC,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC;AACrB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CAAC,GAAY;IACrC,OAAO,GAAG,CAAC,OAAO,EAAE,SAAS,KAAK,SAAS,CAAC;AAC9C,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,GAAY;IAC9C,OAAO,GAAG,CAAC,OAAO,EAAE,SAA+B,CAAC;AACtD,CAAC"}
|
|
1
|
+
{"version":3,"file":"express.js","sourceRoot":"","sources":["../../src/middleware/express.ts"],"names":[],"mappings":"AAaA;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,mBAAmB,CAAW,EAAuB;IACnE,OAAO,CAAC,GAAY,EAAE,IAAc,EAAE,IAAkB,EAAQ,EAAE;QAChE,wCAAwC;QACvC,GAAiC,CAAC,YAAY,GAAG,KAAK,EACrD,YAAoB,EACpB,GAAG,IAAe,EACa,EAAE;YACjC,OAAO,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,GAAG,IAAI,CAAC,CAAC;QAChD,CAAC,CAAC;QAEF,IAAI,EAAE,CAAC;IACT,CAAC,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,KAAK,CACnB,GAAY,EACZ,OAAiB;IAEjB,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,2EAA2E,CAAC,CAAC;IAC/F,CAAC;IACD,GAAG,CAAC,OAAO,CAAC,SAAS,GAAG,OAAO,CAAC,EAAE,CAAC;AACrC,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,MAAM,CAAC,GAAY;IACjC,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC;AACrB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CAAC,GAAY;IACrC,OAAO,GAAG,CAAC,OAAO,EAAE,SAAS,KAAK,SAAS,CAAC;AAC9C,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,GAAY;IAC9C,OAAO,GAAG,CAAC,OAAO,EAAE,SAA+B,CAAC;AACtD,CAAC;AAiCD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,WAAW,CAAC,OAA4B;IACtD,OAAO,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAQ,EAAE;QAC/D,IAAI,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACpB,IAAI,EAAE,CAAC;QACT,CAAC;aAAM,IAAI,OAAO,EAAE,UAAU,EAAE,CAAC;YAC/B,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QACnC,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,yBAAyB,EAAE,CAAC,CAAC;QAC7D,CAAC;IACH,CAAC,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,YAAY,CAAC,OAA6B;IACxD,OAAO,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAQ,EAAE;QAC/D,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACrB,IAAI,EAAE,CAAC;QACT,CAAC;aAAM,IAAI,OAAO,EAAE,UAAU,EAAE,CAAC;YAC/B,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QACnC,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC,CAAC;QACvD,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { handshakeMiddleware, login, logout, isLoggedIn, getSessionAccountId, } from './express.js';
|
|
2
|
-
export type { HandshakeSession, RequestWithAuth } from './express.js';
|
|
1
|
+
export { handshakeMiddleware, login, logout, isLoggedIn, getSessionAccountId, requireAuth, requireGuest, } from './express.js';
|
|
2
|
+
export type { HandshakeSession, RequestWithAuth, RequireAuthOptions, RequireGuestOptions, } from './express.js';
|
|
3
3
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/middleware/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,KAAK,EACL,MAAM,EACN,UAAU,EACV,mBAAmB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/middleware/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,KAAK,EACL,MAAM,EACN,UAAU,EACV,mBAAmB,EACnB,WAAW,EACX,YAAY,GACb,MAAM,cAAc,CAAC;AAEtB,YAAY,EACV,gBAAgB,EAChB,eAAe,EACf,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,cAAc,CAAC"}
|
package/dist/middleware/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { handshakeMiddleware, login, logout, isLoggedIn, getSessionAccountId, } from './express.js';
|
|
1
|
+
export { handshakeMiddleware, login, logout, isLoggedIn, getSessionAccountId, requireAuth, requireGuest, } from './express.js';
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/middleware/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,KAAK,EACL,MAAM,EACN,UAAU,EACV,mBAAmB,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/middleware/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,KAAK,EACL,MAAM,EACN,UAAU,EACV,mBAAmB,EACnB,WAAW,EACX,YAAY,GACb,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import type { OAuthProfile } from '../types.js';
|
|
2
|
+
import { OAuthStrategy } from './oauth-base.js';
|
|
3
|
+
/**
|
|
4
|
+
* Discord user profile from the /users/@me endpoint.
|
|
5
|
+
*/
|
|
6
|
+
export interface DiscordProfile {
|
|
7
|
+
id: string;
|
|
8
|
+
username: string;
|
|
9
|
+
discriminator: string;
|
|
10
|
+
global_name?: string | null;
|
|
11
|
+
avatar?: string | null;
|
|
12
|
+
bot?: boolean;
|
|
13
|
+
system?: boolean;
|
|
14
|
+
mfa_enabled?: boolean;
|
|
15
|
+
banner?: string | null;
|
|
16
|
+
accent_color?: number | null;
|
|
17
|
+
locale?: string;
|
|
18
|
+
verified?: boolean;
|
|
19
|
+
email?: string | null;
|
|
20
|
+
flags?: number;
|
|
21
|
+
premium_type?: number;
|
|
22
|
+
public_flags?: number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Configuration options for Discord OAuth strategy.
|
|
26
|
+
*/
|
|
27
|
+
export interface DiscordStrategyOptions {
|
|
28
|
+
/**
|
|
29
|
+
* Discord OAuth client ID
|
|
30
|
+
*/
|
|
31
|
+
clientId: string;
|
|
32
|
+
/**
|
|
33
|
+
* Discord OAuth client secret
|
|
34
|
+
*/
|
|
35
|
+
clientSecret: string;
|
|
36
|
+
/**
|
|
37
|
+
* Your callback URL (must match Discord Developer Portal configuration)
|
|
38
|
+
*/
|
|
39
|
+
redirectUri: string;
|
|
40
|
+
/**
|
|
41
|
+
* OAuth scopes to request
|
|
42
|
+
* @default ['identify', 'email']
|
|
43
|
+
*/
|
|
44
|
+
scopes?: string[];
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Discord OAuth2 authentication strategy.
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```typescript
|
|
51
|
+
* const hs = new Handshake({
|
|
52
|
+
* findAccount: async (email) => db.accounts.findByEmail(email),
|
|
53
|
+
* findOrCreateFromOAuth: async (provider, profile) => {
|
|
54
|
+
* let account = await db.accounts.findByProviderId(provider, profile.id);
|
|
55
|
+
* if (!account) {
|
|
56
|
+
* account = await db.accounts.create({
|
|
57
|
+
* email: profile.email,
|
|
58
|
+
* name: profile.name,
|
|
59
|
+
* providerId: profile.id,
|
|
60
|
+
* provider,
|
|
61
|
+
* });
|
|
62
|
+
* }
|
|
63
|
+
* return account;
|
|
64
|
+
* },
|
|
65
|
+
* });
|
|
66
|
+
*
|
|
67
|
+
* hs.use(new DiscordStrategy({
|
|
68
|
+
* clientId: process.env.DISCORD_CLIENT_ID!,
|
|
69
|
+
* clientSecret: process.env.DISCORD_CLIENT_SECRET!,
|
|
70
|
+
* redirectUri: 'http://localhost:3000/auth/discord/callback',
|
|
71
|
+
* }));
|
|
72
|
+
*
|
|
73
|
+
* // Routes
|
|
74
|
+
* app.get('/auth/discord', async (req, res) => {
|
|
75
|
+
* const result = await hs.authenticate('discord', req, res, 'redirect');
|
|
76
|
+
* if ('redirectUrl' in result) {
|
|
77
|
+
* res.redirect(result.redirectUrl);
|
|
78
|
+
* }
|
|
79
|
+
* });
|
|
80
|
+
*
|
|
81
|
+
* app.get('/auth/discord/callback', async (req, res) => {
|
|
82
|
+
* const result = await hs.authenticate('discord', req, res, 'callback');
|
|
83
|
+
* if (result.account) {
|
|
84
|
+
* login(req, result.account);
|
|
85
|
+
* res.redirect('/dashboard');
|
|
86
|
+
* } else {
|
|
87
|
+
* res.status(401).send(result.error);
|
|
88
|
+
* }
|
|
89
|
+
* });
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
export declare class DiscordStrategy<TAccount> extends OAuthStrategy<TAccount> {
|
|
93
|
+
constructor(options: DiscordStrategyOptions);
|
|
94
|
+
/**
|
|
95
|
+
* Map Discord profile to standard OAuthProfile.
|
|
96
|
+
*/
|
|
97
|
+
protected mapProfile(data: unknown, accessToken: string): OAuthProfile;
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=discord.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discord.d.ts","sourceRoot":"","sources":["../../src/strategies/discord.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,YAAY,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,qBAAa,eAAe,CAAC,QAAQ,CAAE,SAAQ,aAAa,CAAC,QAAQ,CAAC;gBACxD,OAAO,EAAE,sBAAsB;IAc3C;;OAEG;IAEH,SAAS,CAAC,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,GAAG,YAAY;CAqBvE"}
|