@awesome-lang-auth/node 1.10.1
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/LICENSE +21 -0
- package/README.detailed.md +4059 -0
- package/README.md +248 -0
- package/dist/abstract/base-auth-strategy.abstract.d.ts +7 -0
- package/dist/abstract/base-auth-strategy.abstract.d.ts.map +1 -0
- package/dist/abstract/base-auth-strategy.abstract.js +7 -0
- package/dist/abstract/base-auth-strategy.abstract.js.map +1 -0
- package/dist/abstract/base-oauth-strategy.abstract.d.ts +27 -0
- package/dist/abstract/base-oauth-strategy.abstract.d.ts.map +1 -0
- package/dist/abstract/base-oauth-strategy.abstract.js +11 -0
- package/dist/abstract/base-oauth-strategy.abstract.js.map +1 -0
- package/dist/adapters/express.d.ts +45 -0
- package/dist/adapters/express.d.ts.map +1 -0
- package/dist/adapters/express.js +49 -0
- package/dist/adapters/express.js.map +1 -0
- package/dist/adapters/fastify.d.ts +72 -0
- package/dist/adapters/fastify.d.ts.map +1 -0
- package/dist/adapters/fastify.js +63 -0
- package/dist/adapters/fastify.js.map +1 -0
- package/dist/auth-configurator.d.ts +65 -0
- package/dist/auth-configurator.d.ts.map +1 -0
- package/dist/auth-configurator.js +127 -0
- package/dist/auth-configurator.js.map +1 -0
- package/dist/events/auth-event-bus.d.ts +68 -0
- package/dist/events/auth-event-bus.d.ts.map +1 -0
- package/dist/events/auth-event-bus.js +60 -0
- package/dist/events/auth-event-bus.js.map +1 -0
- package/dist/events/auth-event-names.d.ts +34 -0
- package/dist/events/auth-event-names.d.ts.map +1 -0
- package/dist/events/auth-event-names.js +41 -0
- package/dist/events/auth-event-names.js.map +1 -0
- package/dist/http-types.d.ts +135 -0
- package/dist/http-types.d.ts.map +1 -0
- package/dist/http-types.js +18 -0
- package/dist/http-types.js.map +1 -0
- package/dist/index.d.ts +80 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +88 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces/api-key-store.interface.d.ts +94 -0
- package/dist/interfaces/api-key-store.interface.d.ts.map +1 -0
- package/dist/interfaces/api-key-store.interface.js +3 -0
- package/dist/interfaces/api-key-store.interface.js.map +1 -0
- package/dist/interfaces/auth-strategy.interface.d.ts +6 -0
- package/dist/interfaces/auth-strategy.interface.d.ts.map +1 -0
- package/dist/interfaces/auth-strategy.interface.js +3 -0
- package/dist/interfaces/auth-strategy.interface.js.map +1 -0
- package/dist/interfaces/linked-accounts-store.interface.d.ts +74 -0
- package/dist/interfaces/linked-accounts-store.interface.d.ts.map +1 -0
- package/dist/interfaces/linked-accounts-store.interface.js +3 -0
- package/dist/interfaces/linked-accounts-store.interface.js.map +1 -0
- package/dist/interfaces/pending-link-store.interface.d.ts +77 -0
- package/dist/interfaces/pending-link-store.interface.d.ts.map +1 -0
- package/dist/interfaces/pending-link-store.interface.js +3 -0
- package/dist/interfaces/pending-link-store.interface.js.map +1 -0
- package/dist/interfaces/roles-permissions-store.interface.d.ts +129 -0
- package/dist/interfaces/roles-permissions-store.interface.d.ts.map +1 -0
- package/dist/interfaces/roles-permissions-store.interface.js +3 -0
- package/dist/interfaces/roles-permissions-store.interface.js.map +1 -0
- package/dist/interfaces/session-store.interface.d.ts +92 -0
- package/dist/interfaces/session-store.interface.d.ts.map +1 -0
- package/dist/interfaces/session-store.interface.js +3 -0
- package/dist/interfaces/session-store.interface.js.map +1 -0
- package/dist/interfaces/settings-store.interface.d.ts +91 -0
- package/dist/interfaces/settings-store.interface.d.ts.map +1 -0
- package/dist/interfaces/settings-store.interface.js +3 -0
- package/dist/interfaces/settings-store.interface.js.map +1 -0
- package/dist/interfaces/sse-distributor.interface.d.ts +25 -0
- package/dist/interfaces/sse-distributor.interface.d.ts.map +1 -0
- package/dist/interfaces/sse-distributor.interface.js +3 -0
- package/dist/interfaces/sse-distributor.interface.js.map +1 -0
- package/dist/interfaces/telemetry-store.interface.d.ts +72 -0
- package/dist/interfaces/telemetry-store.interface.d.ts.map +1 -0
- package/dist/interfaces/telemetry-store.interface.js +3 -0
- package/dist/interfaces/telemetry-store.interface.js.map +1 -0
- package/dist/interfaces/template-store.interface.d.ts +37 -0
- package/dist/interfaces/template-store.interface.d.ts.map +1 -0
- package/dist/interfaces/template-store.interface.js +3 -0
- package/dist/interfaces/template-store.interface.js.map +1 -0
- package/dist/interfaces/tenant-store.interface.d.ts +97 -0
- package/dist/interfaces/tenant-store.interface.d.ts.map +1 -0
- package/dist/interfaces/tenant-store.interface.js +3 -0
- package/dist/interfaces/tenant-store.interface.js.map +1 -0
- package/dist/interfaces/token-store.interface.d.ts +10 -0
- package/dist/interfaces/token-store.interface.d.ts.map +1 -0
- package/dist/interfaces/token-store.interface.js +3 -0
- package/dist/interfaces/token-store.interface.js.map +1 -0
- package/dist/interfaces/user-metadata-store.interface.d.ts +50 -0
- package/dist/interfaces/user-metadata-store.interface.d.ts.map +1 -0
- package/dist/interfaces/user-metadata-store.interface.js +3 -0
- package/dist/interfaces/user-metadata-store.interface.js.map +1 -0
- package/dist/interfaces/user-store.interface.d.ts +113 -0
- package/dist/interfaces/user-store.interface.d.ts.map +1 -0
- package/dist/interfaces/user-store.interface.js +3 -0
- package/dist/interfaces/user-store.interface.js.map +1 -0
- package/dist/interfaces/webhook-store.interface.d.ts +139 -0
- package/dist/interfaces/webhook-store.interface.d.ts.map +1 -0
- package/dist/interfaces/webhook-store.interface.js +3 -0
- package/dist/interfaces/webhook-store.interface.js.map +1 -0
- package/dist/middleware/api-key.middleware.d.ts +35 -0
- package/dist/middleware/api-key.middleware.d.ts.map +1 -0
- package/dist/middleware/api-key.middleware.js +45 -0
- package/dist/middleware/api-key.middleware.js.map +1 -0
- package/dist/middleware/auth.middleware.d.ts +13 -0
- package/dist/middleware/auth.middleware.d.ts.map +1 -0
- package/dist/middleware/auth.middleware.js +55 -0
- package/dist/middleware/auth.middleware.js.map +1 -0
- package/dist/middleware/jwks-auth.middleware.d.ts +18 -0
- package/dist/middleware/jwks-auth.middleware.d.ts.map +1 -0
- package/dist/middleware/jwks-auth.middleware.js +77 -0
- package/dist/middleware/jwks-auth.middleware.js.map +1 -0
- package/dist/models/api-key.model.d.ts +66 -0
- package/dist/models/api-key.model.d.ts.map +1 -0
- package/dist/models/api-key.model.js +3 -0
- package/dist/models/api-key.model.js.map +1 -0
- package/dist/models/auth-config.model.d.ts +387 -0
- package/dist/models/auth-config.model.d.ts.map +1 -0
- package/dist/models/auth-config.model.js +3 -0
- package/dist/models/auth-config.model.js.map +1 -0
- package/dist/models/errors.d.ts +7 -0
- package/dist/models/errors.d.ts.map +1 -0
- package/dist/models/errors.js +14 -0
- package/dist/models/errors.js.map +1 -0
- package/dist/models/session.model.d.ts +28 -0
- package/dist/models/session.model.d.ts.map +1 -0
- package/dist/models/session.model.js +3 -0
- package/dist/models/session.model.js.map +1 -0
- package/dist/models/tenant.model.d.ts +20 -0
- package/dist/models/tenant.model.d.ts.map +1 -0
- package/dist/models/tenant.model.js +3 -0
- package/dist/models/tenant.model.js.map +1 -0
- package/dist/models/token.model.d.ts +21 -0
- package/dist/models/token.model.d.ts.map +1 -0
- package/dist/models/token.model.js +3 -0
- package/dist/models/token.model.js.map +1 -0
- package/dist/models/user.model.d.ts +92 -0
- package/dist/models/user.model.d.ts.map +1 -0
- package/dist/models/user.model.js +3 -0
- package/dist/models/user.model.js.map +1 -0
- package/dist/router/admin.router.d.ts +188 -0
- package/dist/router/admin.router.d.ts.map +1 -0
- package/dist/router/admin.router.js +1507 -0
- package/dist/router/admin.router.js.map +1 -0
- package/dist/router/auth.router.d.ts +199 -0
- package/dist/router/auth.router.d.ts.map +1 -0
- package/dist/router/auth.router.js +1636 -0
- package/dist/router/auth.router.js.map +1 -0
- package/dist/router/openapi.d.ts +98 -0
- package/dist/router/openapi.d.ts.map +1 -0
- package/dist/router/openapi.js +1518 -0
- package/dist/router/openapi.js.map +1 -0
- package/dist/router/router-events.d.ts +38 -0
- package/dist/router/router-events.d.ts.map +1 -0
- package/dist/router/router-events.js +74 -0
- package/dist/router/router-events.js.map +1 -0
- package/dist/router/tools.router.d.ts +104 -0
- package/dist/router/tools.router.d.ts.map +1 -0
- package/dist/router/tools.router.js +227 -0
- package/dist/router/tools.router.js.map +1 -0
- package/dist/router/ui.router.d.ts +49 -0
- package/dist/router/ui.router.d.ts.map +1 -0
- package/dist/router/ui.router.js +272 -0
- package/dist/router/ui.router.js.map +1 -0
- package/dist/services/api-key.service.d.ts +53 -0
- package/dist/services/api-key.service.d.ts.map +1 -0
- package/dist/services/api-key.service.js +66 -0
- package/dist/services/api-key.service.js.map +1 -0
- package/dist/services/jwks.service.d.ts +73 -0
- package/dist/services/jwks.service.d.ts.map +1 -0
- package/dist/services/jwks.service.js +174 -0
- package/dist/services/jwks.service.js.map +1 -0
- package/dist/services/mailer.service.d.ts +30 -0
- package/dist/services/mailer.service.d.ts.map +1 -0
- package/dist/services/mailer.service.js +248 -0
- package/dist/services/mailer.service.js.map +1 -0
- package/dist/services/notification.service.d.ts +110 -0
- package/dist/services/notification.service.d.ts.map +1 -0
- package/dist/services/notification.service.js +79 -0
- package/dist/services/notification.service.js.map +1 -0
- package/dist/services/password.service.d.ts +5 -0
- package/dist/services/password.service.d.ts.map +1 -0
- package/dist/services/password.service.js +17 -0
- package/dist/services/password.service.js.map +1 -0
- package/dist/services/sms.service.d.ts +14 -0
- package/dist/services/sms.service.d.ts.map +1 -0
- package/dist/services/sms.service.js +51 -0
- package/dist/services/sms.service.js.map +1 -0
- package/dist/services/token.service.d.ts +62 -0
- package/dist/services/token.service.d.ts.map +1 -0
- package/dist/services/token.service.js +354 -0
- package/dist/services/token.service.js.map +1 -0
- package/dist/stores/memory-template.store.d.ts +12 -0
- package/dist/stores/memory-template.store.d.ts.map +1 -0
- package/dist/stores/memory-template.store.js +35 -0
- package/dist/stores/memory-template.store.js.map +1 -0
- package/dist/strategies/api-key/api-key.strategy.d.ts +72 -0
- package/dist/strategies/api-key/api-key.strategy.d.ts.map +1 -0
- package/dist/strategies/api-key/api-key.strategy.js +182 -0
- package/dist/strategies/api-key/api-key.strategy.js.map +1 -0
- package/dist/strategies/local/local.strategy.d.ts +19 -0
- package/dist/strategies/local/local.strategy.d.ts.map +1 -0
- package/dist/strategies/local/local.strategy.js +45 -0
- package/dist/strategies/local/local.strategy.js.map +1 -0
- package/dist/strategies/magic-link/magic-link.strategy.d.ts +8 -0
- package/dist/strategies/magic-link/magic-link.strategy.d.ts.map +1 -0
- package/dist/strategies/magic-link/magic-link.strategy.js +53 -0
- package/dist/strategies/magic-link/magic-link.strategy.js.map +1 -0
- package/dist/strategies/oauth/generic-oauth.strategy.d.ts +120 -0
- package/dist/strategies/oauth/generic-oauth.strategy.d.ts.map +1 -0
- package/dist/strategies/oauth/generic-oauth.strategy.js +88 -0
- package/dist/strategies/oauth/generic-oauth.strategy.js.map +1 -0
- package/dist/strategies/oauth/github.strategy.d.ts +31 -0
- package/dist/strategies/oauth/github.strategy.d.ts.map +1 -0
- package/dist/strategies/oauth/github.strategy.js +72 -0
- package/dist/strategies/oauth/github.strategy.js.map +1 -0
- package/dist/strategies/oauth/google.strategy.d.ts +31 -0
- package/dist/strategies/oauth/google.strategy.d.ts.map +1 -0
- package/dist/strategies/oauth/google.strategy.js +61 -0
- package/dist/strategies/oauth/google.strategy.js.map +1 -0
- package/dist/strategies/sms/sms.strategy.d.ts +7 -0
- package/dist/strategies/sms/sms.strategy.d.ts.map +1 -0
- package/dist/strategies/sms/sms.strategy.js +39 -0
- package/dist/strategies/sms/sms.strategy.js.map +1 -0
- package/dist/strategies/two-factor/totp.strategy.d.ts +12 -0
- package/dist/strategies/two-factor/totp.strategy.d.ts.map +1 -0
- package/dist/strategies/two-factor/totp.strategy.js +32 -0
- package/dist/strategies/two-factor/totp.strategy.js.map +1 -0
- package/dist/tools/auth-tools.d.ts +200 -0
- package/dist/tools/auth-tools.d.ts.map +1 -0
- package/dist/tools/auth-tools.js +232 -0
- package/dist/tools/auth-tools.js.map +1 -0
- package/dist/tools/sse-manager.d.ts +118 -0
- package/dist/tools/sse-manager.d.ts.map +1 -0
- package/dist/tools/sse-manager.js +163 -0
- package/dist/tools/sse-manager.js.map +1 -0
- package/dist/tools/sse-notify.decorator.d.ts +74 -0
- package/dist/tools/sse-notify.decorator.d.ts.map +1 -0
- package/dist/tools/sse-notify.decorator.js +78 -0
- package/dist/tools/sse-notify.decorator.js.map +1 -0
- package/dist/tools/webhook-action.d.ts +130 -0
- package/dist/tools/webhook-action.d.ts.map +1 -0
- package/dist/tools/webhook-action.js +144 -0
- package/dist/tools/webhook-action.js.map +1 -0
- package/dist/tools/webhook-sender.d.ts +31 -0
- package/dist/tools/webhook-sender.d.ts.map +1 -0
- package/dist/tools/webhook-sender.js +80 -0
- package/dist/tools/webhook-sender.js.map +1 -0
- package/dist/ui-assets/2fa.html +115 -0
- package/dist/ui-assets/account-conflict.html +108 -0
- package/dist/ui-assets/admin.css +263 -0
- package/dist/ui-assets/admin.js +1927 -0
- package/dist/ui-assets/auth.js +725 -0
- package/dist/ui-assets/base.css +219 -0
- package/dist/ui-assets/forgot-password.html +93 -0
- package/dist/ui-assets/link-verify.html +74 -0
- package/dist/ui-assets/login.html +135 -0
- package/dist/ui-assets/magic-link.html +112 -0
- package/dist/ui-assets/register.html +122 -0
- package/dist/ui-assets/reset-password.html +103 -0
- package/dist/ui-assets/ui-i18n-keys.json +78 -0
- package/dist/ui-assets/verify-email.html +66 -0
- package/package.json +89 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration for a single outgoing webhook subscription.
|
|
3
|
+
*/
|
|
4
|
+
export interface WebhookConfig {
|
|
5
|
+
/** Unique identifier for this webhook registration. */
|
|
6
|
+
id: string;
|
|
7
|
+
/** The URL to POST events to. */
|
|
8
|
+
url: string;
|
|
9
|
+
/**
|
|
10
|
+
* Event name patterns this webhook subscribes to.
|
|
11
|
+
* Use `'*'` to receive all events, or specific names like
|
|
12
|
+
* `'identity.auth.login.success'`.
|
|
13
|
+
*/
|
|
14
|
+
events: string[];
|
|
15
|
+
/** Optional HMAC secret for request signing (SHA-256). */
|
|
16
|
+
secret?: string;
|
|
17
|
+
/** Whether this webhook is currently active. Defaults to `true`. */
|
|
18
|
+
isActive?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Tenant ID — when set, this webhook only fires for events belonging to
|
|
21
|
+
* that tenant. Omit for global webhooks.
|
|
22
|
+
*/
|
|
23
|
+
tenantId?: string;
|
|
24
|
+
/**
|
|
25
|
+
* Maximum number of delivery attempts before giving up.
|
|
26
|
+
* Defaults to 3.
|
|
27
|
+
*/
|
|
28
|
+
maxRetries?: number;
|
|
29
|
+
/**
|
|
30
|
+
* Initial retry delay in milliseconds for exponential back-off.
|
|
31
|
+
* Defaults to 1000 ms.
|
|
32
|
+
*/
|
|
33
|
+
retryDelayMs?: number;
|
|
34
|
+
/**
|
|
35
|
+
* Provider name for inbound webhooks (e.g. `'stripe'`, `'github'`).
|
|
36
|
+
* When set, this config is used by the tools router when it receives
|
|
37
|
+
* `POST /tools/webhook/:provider` with a matching `:provider` param.
|
|
38
|
+
* Outgoing-only configs should leave this unset.
|
|
39
|
+
*/
|
|
40
|
+
provider?: string;
|
|
41
|
+
/**
|
|
42
|
+
* Action IDs permitted for this webhook's `vm` sandbox.
|
|
43
|
+
* Only actions that are **also** in `AuthSettings.enabledWebhookActions`
|
|
44
|
+
* will actually be injected (intersection rule).
|
|
45
|
+
*
|
|
46
|
+
* Managed via the Admin UI's Webhooks → edit drawer.
|
|
47
|
+
*/
|
|
48
|
+
allowedActions?: string[];
|
|
49
|
+
/**
|
|
50
|
+
* JavaScript that runs inside the `vm` sandbox when this inbound webhook
|
|
51
|
+
* fires. The sandbox exposes:
|
|
52
|
+
* - `body` — the raw request payload (`unknown`)
|
|
53
|
+
* - `actions` — filtered action functions keyed by ID
|
|
54
|
+
*
|
|
55
|
+
* The script must assign `result` to instruct the router what event to
|
|
56
|
+
* emit, or leave `result` as `null` to silently ack.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```js
|
|
60
|
+
* // jsScript
|
|
61
|
+
* if (body.type === 'customer.subscription.deleted') {
|
|
62
|
+
* await actions['billing.cancelSubscription'](body.data.object.id);
|
|
63
|
+
* result = { event: 'identity.tenant.user.removed', data: body.data };
|
|
64
|
+
* }
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
jsScript?: string;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* The JSON body sent to a webhook endpoint.
|
|
71
|
+
*/
|
|
72
|
+
export interface OutgoingWebhookEvent {
|
|
73
|
+
/** The standardised event name. */
|
|
74
|
+
event: string;
|
|
75
|
+
/** Semantic version of the event schema. */
|
|
76
|
+
version: string;
|
|
77
|
+
/** ISO 8601 timestamp. */
|
|
78
|
+
timestamp: string;
|
|
79
|
+
/** Arbitrary event data. */
|
|
80
|
+
data: unknown;
|
|
81
|
+
/** Optional metadata (tenantId, userId, correlationId, …). */
|
|
82
|
+
metadata?: Record<string, unknown>;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Store that holds webhook configurations.
|
|
86
|
+
*
|
|
87
|
+
* Implement this interface to persist webhook subscriptions in any database.
|
|
88
|
+
* When not provided, outgoing webhooks are disabled.
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```typescript
|
|
92
|
+
* import { IWebhookStore, WebhookConfig } from '@awesome-lang-auth/node';
|
|
93
|
+
*
|
|
94
|
+
* export class MyWebhookStore implements IWebhookStore {
|
|
95
|
+
* async findByEvent(event: string, tenantId?: string): Promise<WebhookConfig[]> {
|
|
96
|
+
* return db('webhooks')
|
|
97
|
+
* .where('isActive', true)
|
|
98
|
+
* .where((q) => q.where('tenantId', tenantId ?? null).orWhereNull('tenantId'))
|
|
99
|
+
* .where((q) => q.whereJsonContains('events', event).orWhereJsonContains('events', '*'));
|
|
100
|
+
* }
|
|
101
|
+
* }
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
export interface IWebhookStore {
|
|
105
|
+
/**
|
|
106
|
+
* Return all active webhook configurations that should receive `event`.
|
|
107
|
+
* Multi-tenant: when `tenantId` is provided, return both tenant-scoped
|
|
108
|
+
* and global (no `tenantId`) webhooks.
|
|
109
|
+
*/
|
|
110
|
+
findByEvent(event: string, tenantId?: string): Promise<WebhookConfig[]>;
|
|
111
|
+
/**
|
|
112
|
+
* Return all webhook configurations (paginated).
|
|
113
|
+
* Optional — only needed for admin management screens.
|
|
114
|
+
*/
|
|
115
|
+
listAll?(limit: number, offset: number): Promise<WebhookConfig[]>;
|
|
116
|
+
/**
|
|
117
|
+
* Persist a new webhook configuration and return it with an assigned `id`.
|
|
118
|
+
* Optional — only needed when webhooks can be managed through the admin UI.
|
|
119
|
+
*/
|
|
120
|
+
add?(config: Omit<WebhookConfig, 'id'>): Promise<WebhookConfig>;
|
|
121
|
+
/**
|
|
122
|
+
* Permanently delete a webhook configuration.
|
|
123
|
+
* Optional — only needed for admin management screens.
|
|
124
|
+
*/
|
|
125
|
+
remove?(id: string): Promise<void>;
|
|
126
|
+
/**
|
|
127
|
+
* Apply a partial update to an existing webhook configuration.
|
|
128
|
+
* Optional — only needed for admin management screens (e.g. toggling `isActive`).
|
|
129
|
+
*/
|
|
130
|
+
update?(id: string, changes: Partial<Omit<WebhookConfig, 'id'>>): Promise<void>;
|
|
131
|
+
/**
|
|
132
|
+
* Find the inbound webhook configuration for the given provider name.
|
|
133
|
+
* Used by the tools router to look up the `jsScript` and `allowedActions`
|
|
134
|
+
* associated with `POST /tools/webhook/:provider`.
|
|
135
|
+
* Optional — only needed when dynamic script execution is required.
|
|
136
|
+
*/
|
|
137
|
+
findByProvider?(provider: string): Promise<WebhookConfig | null>;
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=webhook-store.interface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook-store.interface.d.ts","sourceRoot":"","sources":["../../src/interfaces/webhook-store.interface.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,uDAAuD;IACvD,EAAE,EAAE,MAAM,CAAC;IACX,iCAAiC;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ;;;;OAIG;IACH,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,0DAA0D;IAC1D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oEAAoE;IACpE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAItB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAE1B;;;;;;;;;;;;;;;;;OAiBG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,mCAAmC;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,4CAA4C;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,0BAA0B;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,4BAA4B;IAC5B,IAAI,EAAE,OAAO,CAAC;IACd,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;OAIG;IACH,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC;IAExE;;;OAGG;IACH,OAAO,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC;IAElE;;;OAGG;IACH,GAAG,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IAEhE;;;OAGG;IACH,MAAM,CAAC,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEnC;;;OAGG;IACH,MAAM,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEhF;;;;;OAKG;IACH,cAAc,CAAC,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC;CAClE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook-store.interface.js","sourceRoot":"","sources":["../../src/interfaces/webhook-store.interface.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { RequestHandler } from 'express';
|
|
2
|
+
import { ApiKeyStrategyOptions } from '../strategies/api-key/api-key.strategy';
|
|
3
|
+
import { IApiKeyStore } from '../interfaces/api-key-store.interface';
|
|
4
|
+
import { ApiKeyContext } from '../models/api-key.model';
|
|
5
|
+
declare global {
|
|
6
|
+
namespace Express {
|
|
7
|
+
interface Request {
|
|
8
|
+
/** Populated by `createApiKeyMiddleware` after successful API key authentication. */
|
|
9
|
+
apiKey?: ApiKeyContext;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Create an Express middleware that authenticates incoming requests using an
|
|
15
|
+
* API Key / Service Token.
|
|
16
|
+
*
|
|
17
|
+
* The middleware accepts the key via:
|
|
18
|
+
* - `Authorization: ApiKey <key>` header
|
|
19
|
+
* - `X-Api-Key: <key>` header
|
|
20
|
+
*
|
|
21
|
+
* On success, the validated `ApiKeyContext` is attached to `req.apiKey` and
|
|
22
|
+
* `next()` is called. On failure a `401` or `403` JSON error is returned.
|
|
23
|
+
*
|
|
24
|
+
* @param store Implementation of `IApiKeyStore` for persistence.
|
|
25
|
+
* @param options Optional validation rules (scopes, IP allowlist, audit log).
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* import { createApiKeyMiddleware } from '@awesome-lang-auth/node';
|
|
30
|
+
*
|
|
31
|
+
* app.use('/tools', createApiKeyMiddleware(myApiKeyStore, { requiredScopes: ['tools:read'] }));
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export declare function createApiKeyMiddleware(store: IApiKeyStore, options?: ApiKeyStrategyOptions): RequestHandler;
|
|
35
|
+
//# sourceMappingURL=api-key.middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-key.middleware.d.ts","sourceRoot":"","sources":["../../src/middleware/api-key.middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmC,cAAc,EAAE,MAAM,SAAS,CAAC;AAC1E,OAAO,EAAkB,qBAAqB,EAAE,MAAM,wCAAwC,CAAC;AAC/F,OAAO,EAAE,YAAY,EAAE,MAAM,uCAAuC,CAAC;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAGxD,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,OAAO,CAAC;QAChB,UAAU,OAAO;YACf,qFAAqF;YACrF,MAAM,CAAC,EAAE,aAAa,CAAC;SACxB;KACF;CACF;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,YAAY,EACnB,OAAO,GAAE,qBAA0B,GAClC,cAAc,CAgBhB"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createApiKeyMiddleware = createApiKeyMiddleware;
|
|
4
|
+
const api_key_strategy_1 = require("../strategies/api-key/api-key.strategy");
|
|
5
|
+
const errors_1 = require("../models/errors");
|
|
6
|
+
/**
|
|
7
|
+
* Create an Express middleware that authenticates incoming requests using an
|
|
8
|
+
* API Key / Service Token.
|
|
9
|
+
*
|
|
10
|
+
* The middleware accepts the key via:
|
|
11
|
+
* - `Authorization: ApiKey <key>` header
|
|
12
|
+
* - `X-Api-Key: <key>` header
|
|
13
|
+
*
|
|
14
|
+
* On success, the validated `ApiKeyContext` is attached to `req.apiKey` and
|
|
15
|
+
* `next()` is called. On failure a `401` or `403` JSON error is returned.
|
|
16
|
+
*
|
|
17
|
+
* @param store Implementation of `IApiKeyStore` for persistence.
|
|
18
|
+
* @param options Optional validation rules (scopes, IP allowlist, audit log).
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* import { createApiKeyMiddleware } from '@awesome-lang-auth/node';
|
|
23
|
+
*
|
|
24
|
+
* app.use('/tools', createApiKeyMiddleware(myApiKeyStore, { requiredScopes: ['tools:read'] }));
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
function createApiKeyMiddleware(store, options = {}) {
|
|
28
|
+
const strategy = new api_key_strategy_1.ApiKeyStrategy(store, options);
|
|
29
|
+
return async (req, res, next) => {
|
|
30
|
+
try {
|
|
31
|
+
const context = await strategy.authenticate(req.headers, req.ip);
|
|
32
|
+
req.apiKey = context;
|
|
33
|
+
next();
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
if (err instanceof errors_1.AuthError) {
|
|
37
|
+
res.status(err.statusCode).json({ error: err.message, code: err.code });
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
res.status(500).json({ error: 'Internal server error' });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=api-key.middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-key.middleware.js","sourceRoot":"","sources":["../../src/middleware/api-key.middleware.ts"],"names":[],"mappings":";;AAoCA,wDAmBC;AAtDD,6EAA+F;AAG/F,6CAA6C;AAW7C;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,SAAgB,sBAAsB,CACpC,KAAmB,EACnB,UAAiC,EAAE;IAEnC,MAAM,QAAQ,GAAG,IAAI,iCAAc,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IAEpD,OAAO,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAiB,EAAE;QAC9E,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,YAAY,CAAC,GAAG,CAAC,OAAwD,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;YAClH,GAAG,CAAC,MAAM,GAAG,OAAO,CAAC;YACrB,IAAI,EAAE,CAAC;QACT,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,YAAY,kBAAS,EAAE,CAAC;gBAC7B,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;YAC1E,CAAC;iBAAM,CAAC;gBACN,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC,CAAC;YAC3D,CAAC;QACH,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { RequestHandler } from 'express';
|
|
2
|
+
import { AuthConfig } from '../models/auth-config.model';
|
|
3
|
+
import { AccessTokenPayload } from '../models/token.model';
|
|
4
|
+
import { ISessionStore } from '../interfaces/session-store.interface';
|
|
5
|
+
declare global {
|
|
6
|
+
namespace Express {
|
|
7
|
+
interface Request {
|
|
8
|
+
user?: AccessTokenPayload;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export declare function createAuthMiddleware(config: AuthConfig, sessionStore?: ISessionStore): RequestHandler;
|
|
13
|
+
//# sourceMappingURL=auth.middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.middleware.d.ts","sourceRoot":"","sources":["../../src/middleware/auth.middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmC,cAAc,EAAE,MAAM,SAAS,CAAC;AAC1E,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAE3D,OAAO,EAAE,aAAa,EAAE,MAAM,uCAAuC,CAAC;AAEtE,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,OAAO,CAAC;QAChB,UAAU,OAAO;YACf,IAAI,CAAC,EAAE,kBAAkB,CAAC;SAC3B;KACF;CACF;AAID,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,UAAU,EAAE,YAAY,CAAC,EAAE,aAAa,GAAG,cAAc,CAiDrG"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createAuthMiddleware = createAuthMiddleware;
|
|
4
|
+
const token_service_1 = require("../services/token.service");
|
|
5
|
+
const tokenService = new token_service_1.TokenService();
|
|
6
|
+
function createAuthMiddleware(config, sessionStore) {
|
|
7
|
+
return async (req, res, next) => {
|
|
8
|
+
// Prefer Authorization: Bearer header (bearer strategy), fall back to cookie
|
|
9
|
+
const authHeader = req.headers['authorization'];
|
|
10
|
+
let token = null;
|
|
11
|
+
let usingBearer = false;
|
|
12
|
+
if (authHeader && authHeader.startsWith('Bearer ')) {
|
|
13
|
+
token = authHeader.substring(7);
|
|
14
|
+
usingBearer = true;
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
token = tokenService.extractTokenFromCookie(req, 'accessToken');
|
|
18
|
+
}
|
|
19
|
+
if (!token) {
|
|
20
|
+
res.status(403).json({ error: 'No access token provided' });
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
// CSRF double-submit check only applies to cookie-based auth and state-changing methods
|
|
24
|
+
const safeMethods = ['GET', 'HEAD', 'OPTIONS'];
|
|
25
|
+
if (!usingBearer && config.csrf?.enabled && !safeMethods.includes(req.method)) {
|
|
26
|
+
const csrfCookie = tokenService.extractTokenFromCookie(req, 'csrf-token');
|
|
27
|
+
const csrfHeader = req.headers['x-csrf-token'];
|
|
28
|
+
if (!csrfCookie || !csrfHeader || csrfCookie !== csrfHeader) {
|
|
29
|
+
res.status(403).json({ error: 'CSRF token validation failed', code: 'CSRF_INVALID' });
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
const payload = tokenService.verifyAccessToken(token, config);
|
|
35
|
+
// Optional Real-time Session Validation
|
|
36
|
+
if (sessionStore && payload.sid && config.session?.checkOn === 'allcalls') {
|
|
37
|
+
const session = await sessionStore.getSession(payload.sid);
|
|
38
|
+
if (!session) {
|
|
39
|
+
res.status(401).json({ error: 'Session has been revoked', code: 'SESSION_REVOKED' });
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// Update activity timestamp if session management is active (even in 'refresh' or 'none' mode for visibility)
|
|
44
|
+
if (sessionStore && payload.sid) {
|
|
45
|
+
await sessionStore.updateSessionLastActive(payload.sid).catch(() => { });
|
|
46
|
+
}
|
|
47
|
+
req.user = payload;
|
|
48
|
+
next();
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
res.status(403).json({ error: 'Invalid or expired access token' });
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=auth.middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.middleware.js","sourceRoot":"","sources":["../../src/middleware/auth.middleware.ts"],"names":[],"mappings":";;AAgBA,oDAiDC;AA9DD,6DAAyD;AAWzD,MAAM,YAAY,GAAG,IAAI,4BAAY,EAAE,CAAC;AAExC,SAAgB,oBAAoB,CAAC,MAAkB,EAAE,YAA4B;IACnF,OAAO,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAiB,EAAE;QAC9E,6EAA6E;QAC7E,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;QAChD,IAAI,KAAK,GAAkB,IAAI,CAAC;QAChC,IAAI,WAAW,GAAG,KAAK,CAAC;QACxB,IAAI,UAAU,IAAI,UAAU,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YACnD,KAAK,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;YAChC,WAAW,GAAG,IAAI,CAAC;QACrB,CAAC;aAAM,CAAC;YACN,KAAK,GAAG,YAAY,CAAC,sBAAsB,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;QAClE,CAAC;QACD,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,0BAA0B,EAAE,CAAC,CAAC;YAC5D,OAAO;QACT,CAAC;QACD,wFAAwF;QACxF,MAAM,WAAW,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;QAC/C,IAAI,CAAC,WAAW,IAAI,MAAM,CAAC,IAAI,EAAE,OAAO,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YAC9E,MAAM,UAAU,GAAG,YAAY,CAAC,sBAAsB,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;YAC1E,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC,cAAc,CAAuB,CAAC;YACrE,IAAI,CAAC,UAAU,IAAI,CAAC,UAAU,IAAI,UAAU,KAAK,UAAU,EAAE,CAAC;gBAC5D,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,8BAA8B,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC,CAAC;gBACtF,OAAO;YACT,CAAC;QACH,CAAC;QACD,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,YAAY,CAAC,iBAAiB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;YAE9D,wCAAwC;YACxC,IAAI,YAAY,IAAI,OAAO,CAAC,GAAG,IAAI,MAAM,CAAC,OAAO,EAAE,OAAO,KAAK,UAAU,EAAE,CAAC;gBAC1E,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;gBAC3D,IAAI,CAAC,OAAO,EAAE,CAAC;oBACb,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,0BAA0B,EAAE,IAAI,EAAE,iBAAiB,EAAE,CAAC,CAAC;oBACrF,OAAO;gBACT,CAAC;YACH,CAAC;YAED,8GAA8G;YAC9G,IAAI,YAAY,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;gBAChC,MAAM,YAAY,CAAC,uBAAuB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YAC1E,CAAC;YAED,GAAG,CAAC,IAAI,GAAG,OAAO,CAAC;YACnB,IAAI,EAAE,CAAC;QACT,CAAC;QAAC,MAAM,CAAC;YACP,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,iCAAiC,EAAE,CAAC,CAAC;QACrE,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { RequestHandler } from 'express';
|
|
2
|
+
import { AuthConfig } from '../models/auth-config.model';
|
|
3
|
+
/**
|
|
4
|
+
* Auth middleware for Resource Server mode.
|
|
5
|
+
*
|
|
6
|
+
* Validates incoming Bearer tokens against the remote JWKS endpoint configured
|
|
7
|
+
* in `config.resourceServer`. Cookie-based auth (using `accessTokenSecret` /
|
|
8
|
+
* HS256) is also supported as a fallback for SSR pages on the dashboard itself.
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* ```ts
|
|
12
|
+
* app.use(createJwksAuthMiddleware(config));
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export declare function createJwksAuthMiddleware(config: AuthConfig): RequestHandler;
|
|
16
|
+
/** Exported for testing: clear the module-level JWKS client cache. */
|
|
17
|
+
export declare function _clearJwksClientCache(): void;
|
|
18
|
+
//# sourceMappingURL=jwks-auth.middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwks-auth.middleware.d.ts","sourceRoot":"","sources":["../../src/middleware/jwks-auth.middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmC,cAAc,EAAE,MAAM,SAAS,CAAC;AAC1E,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAuBzD;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,UAAU,GAAG,cAAc,CA2C3E;AAED,sEAAsE;AACtE,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createJwksAuthMiddleware = createJwksAuthMiddleware;
|
|
4
|
+
exports._clearJwksClientCache = _clearJwksClientCache;
|
|
5
|
+
const token_service_1 = require("../services/token.service");
|
|
6
|
+
const jwks_service_1 = require("../services/jwks.service");
|
|
7
|
+
const tokenService = new token_service_1.TokenService();
|
|
8
|
+
// Module-level cache: one JwksClient per JWKS URL so the key cache is shared
|
|
9
|
+
// across requests even when `createJwksAuthMiddleware` is called multiple times.
|
|
10
|
+
const clientCache = new Map();
|
|
11
|
+
function getOrCreateClient(config) {
|
|
12
|
+
const rs = config.resourceServer;
|
|
13
|
+
const existing = clientCache.get(rs.jwksUrl);
|
|
14
|
+
if (existing)
|
|
15
|
+
return existing;
|
|
16
|
+
const client = jwks_service_1.JwksService.createRemoteClient(rs.jwksUrl, {
|
|
17
|
+
cacheTtl: rs.jwksCacheTtl,
|
|
18
|
+
fetchTimeout: rs.jwksFetchTimeout,
|
|
19
|
+
});
|
|
20
|
+
clientCache.set(rs.jwksUrl, client);
|
|
21
|
+
return client;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Auth middleware for Resource Server mode.
|
|
25
|
+
*
|
|
26
|
+
* Validates incoming Bearer tokens against the remote JWKS endpoint configured
|
|
27
|
+
* in `config.resourceServer`. Cookie-based auth (using `accessTokenSecret` /
|
|
28
|
+
* HS256) is also supported as a fallback for SSR pages on the dashboard itself.
|
|
29
|
+
*
|
|
30
|
+
* Usage:
|
|
31
|
+
* ```ts
|
|
32
|
+
* app.use(createJwksAuthMiddleware(config));
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
function createJwksAuthMiddleware(config) {
|
|
36
|
+
if (!config.resourceServer?.enabled) {
|
|
37
|
+
throw new Error('createJwksAuthMiddleware requires config.resourceServer.enabled = true');
|
|
38
|
+
}
|
|
39
|
+
const jwksClient = getOrCreateClient(config);
|
|
40
|
+
return async (req, res, next) => {
|
|
41
|
+
const authHeader = req.headers['authorization'];
|
|
42
|
+
let token = null;
|
|
43
|
+
let usingBearer = false;
|
|
44
|
+
if (authHeader && authHeader.startsWith('Bearer ')) {
|
|
45
|
+
token = authHeader.substring(7);
|
|
46
|
+
usingBearer = true;
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
token = tokenService.extractTokenFromCookie(req, 'accessToken');
|
|
50
|
+
}
|
|
51
|
+
if (!token) {
|
|
52
|
+
res.status(403).json({ error: 'No access token provided' });
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
try {
|
|
56
|
+
if (usingBearer) {
|
|
57
|
+
// Bearer tokens are validated against the remote JWKS (RS256)
|
|
58
|
+
const payload = await tokenService.verifyWithJwks(token, jwksClient, config.resourceServer.issuer);
|
|
59
|
+
req.user = payload;
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
// Cookie-based tokens use the local HS256 secret (SSR / dashboard session)
|
|
63
|
+
const payload = tokenService.verifyAccessToken(token, config);
|
|
64
|
+
req.user = payload;
|
|
65
|
+
}
|
|
66
|
+
next();
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
res.status(401).json({ error: 'Invalid or expired access token', code: 'INVALID_TOKEN' });
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
/** Exported for testing: clear the module-level JWKS client cache. */
|
|
74
|
+
function _clearJwksClientCache() {
|
|
75
|
+
clientCache.clear();
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=jwks-auth.middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwks-auth.middleware.js","sourceRoot":"","sources":["../../src/middleware/jwks-auth.middleware.ts"],"names":[],"mappings":";;AAoCA,4DA2CC;AAGD,sDAEC;AAlFD,6DAAyD;AACzD,2DAAmE;AAEnE,MAAM,YAAY,GAAG,IAAI,4BAAY,EAAE,CAAC;AAExC,6EAA6E;AAC7E,iFAAiF;AACjF,MAAM,WAAW,GAAG,IAAI,GAAG,EAAsB,CAAC;AAElD,SAAS,iBAAiB,CAAC,MAAkB;IAC3C,MAAM,EAAE,GAAG,MAAM,CAAC,cAAe,CAAC;IAClC,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC;IAC7C,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAE9B,MAAM,MAAM,GAAG,0BAAW,CAAC,kBAAkB,CAAC,EAAE,CAAC,OAAO,EAAE;QACxD,QAAQ,EAAE,EAAE,CAAC,YAAY;QACzB,YAAY,EAAE,EAAE,CAAC,gBAAgB;KAClC,CAAC,CAAC;IACH,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IACpC,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;;;;;;GAWG;AACH,SAAgB,wBAAwB,CAAC,MAAkB;IACzD,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,OAAO,EAAE,CAAC;QACpC,MAAM,IAAI,KAAK,CAAC,wEAAwE,CAAC,CAAC;IAC5F,CAAC;IAED,MAAM,UAAU,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAE7C,OAAO,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAiB,EAAE;QAC9E,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;QAChD,IAAI,KAAK,GAAkB,IAAI,CAAC;QAChC,IAAI,WAAW,GAAG,KAAK,CAAC;QAExB,IAAI,UAAU,IAAI,UAAU,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YACnD,KAAK,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;YAChC,WAAW,GAAG,IAAI,CAAC;QACrB,CAAC;aAAM,CAAC;YACN,KAAK,GAAG,YAAY,CAAC,sBAAsB,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;QAClE,CAAC;QAED,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,0BAA0B,EAAE,CAAC,CAAC;YAC5D,OAAO;QACT,CAAC;QAED,IAAI,CAAC;YACH,IAAI,WAAW,EAAE,CAAC;gBAChB,8DAA8D;gBAC9D,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,cAAc,CAC/C,KAAK,EACL,UAAU,EACV,MAAM,CAAC,cAAe,CAAC,MAAM,CAC9B,CAAC;gBACF,GAAG,CAAC,IAAI,GAAG,OAAO,CAAC;YACrB,CAAC;iBAAM,CAAC;gBACN,2EAA2E;gBAC3E,MAAM,OAAO,GAAG,YAAY,CAAC,iBAAiB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;gBAC9D,GAAG,CAAC,IAAI,GAAG,OAAO,CAAC;YACrB,CAAC;YACD,IAAI,EAAE,CAAC;QACT,CAAC;QAAC,MAAM,CAAC;YACP,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,iCAAiC,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC,CAAC;QAC5F,CAAC;IACH,CAAC,CAAC;AACJ,CAAC;AAED,sEAAsE;AACtE,SAAgB,qBAAqB;IACnC,WAAW,CAAC,KAAK,EAAE,CAAC;AACtB,CAAC"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Domain model for an API Key / Service Token.
|
|
3
|
+
*
|
|
4
|
+
* The raw key value is **never** stored — only the bcrypt hash is persisted.
|
|
5
|
+
* The plaintext key is returned exactly once at creation time.
|
|
6
|
+
*/
|
|
7
|
+
export interface ApiKey {
|
|
8
|
+
/** Unique identifier for the key record (UUID or similar). */
|
|
9
|
+
id: string;
|
|
10
|
+
/**
|
|
11
|
+
* Human-readable label to identify the key (e.g. `'webhook-stripe'`).
|
|
12
|
+
* Shown in audit logs and the admin UI.
|
|
13
|
+
*/
|
|
14
|
+
name: string;
|
|
15
|
+
/**
|
|
16
|
+
* Bcrypt hash of the raw key. Never expose this to the caller.
|
|
17
|
+
*/
|
|
18
|
+
keyHash: string;
|
|
19
|
+
/**
|
|
20
|
+
* Key prefix — the first 8 characters of the raw key, stored in plaintext
|
|
21
|
+
* so that keys can be identified in the UI without revealing the full secret.
|
|
22
|
+
* Format: `ak_<8 chars>…`
|
|
23
|
+
*/
|
|
24
|
+
keyPrefix: string;
|
|
25
|
+
/**
|
|
26
|
+
* Optional service/machine identity this key is attached to.
|
|
27
|
+
* Can be a user ID, a tenant ID, a service name — whatever makes sense for
|
|
28
|
+
* the consuming application.
|
|
29
|
+
*/
|
|
30
|
+
serviceId?: string | null;
|
|
31
|
+
/**
|
|
32
|
+
* Scope strings that restrict what this key can access.
|
|
33
|
+
* Interpreted by the consuming application; the library passes them through
|
|
34
|
+
* via `req.apiKey.scopes`.
|
|
35
|
+
*
|
|
36
|
+
* @example `['tools:read', 'tools:write', 'webhooks:receive']`
|
|
37
|
+
*/
|
|
38
|
+
scopes?: string[];
|
|
39
|
+
/**
|
|
40
|
+
* Optional CIDR ranges or individual IPs that are allowed to use this key.
|
|
41
|
+
* When `null` or empty, no IP restriction is applied.
|
|
42
|
+
*
|
|
43
|
+
* @example `['10.0.0.0/8', '203.0.113.42']`
|
|
44
|
+
*/
|
|
45
|
+
allowedIps?: string[] | null;
|
|
46
|
+
/** Whether the key is active. Set to `false` to revoke immediately. */
|
|
47
|
+
isActive: boolean;
|
|
48
|
+
/** Optional expiry date after which the key is no longer valid. */
|
|
49
|
+
expiresAt?: Date | null;
|
|
50
|
+
/** When this key record was created. */
|
|
51
|
+
createdAt: Date;
|
|
52
|
+
/** Timestamp of the most recent successful use of this key. */
|
|
53
|
+
lastUsedAt?: Date | null;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Context attached to `req.apiKey` after a successful API key authentication.
|
|
57
|
+
*/
|
|
58
|
+
export interface ApiKeyContext {
|
|
59
|
+
/** The API key record (without the hash). */
|
|
60
|
+
keyId: string;
|
|
61
|
+
keyPrefix: string;
|
|
62
|
+
name: string;
|
|
63
|
+
serviceId?: string | null;
|
|
64
|
+
scopes: string[];
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=api-key.model.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-key.model.d.ts","sourceRoot":"","sources":["../../src/models/api-key.model.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,WAAW,MAAM;IACrB,8DAA8D;IAC9D,EAAE,EAAE,MAAM,CAAC;IAEX;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;;;OAIG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAE1B;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAElB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAE7B,uEAAuE;IACvE,QAAQ,EAAE,OAAO,CAAC;IAElB,mEAAmE;IACnE,SAAS,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IAExB,wCAAwC;IACxC,SAAS,EAAE,IAAI,CAAC;IAEhB,+DAA+D;IAC/D,UAAU,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,6CAA6C;IAC7C,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-key.model.js","sourceRoot":"","sources":["../../src/models/api-key.model.ts"],"names":[],"mappings":""}
|