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.
Files changed (54) hide show
  1. package/ReadMe.md +230 -16
  2. package/dist/index.d.ts +18 -2
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +11 -1
  5. package/dist/index.js.map +1 -1
  6. package/dist/middleware/express.d.ts +67 -0
  7. package/dist/middleware/express.d.ts.map +1 -1
  8. package/dist/middleware/express.js +69 -0
  9. package/dist/middleware/express.js.map +1 -1
  10. package/dist/middleware/index.d.ts +2 -2
  11. package/dist/middleware/index.d.ts.map +1 -1
  12. package/dist/middleware/index.js +1 -1
  13. package/dist/middleware/index.js.map +1 -1
  14. package/dist/strategies/discord.d.ts +99 -0
  15. package/dist/strategies/discord.d.ts.map +1 -0
  16. package/dist/strategies/discord.js +85 -0
  17. package/dist/strategies/discord.js.map +1 -0
  18. package/dist/strategies/github.d.ts +112 -0
  19. package/dist/strategies/github.d.ts.map +1 -0
  20. package/dist/strategies/github.js +110 -0
  21. package/dist/strategies/github.js.map +1 -0
  22. package/dist/strategies/google.d.ts +91 -0
  23. package/dist/strategies/google.d.ts.map +1 -0
  24. package/dist/strategies/google.js +77 -0
  25. package/dist/strategies/google.js.map +1 -0
  26. package/dist/strategies/index.d.ts +16 -0
  27. package/dist/strategies/index.d.ts.map +1 -1
  28. package/dist/strategies/index.js +10 -0
  29. package/dist/strategies/index.js.map +1 -1
  30. package/dist/strategies/magic-link.d.ts +141 -0
  31. package/dist/strategies/magic-link.d.ts.map +1 -0
  32. package/dist/strategies/magic-link.js +186 -0
  33. package/dist/strategies/magic-link.js.map +1 -0
  34. package/dist/strategies/microsoft.d.ts +127 -0
  35. package/dist/strategies/microsoft.d.ts.map +1 -0
  36. package/dist/strategies/microsoft.js +98 -0
  37. package/dist/strategies/microsoft.js.map +1 -0
  38. package/dist/strategies/oauth-base.d.ts +162 -0
  39. package/dist/strategies/oauth-base.d.ts.map +1 -0
  40. package/dist/strategies/oauth-base.js +243 -0
  41. package/dist/strategies/oauth-base.js.map +1 -0
  42. package/dist/strategies/password.d.ts +69 -6
  43. package/dist/strategies/password.d.ts.map +1 -1
  44. package/dist/strategies/password.js +73 -24
  45. package/dist/strategies/password.js.map +1 -1
  46. package/dist/strategies/twitter-x.d.ts +130 -0
  47. package/dist/strategies/twitter-x.d.ts.map +1 -0
  48. package/dist/strategies/twitter-x.js +275 -0
  49. package/dist/strategies/twitter-x.js.map +1 -0
  50. package/dist/strategies/username-password.d.ts +38 -0
  51. package/dist/strategies/username-password.d.ts.map +1 -0
  52. package/dist/strategies/username-password.js +61 -0
  53. package/dist/strategies/username-password.js.map +1 -0
  54. 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** - Password, Magic Link, Google OAuth, GitHub OAuth
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, PasswordStrategy } from 'handshake-auth';
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 PasswordStrategy());
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
- PasswordStrategy,
111
+ UsernamePasswordStrategy,
80
112
  handshakeMiddleware,
81
113
  login,
82
114
  logout,
83
- isLoggedIn,
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 PasswordStrategy());
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 { handshakeMiddleware, login, logout, isLoggedIn, getSessionAccountId, } from './middleware/index.js';
5
- export type { HandshakeSession, RequestWithAuth } from './middleware/index.js';
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
@@ -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;AAGzD,OAAO,EACL,mBAAmB,EACnB,KAAK,EACL,MAAM,EACN,UAAU,EACV,mBAAmB,GACpB,MAAM,uBAAuB,CAAC;AAE/B,YAAY,EAAE,gBAAgB,EAAE,eAAe,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,GACpB,MAAM,uBAAuB,CAAC"}
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,GACpB,MAAM,cAAc,CAAC;AAEtB,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC"}
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"}
@@ -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,GACpB,MAAM,cAAc,CAAC"}
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"}