@soapjs/soap-auth 0.4.4 → 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/README.md +261 -128
- package/build/index.d.ts +1 -0
- package/build/index.js +1 -0
- package/build/recipes/auth-config.recipes.d.ts +40 -0
- package/build/recipes/auth-config.recipes.js +135 -0
- package/build/recipes/http-context.helpers.d.ts +13 -0
- package/build/recipes/http-context.helpers.js +64 -0
- package/build/recipes/index.d.ts +3 -0
- package/build/recipes/index.js +19 -0
- package/build/recipes/oauth2-presets.d.ts +20 -0
- package/build/recipes/oauth2-presets.js +74 -0
- package/build/soap-auth.js +62 -0
- package/build/strategies/oauth2/hybrid.oauth2.strategy.js +1 -1
- package/build/strategies/oauth2/oauth2.strategy.js +2 -2
- package/build/strategies/oauth2/oauth2.types.d.ts +5 -0
- package/build/strategies/oauth2/providers/configurable-hybrid-oauth2.strategy.d.ts +19 -0
- package/build/strategies/oauth2/providers/configurable-hybrid-oauth2.strategy.js +85 -0
- package/build/strategies/oauth2/providers/configurable-oauth2.strategy.d.ts +11 -0
- package/build/strategies/oauth2/providers/configurable-oauth2.strategy.js +46 -0
- package/build/strategies/oauth2/providers/index.d.ts +2 -0
- package/build/strategies/oauth2/providers/index.js +2 -0
- package/build/strategies/oauth2/providers/provider.types.d.ts +3 -0
- package/build/types.d.ts +5 -2
- package/package.json +90 -12
- package/.claude/settings.local.json +0 -20
- package/jest.config.unit.json +0 -10
package/README.md
CHANGED
|
@@ -1,174 +1,307 @@
|
|
|
1
|
-
# SoapAuth
|
|
1
|
+
# SoapAuth
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Authentication strategies, session handling, MFA, and token helpers for the SoapJS ecosystem.
|
|
4
|
+
|
|
5
|
+
`@soapjs/soap-auth` provides composable authentication primitives for HTTP and socket applications. It includes JWT, local credentials, basic auth, API key auth, built-in OAuth2 social providers, sessions, roles, rate limiting, account lockout, password helpers, MFA/TOTP, PKCE, and JWKS verification.
|
|
6
|
+
|
|
7
|
+
The package does not depend on Passport or provider SDKs. Built-in and configurable OAuth2 strategies use platform `fetch` plus user-provided mapping callbacks, so applications can start quickly and still replace any part of the auth flow with their own implementation.
|
|
4
8
|
|
|
5
9
|
## Installation
|
|
10
|
+
|
|
6
11
|
```sh
|
|
7
|
-
npm install @soapjs/soap-auth
|
|
12
|
+
npm install @soapjs/soap-auth @soapjs/soap
|
|
8
13
|
```
|
|
9
14
|
|
|
10
|
-
##
|
|
11
|
-
- **Supports multiple authentication strategies** (JWT, OAuth2, API Key, Basic, Local, Hybrid OAuth2).
|
|
12
|
-
- **Works with both HTTP and WebSocket protocols.**
|
|
13
|
-
- **Manages sessions, MFA, roles, account locks, and rate limiting.**
|
|
14
|
-
- **Easy configuration and extendability.**
|
|
15
|
-
- **Integration with frameworks like Express, NestJS, etc.**
|
|
15
|
+
## Requirements
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
- Node.js 24.17.0 or newer
|
|
18
|
+
- `@soapjs/soap` 0.12 or newer
|
|
18
19
|
|
|
19
|
-
##
|
|
20
|
-
```typescript
|
|
21
|
-
import { SoapAuth, JwtStrategy } from "@soapjs/soap-auth";
|
|
20
|
+
## Quick Start
|
|
22
21
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
// ...
|
|
26
|
-
const result = await auth.getHttpStrategy<JwtStrategy>("jwt").authenticate(request);
|
|
27
|
-
console.log(result.user);
|
|
28
|
-
```
|
|
22
|
+
```ts
|
|
23
|
+
import { createJwtAuthConfig, SoapAuth } from "@soapjs/soap-auth";
|
|
29
24
|
|
|
30
|
-
|
|
25
|
+
const auth = await SoapAuth.create({
|
|
26
|
+
http: {
|
|
27
|
+
jwt: createJwtAuthConfig({
|
|
28
|
+
accessSecret: process.env.JWT_ACCESS_SECRET!,
|
|
29
|
+
refreshSecret: process.env.JWT_REFRESH_SECRET!,
|
|
30
|
+
user: {
|
|
31
|
+
fetchUser: async (payload) => users.findById((payload as any).id),
|
|
32
|
+
},
|
|
33
|
+
}),
|
|
34
|
+
},
|
|
35
|
+
});
|
|
31
36
|
|
|
32
|
-
|
|
37
|
+
const result = await auth.getHttpStrategy("jwt").authenticate(context);
|
|
38
|
+
```
|
|
33
39
|
|
|
34
|
-
|
|
40
|
+
## Recipes
|
|
35
41
|
|
|
36
|
-
|
|
37
|
-
```typescript
|
|
38
|
-
import { JwtStrategy } from "@soapjs/soap-auth";
|
|
42
|
+
Recipes are framework-neutral config helpers. They return plain SoapAuth config objects and do not import Express, Passport, provider SDKs, or any other adapter library.
|
|
39
43
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
44
|
+
```ts
|
|
45
|
+
import {
|
|
46
|
+
createApiKeyAuthConfig,
|
|
47
|
+
createHybridOAuth2ProviderConfig,
|
|
48
|
+
createJwtAuthConfig,
|
|
49
|
+
createLocalAuthConfig,
|
|
50
|
+
createOAuth2ProviderConfig,
|
|
51
|
+
oauth2ProviderEndpoints,
|
|
52
|
+
} from "@soapjs/soap-auth";
|
|
49
53
|
```
|
|
50
54
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
55
|
+
Available recipes:
|
|
56
|
+
|
|
57
|
+
- `createJwtAuthConfig(...)`
|
|
58
|
+
- `createLocalAuthConfig(...)`
|
|
59
|
+
- `createBasicAuthConfig(...)`
|
|
60
|
+
- `createApiKeyAuthConfig(...)`
|
|
61
|
+
- `createOAuth2ProviderConfig(...)`
|
|
62
|
+
- `createHybridOAuth2ProviderConfig(...)`
|
|
63
|
+
- `oauth2ProviderEndpoints.auth0(...)`
|
|
64
|
+
- `oauth2ProviderEndpoints.keycloak(...)`
|
|
65
|
+
- `oauth2ProviderEndpoints.discord()`
|
|
66
|
+
- `oauth2ProviderEndpoints.google()`
|
|
67
|
+
- `oauth2ProviderEndpoints.github()`
|
|
68
|
+
- `oauth2ProviderEndpoints.facebook()`
|
|
69
|
+
|
|
70
|
+
Recipes are also available from `@soapjs/soap-auth/recipes`.
|
|
71
|
+
|
|
72
|
+
## Factory Configuration
|
|
73
|
+
|
|
74
|
+
`SoapAuth.create()` registers built-in strategies from config:
|
|
75
|
+
|
|
76
|
+
- `http.jwt` as `jwt`
|
|
77
|
+
- `http.local` as `local`
|
|
78
|
+
- `http.basic` as `basic`
|
|
79
|
+
- `http.apiKey` as `api-key`
|
|
80
|
+
- `http.oauth2.google` as `google`
|
|
81
|
+
- `http.oauth2.github` as `github`
|
|
82
|
+
- `http.oauth2.facebook` as `facebook`
|
|
83
|
+
- any other `http.oauth2.<name>` with OAuth2 endpoints as `<name>`
|
|
84
|
+
- any `http.hybridOAuth2.<name>` with OAuth2 endpoints as `<name>`
|
|
85
|
+
- `socket.jwt` as `jwt`
|
|
86
|
+
- `socket.apiKey` as `api-key`
|
|
87
|
+
|
|
88
|
+
Custom strategies can be registered through `http.custom`, `socket.custom`, or manually with `addStrategy(strategy, name, category)`.
|
|
89
|
+
|
|
90
|
+
## Local Credentials
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
import { createLocalAuthConfig } from "@soapjs/soap-auth";
|
|
94
|
+
|
|
95
|
+
const auth = await SoapAuth.create({
|
|
96
|
+
http: {
|
|
97
|
+
local: createLocalAuthConfig({
|
|
98
|
+
credentials: {
|
|
99
|
+
extractCredentials: (ctx: any) => ({
|
|
100
|
+
identifier: ctx.body.email,
|
|
101
|
+
password: ctx.body.password,
|
|
102
|
+
}),
|
|
103
|
+
verifyCredentials: async (identifier, password) =>
|
|
104
|
+
users.verifyPassword(identifier, password),
|
|
105
|
+
},
|
|
106
|
+
user: {
|
|
107
|
+
fetchUser: async (identifier) => users.findByEmail(String(identifier)),
|
|
108
|
+
},
|
|
109
|
+
basePath: "/auth",
|
|
110
|
+
}),
|
|
62
111
|
},
|
|
63
|
-
})
|
|
112
|
+
});
|
|
64
113
|
```
|
|
65
114
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
115
|
+
## API Key
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
import { createApiKeyAuthConfig } from "@soapjs/soap-auth";
|
|
69
119
|
|
|
70
|
-
auth.
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
120
|
+
const auth = await SoapAuth.create({
|
|
121
|
+
http: {
|
|
122
|
+
apiKey: createApiKeyAuthConfig({
|
|
123
|
+
keyType: "long-term",
|
|
124
|
+
extractApiKey: (ctx: any) => ctx.headers["x-api-key"] ?? null,
|
|
125
|
+
retrieveUserByApiKey: async (apiKey) => apiKeys.findUser(apiKey),
|
|
126
|
+
isApiKeyExpired: async (apiKey) => apiKeys.isExpired(apiKey),
|
|
127
|
+
trackApiKeyUsage: async (apiKey) => apiKeys.touch(apiKey),
|
|
128
|
+
}),
|
|
74
129
|
},
|
|
75
|
-
})
|
|
130
|
+
});
|
|
76
131
|
```
|
|
77
132
|
|
|
78
|
-
|
|
79
|
-
```typescript
|
|
80
|
-
import { BasicStrategy } from "@soapjs/soap-auth";
|
|
133
|
+
## Sessions
|
|
81
134
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
135
|
+
```ts
|
|
136
|
+
import { MemorySessionStore, SoapAuth } from "@soapjs/soap-auth";
|
|
137
|
+
|
|
138
|
+
const auth = await SoapAuth.create({
|
|
139
|
+
session: {
|
|
140
|
+
secret: process.env.SESSION_SECRET!,
|
|
141
|
+
store: new MemorySessionStore(),
|
|
142
|
+
getSessionId: (ctx: any) =>
|
|
143
|
+
ctx.cookies?.SESSIONID ?? ctx.headers?.["x-session-id"] ?? null,
|
|
85
144
|
},
|
|
86
|
-
|
|
87
|
-
|
|
145
|
+
http: {
|
|
146
|
+
local: localConfig,
|
|
88
147
|
},
|
|
89
|
-
})
|
|
148
|
+
});
|
|
90
149
|
```
|
|
91
150
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
151
|
+
`MemorySessionStore` is useful for tests and local development. Production applications should provide a durable `SessionStore` backed by a database, Redis, or another shared storage system.
|
|
152
|
+
|
|
153
|
+
## OAuth2 Providers
|
|
95
154
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
155
|
+
```ts
|
|
156
|
+
const auth = await SoapAuth.create({
|
|
157
|
+
http: {
|
|
158
|
+
oauth2: {
|
|
159
|
+
google: {
|
|
160
|
+
clientId: process.env.GOOGLE_CLIENT_ID!,
|
|
161
|
+
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
|
|
162
|
+
redirectUri: "https://example.com/auth/google/callback",
|
|
163
|
+
},
|
|
164
|
+
github: {
|
|
165
|
+
clientId: process.env.GITHUB_CLIENT_ID!,
|
|
166
|
+
clientSecret: process.env.GITHUB_CLIENT_SECRET!,
|
|
167
|
+
redirectUri: "https://example.com/auth/github/callback",
|
|
168
|
+
},
|
|
169
|
+
},
|
|
100
170
|
},
|
|
101
|
-
})
|
|
171
|
+
});
|
|
102
172
|
```
|
|
103
173
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
174
|
+
Providers with standard OAuth2/OIDC endpoints can use configurable OAuth2. Providers with unusual token exchange, user lookup, or redirect requirements can be implemented as a subclass of `OAuth2Strategy` or `HttpOAuth2Strategy` and registered through `http.custom`.
|
|
175
|
+
|
|
176
|
+
## Configurable OAuth2 Providers
|
|
177
|
+
|
|
178
|
+
Most OAuth2/OIDC providers do not need a custom class. Provide the endpoints and a profile mapper:
|
|
179
|
+
|
|
180
|
+
```ts
|
|
181
|
+
import { createOAuth2ProviderConfig } from "@soapjs/soap-auth";
|
|
182
|
+
|
|
183
|
+
const auth = await SoapAuth.create({
|
|
184
|
+
http: {
|
|
185
|
+
oauth2: {
|
|
186
|
+
auth0: createOAuth2ProviderConfig({
|
|
187
|
+
provider: "auth0",
|
|
188
|
+
clientId: process.env.AUTH0_CLIENT_ID!,
|
|
189
|
+
clientSecret: process.env.AUTH0_CLIENT_SECRET!,
|
|
190
|
+
redirectUri: "https://example.com/auth/auth0/callback",
|
|
191
|
+
presetOptions: { domain: "tenant.auth0.com" },
|
|
192
|
+
user: {
|
|
193
|
+
fetchUser: async () => null,
|
|
194
|
+
validateUser: async (profile: any) => ({
|
|
195
|
+
id: profile.sub,
|
|
196
|
+
email: profile.email,
|
|
197
|
+
username: profile.nickname ?? profile.name,
|
|
198
|
+
picture: profile.picture,
|
|
199
|
+
}),
|
|
200
|
+
},
|
|
201
|
+
}),
|
|
115
202
|
},
|
|
116
203
|
},
|
|
117
|
-
})
|
|
204
|
+
});
|
|
118
205
|
```
|
|
119
206
|
|
|
120
|
-
|
|
207
|
+
For providers without a `userinfo` endpoint, implement `user.fetchUser(accessToken)` and return your application user directly.
|
|
121
208
|
|
|
122
|
-
##
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
209
|
+
## Configurable Hybrid OAuth2
|
|
210
|
+
|
|
211
|
+
Hybrid OAuth2 tries existing JWT/session auth first, then falls back to OAuth2. This is useful when browser users log in through OAuth2 but API clients can keep using JWT.
|
|
212
|
+
|
|
213
|
+
```ts
|
|
214
|
+
import { createHybridOAuth2ProviderConfig } from "@soapjs/soap-auth";
|
|
215
|
+
|
|
216
|
+
const auth = await SoapAuth.create({
|
|
217
|
+
session: sessionConfig,
|
|
218
|
+
http: {
|
|
219
|
+
jwt: jwtConfig,
|
|
220
|
+
hybridOAuth2: {
|
|
221
|
+
enterprise: createHybridOAuth2ProviderConfig({
|
|
222
|
+
provider: "enterprise",
|
|
223
|
+
clientId: process.env.IDP_CLIENT_ID!,
|
|
224
|
+
clientSecret: process.env.IDP_CLIENT_SECRET!,
|
|
225
|
+
redirectUri: "https://example.com/auth/enterprise/callback",
|
|
226
|
+
endpoints: {
|
|
227
|
+
authorizationUrl: "https://idp.example.com/authorize",
|
|
228
|
+
tokenUrl: "https://idp.example.com/token",
|
|
229
|
+
userInfoUrl: "https://idp.example.com/userinfo",
|
|
230
|
+
},
|
|
231
|
+
user: {
|
|
232
|
+
fetchUser: async () => null,
|
|
233
|
+
validateUser: async (profile: any) => ({
|
|
234
|
+
id: profile.sub,
|
|
235
|
+
email: profile.email,
|
|
236
|
+
}),
|
|
237
|
+
},
|
|
238
|
+
}),
|
|
239
|
+
},
|
|
240
|
+
},
|
|
241
|
+
});
|
|
143
242
|
```
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
243
|
+
|
|
244
|
+
## Custom Strategies
|
|
245
|
+
|
|
246
|
+
When the built-in config is not enough, implement `AuthStrategy` directly:
|
|
247
|
+
|
|
248
|
+
```ts
|
|
249
|
+
const auth = await SoapAuth.create({
|
|
250
|
+
http: {
|
|
251
|
+
custom: {
|
|
252
|
+
internal: {
|
|
253
|
+
async authenticate(ctx: any) {
|
|
254
|
+
const user = await internalAuth.verify(ctx.headers.authorization);
|
|
255
|
+
return user ? { user } : null;
|
|
256
|
+
},
|
|
257
|
+
},
|
|
258
|
+
},
|
|
259
|
+
},
|
|
260
|
+
});
|
|
149
261
|
```
|
|
150
262
|
|
|
151
|
-
|
|
263
|
+
No external strategy package is required; custom strategies only need an `authenticate(context)` method.
|
|
264
|
+
|
|
265
|
+
## MFA, Roles, Rate Limits, and Lockout
|
|
152
266
|
|
|
153
|
-
|
|
154
|
-
**How to report an issue?**
|
|
155
|
-
Open an issue on GitHub.
|
|
267
|
+
Shared controls can be attached to credential strategies:
|
|
156
268
|
|
|
157
|
-
|
|
158
|
-
|
|
269
|
+
```ts
|
|
270
|
+
const localConfig = {
|
|
271
|
+
credentials,
|
|
272
|
+
user,
|
|
273
|
+
routes,
|
|
274
|
+
mfa: {
|
|
275
|
+
isMfaRequired: (user: any) => user.mfaEnabled,
|
|
276
|
+
extractMfaCode: (ctx: any) => ctx.body.mfaCode,
|
|
277
|
+
validateMfaCode: async (user: any, code: string) =>
|
|
278
|
+
mfa.verify(user.id, code),
|
|
279
|
+
},
|
|
280
|
+
role: {
|
|
281
|
+
roles: ["admin"],
|
|
282
|
+
authorizeByRoles: async (user: any, roles: string[]) =>
|
|
283
|
+
roles.includes(user.role),
|
|
284
|
+
},
|
|
285
|
+
rateLimit: {
|
|
286
|
+
checkRateLimit: async (ctx: any) => rateLimiter.isLimited(ctx.ip),
|
|
287
|
+
incrementRequestCount: async (ctx: any) => rateLimiter.increment(ctx.ip),
|
|
288
|
+
},
|
|
289
|
+
};
|
|
290
|
+
```
|
|
159
291
|
|
|
160
|
-
|
|
161
|
-
## Issues
|
|
162
|
-
If you encounter any issues, please feel free to report them [here](https://github.com/soapjs/soap/issues/new/choose).
|
|
292
|
+
## Release Checks
|
|
163
293
|
|
|
164
|
-
|
|
165
|
-
|
|
294
|
+
Before publishing:
|
|
295
|
+
|
|
296
|
+
```sh
|
|
297
|
+
npm run test:unit
|
|
298
|
+
npm run build
|
|
299
|
+
npm pack --dry-run
|
|
300
|
+
npm audit --omit=dev
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
The package publishes compiled CommonJS output from `build/` and TypeScript declarations.
|
|
166
304
|
|
|
167
|
-
- Official:
|
|
168
|
-
- Website: http://docs.soapjs.com
|
|
169
|
-
- Radoslaw Kamysz:
|
|
170
|
-
- Email: [radoslaw.kamysz@gmail.com](mailto:radoslaw.kamysz@gmail.com)
|
|
171
|
-
- Warpcast: [@k4mr4ad](https://warpcast.com/k4mr4ad)
|
|
172
|
-
- Twitter: [@radoslawkamysz](https://x.com/radoslawkamysz)
|
|
173
305
|
## License
|
|
174
|
-
|
|
306
|
+
|
|
307
|
+
MIT
|
package/build/index.d.ts
CHANGED
package/build/index.js
CHANGED
|
@@ -18,6 +18,7 @@ __exportStar(require("./session"), exports);
|
|
|
18
18
|
__exportStar(require("./services"), exports);
|
|
19
19
|
__exportStar(require("./strategies"), exports);
|
|
20
20
|
__exportStar(require("./tools"), exports);
|
|
21
|
+
__exportStar(require("./recipes"), exports);
|
|
21
22
|
__exportStar(require("./errors"), exports);
|
|
22
23
|
__exportStar(require("./types"), exports);
|
|
23
24
|
__exportStar(require("./soap-auth"), exports);
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { ApiKeyStrategyConfig } from "../strategies/api-key/api-key.types";
|
|
2
|
+
import { BasicStrategyConfig } from "../strategies/basic/basic.types";
|
|
3
|
+
import { JwtConfig } from "../strategies/jwt/jwt.types";
|
|
4
|
+
import { LocalStrategyConfig } from "../strategies/local/local.types";
|
|
5
|
+
import { OAuth2ProviderConfig } from "../strategies/oauth2/oauth2.types";
|
|
6
|
+
import { Auth0PresetOptions, FacebookPresetOptions, KeycloakPresetOptions, OAuth2ProviderPreset } from "./oauth2-presets";
|
|
7
|
+
import { AuthRouteConfig, TokenIssuerConfig, UserConfig } from "../types";
|
|
8
|
+
import { OAuth2Endpoints } from "../strategies/oauth2/oauth2.types";
|
|
9
|
+
type RouteOverrides = Partial<Record<string, Partial<AuthRouteConfig>>>;
|
|
10
|
+
export interface JwtAuthRecipeOptions<TContext = unknown, TUser = unknown> extends Omit<Partial<JwtConfig<TContext, TUser>>, "accessToken" | "refreshToken" | "routes"> {
|
|
11
|
+
accessSecret: string;
|
|
12
|
+
refreshSecret?: string;
|
|
13
|
+
accessToken?: Partial<TokenIssuerConfig<TContext>>;
|
|
14
|
+
refreshToken?: Partial<TokenIssuerConfig<TContext>>;
|
|
15
|
+
user?: UserConfig<TUser>;
|
|
16
|
+
routes?: RouteOverrides;
|
|
17
|
+
}
|
|
18
|
+
export declare function createJwtAuthConfig<TContext = unknown, TUser = unknown>(options: JwtAuthRecipeOptions<TContext, TUser>): JwtConfig<TContext, TUser>;
|
|
19
|
+
export interface LocalAuthRecipeOptions<TContext = unknown, TUser = unknown> extends Omit<LocalStrategyConfig<TContext, TUser>, "routes"> {
|
|
20
|
+
basePath?: string;
|
|
21
|
+
routes?: RouteOverrides;
|
|
22
|
+
}
|
|
23
|
+
export declare function createLocalAuthConfig<TContext = unknown, TUser = unknown>(options: LocalAuthRecipeOptions<TContext, TUser>): LocalStrategyConfig<TContext, TUser>;
|
|
24
|
+
export interface BasicAuthRecipeOptions<TContext = unknown, TUser = unknown> extends Omit<BasicStrategyConfig<TContext, TUser>, "routes"> {
|
|
25
|
+
basePath?: string;
|
|
26
|
+
routes?: RouteOverrides;
|
|
27
|
+
}
|
|
28
|
+
export declare function createBasicAuthConfig<TContext = unknown, TUser = unknown>(options: BasicAuthRecipeOptions<TContext, TUser>): BasicStrategyConfig<TContext, TUser>;
|
|
29
|
+
export interface ApiKeyAuthRecipeOptions<TContext = unknown, TUser = unknown> extends ApiKeyStrategyConfig<TContext, TUser> {
|
|
30
|
+
}
|
|
31
|
+
export declare function createApiKeyAuthConfig<TContext = unknown, TUser = unknown>(options: ApiKeyAuthRecipeOptions<TContext, TUser>): ApiKeyStrategyConfig<TContext, TUser>;
|
|
32
|
+
export interface OAuth2AuthRecipeOptions<TUser = unknown> extends Omit<OAuth2ProviderConfig<any, TUser>, "endpoints" | "routes"> {
|
|
33
|
+
provider: OAuth2ProviderPreset | string;
|
|
34
|
+
endpoints?: OAuth2Endpoints;
|
|
35
|
+
presetOptions?: Auth0PresetOptions | KeycloakPresetOptions | FacebookPresetOptions;
|
|
36
|
+
routes?: RouteOverrides;
|
|
37
|
+
}
|
|
38
|
+
export declare function createOAuth2ProviderConfig<TUser = unknown>(options: OAuth2AuthRecipeOptions<TUser>): OAuth2ProviderConfig<any, TUser>;
|
|
39
|
+
export declare function createHybridOAuth2ProviderConfig<TUser = unknown>(options: OAuth2AuthRecipeOptions<TUser>): OAuth2ProviderConfig<any, TUser>;
|
|
40
|
+
export {};
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createHybridOAuth2ProviderConfig = exports.createOAuth2ProviderConfig = exports.createApiKeyAuthConfig = exports.createBasicAuthConfig = exports.createLocalAuthConfig = exports.createJwtAuthConfig = void 0;
|
|
4
|
+
const oauth2_presets_1 = require("./oauth2-presets");
|
|
5
|
+
function route(path, method, override) {
|
|
6
|
+
return {
|
|
7
|
+
path: override?.path ?? path,
|
|
8
|
+
method: override?.method ?? method,
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
function credentialRoutes(basePath, overrides = {}) {
|
|
12
|
+
return {
|
|
13
|
+
login: route(`${basePath}/login`, "POST", overrides.login),
|
|
14
|
+
logout: route(`${basePath}/logout`, "POST", overrides.logout),
|
|
15
|
+
resetPassword: overrides.resetPassword
|
|
16
|
+
? route(`${basePath}/password/reset`, "POST", overrides.resetPassword)
|
|
17
|
+
: undefined,
|
|
18
|
+
changePassword: overrides.changePassword
|
|
19
|
+
? route(`${basePath}/password/change`, "POST", overrides.changePassword)
|
|
20
|
+
: undefined,
|
|
21
|
+
requestPasswordReset: overrides.requestPasswordReset
|
|
22
|
+
? route(`${basePath}/password/reset/request`, "POST", overrides.requestPasswordReset)
|
|
23
|
+
: undefined,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
function oauthRoutes(basePath, overrides = {}) {
|
|
27
|
+
return {
|
|
28
|
+
login: route(basePath, "GET", overrides.login),
|
|
29
|
+
callback: route(`${basePath}/callback`, "GET", overrides.callback),
|
|
30
|
+
logout: overrides.logout
|
|
31
|
+
? route(`${basePath}/logout`, "POST", overrides.logout)
|
|
32
|
+
: undefined,
|
|
33
|
+
refresh: overrides.refresh
|
|
34
|
+
? route(`${basePath}/refresh`, "POST", overrides.refresh)
|
|
35
|
+
: undefined,
|
|
36
|
+
revoke: overrides.revoke
|
|
37
|
+
? route(`${basePath}/revoke`, "POST", overrides.revoke)
|
|
38
|
+
: undefined,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function createJwtAuthConfig(options) {
|
|
42
|
+
const { accessSecret, refreshSecret, accessToken, refreshToken, routes, ...config } = options;
|
|
43
|
+
return {
|
|
44
|
+
...config,
|
|
45
|
+
user: options.user,
|
|
46
|
+
accessToken: {
|
|
47
|
+
issuer: {
|
|
48
|
+
secretKey: accessSecret,
|
|
49
|
+
options: {
|
|
50
|
+
expiresIn: "15m",
|
|
51
|
+
...(accessToken?.options ?? {}),
|
|
52
|
+
},
|
|
53
|
+
buildPayload: accessToken?.buildPayload,
|
|
54
|
+
},
|
|
55
|
+
verifier: { options: {} },
|
|
56
|
+
},
|
|
57
|
+
refreshToken: refreshSecret
|
|
58
|
+
? {
|
|
59
|
+
issuer: {
|
|
60
|
+
secretKey: refreshSecret,
|
|
61
|
+
options: {
|
|
62
|
+
expiresIn: "7d",
|
|
63
|
+
...(refreshToken?.options ?? {}),
|
|
64
|
+
},
|
|
65
|
+
buildPayload: refreshToken?.buildPayload,
|
|
66
|
+
},
|
|
67
|
+
verifier: { options: {} },
|
|
68
|
+
}
|
|
69
|
+
: undefined,
|
|
70
|
+
routes: {
|
|
71
|
+
login: route("/auth/jwt/login", "POST", routes?.login),
|
|
72
|
+
logout: route("/auth/jwt/logout", "POST", routes?.logout),
|
|
73
|
+
refresh: route("/auth/jwt/refresh", "POST", routes?.refresh),
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
exports.createJwtAuthConfig = createJwtAuthConfig;
|
|
78
|
+
function createLocalAuthConfig(options) {
|
|
79
|
+
const { basePath, routes, ...config } = options;
|
|
80
|
+
return {
|
|
81
|
+
...config,
|
|
82
|
+
routes: credentialRoutes(basePath ?? "/auth/local", routes),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
exports.createLocalAuthConfig = createLocalAuthConfig;
|
|
86
|
+
function createBasicAuthConfig(options) {
|
|
87
|
+
const { basePath, routes, ...config } = options;
|
|
88
|
+
return {
|
|
89
|
+
...config,
|
|
90
|
+
routes: credentialRoutes(basePath ?? "/auth/basic", routes),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
exports.createBasicAuthConfig = createBasicAuthConfig;
|
|
94
|
+
function createApiKeyAuthConfig(options) {
|
|
95
|
+
return {
|
|
96
|
+
keyType: "long-term",
|
|
97
|
+
...options,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
exports.createApiKeyAuthConfig = createApiKeyAuthConfig;
|
|
101
|
+
function resolveOAuth2Endpoints(options) {
|
|
102
|
+
if (options.endpoints) {
|
|
103
|
+
return options.endpoints;
|
|
104
|
+
}
|
|
105
|
+
switch (options.provider) {
|
|
106
|
+
case "auth0":
|
|
107
|
+
return oauth2_presets_1.oauth2ProviderEndpoints.auth0(options.presetOptions);
|
|
108
|
+
case "keycloak":
|
|
109
|
+
return oauth2_presets_1.oauth2ProviderEndpoints.keycloak(options.presetOptions);
|
|
110
|
+
case "google":
|
|
111
|
+
return oauth2_presets_1.oauth2ProviderEndpoints.google();
|
|
112
|
+
case "github":
|
|
113
|
+
return oauth2_presets_1.oauth2ProviderEndpoints.github();
|
|
114
|
+
case "facebook":
|
|
115
|
+
return oauth2_presets_1.oauth2ProviderEndpoints.facebook(options.presetOptions);
|
|
116
|
+
case "discord":
|
|
117
|
+
return oauth2_presets_1.oauth2ProviderEndpoints.discord();
|
|
118
|
+
default:
|
|
119
|
+
throw new Error(`OAuth2 provider "${options.provider}" requires explicit endpoints.`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
function createOAuth2ProviderConfig(options) {
|
|
123
|
+
const { provider, endpoints, presetOptions, routes, ...config } = options;
|
|
124
|
+
return {
|
|
125
|
+
...config,
|
|
126
|
+
grantType: options.grantType ?? "authorization_code",
|
|
127
|
+
endpoints: resolveOAuth2Endpoints(options),
|
|
128
|
+
routes: oauthRoutes(`/auth/${provider}`, routes),
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
exports.createOAuth2ProviderConfig = createOAuth2ProviderConfig;
|
|
132
|
+
function createHybridOAuth2ProviderConfig(options) {
|
|
133
|
+
return createOAuth2ProviderConfig(options);
|
|
134
|
+
}
|
|
135
|
+
exports.createHybridOAuth2ProviderConfig = createHybridOAuth2ProviderConfig;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface CookieOptions {
|
|
2
|
+
httpOnly?: boolean;
|
|
3
|
+
secure?: boolean;
|
|
4
|
+
sameSite?: "strict" | "lax" | "none" | "Strict" | "Lax" | "None";
|
|
5
|
+
maxAge?: number;
|
|
6
|
+
path?: string;
|
|
7
|
+
domain?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function extractBearerToken(context: any): string | undefined;
|
|
10
|
+
export declare function setBearerToken(context: any, token: string): void;
|
|
11
|
+
export declare function getCookie(context: any, name: string): string | undefined;
|
|
12
|
+
export declare function setCookie(context: any, name: string, value: string, options?: CookieOptions): void;
|
|
13
|
+
export declare function redirect(context: any, url: string, status?: number): void;
|