@kurdel/auth 0.1.0-beta.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.md +253 -0
- package/lib/domain/auth-context.d.ts +8 -0
- package/lib/domain/auth-context.js +2 -0
- package/lib/domain/auth-context.js.map +1 -0
- package/lib/domain/auth-event-sink-provider.d.ts +7 -0
- package/lib/domain/auth-event-sink-provider.js +2 -0
- package/lib/domain/auth-event-sink-provider.js.map +1 -0
- package/lib/domain/auth-event.d.ts +30 -0
- package/lib/domain/auth-event.js +5 -0
- package/lib/domain/auth-event.js.map +1 -0
- package/lib/domain/auth-strategy-provider.d.ts +9 -0
- package/lib/domain/auth-strategy-provider.js +2 -0
- package/lib/domain/auth-strategy-provider.js.map +1 -0
- package/lib/domain/auth-strategy.d.ts +17 -0
- package/lib/domain/auth-strategy.js +2 -0
- package/lib/domain/auth-strategy.js.map +1 -0
- package/lib/domain/authorization-policy-provider.d.ts +9 -0
- package/lib/domain/authorization-policy-provider.js +2 -0
- package/lib/domain/authorization-policy-provider.js.map +1 -0
- package/lib/domain/authorization-policy.d.ts +6 -0
- package/lib/domain/authorization-policy.js +2 -0
- package/lib/domain/authorization-policy.js.map +1 -0
- package/lib/domain/index.d.ts +7 -0
- package/lib/domain/index.js +8 -0
- package/lib/domain/index.js.map +1 -0
- package/lib/index.d.ts +6 -0
- package/lib/index.js +7 -0
- package/lib/index.js.map +1 -0
- package/lib/infra/in-memory/in-memory-api-key-repository.d.ts +7 -0
- package/lib/infra/in-memory/in-memory-api-key-repository.js +10 -0
- package/lib/infra/in-memory/in-memory-api-key-repository.js.map +1 -0
- package/lib/infra/in-memory/in-memory-auth-user-repository.d.ts +8 -0
- package/lib/infra/in-memory/in-memory-auth-user-repository.js +10 -0
- package/lib/infra/in-memory/in-memory-auth-user-repository.js.map +1 -0
- package/lib/infra/in-memory/in-memory-jwt-repository.d.ts +7 -0
- package/lib/infra/in-memory/in-memory-jwt-repository.js +8 -0
- package/lib/infra/in-memory/in-memory-jwt-repository.js.map +1 -0
- package/lib/infra/in-memory/index.d.ts +3 -0
- package/lib/infra/in-memory/index.js +4 -0
- package/lib/infra/in-memory/index.js.map +1 -0
- package/lib/infra/index.d.ts +1 -0
- package/lib/infra/index.js +2 -0
- package/lib/infra/index.js.map +1 -0
- package/lib/repositories/api-key/api-key-repository.d.ts +30 -0
- package/lib/repositories/api-key/api-key-repository.js +2 -0
- package/lib/repositories/api-key/api-key-repository.js.map +1 -0
- package/lib/repositories/api-key/api-key-usage-recorder.d.ts +4 -0
- package/lib/repositories/api-key/api-key-usage-recorder.js +2 -0
- package/lib/repositories/api-key/api-key-usage-recorder.js.map +1 -0
- package/lib/repositories/api-key/index.d.ts +2 -0
- package/lib/repositories/api-key/index.js +3 -0
- package/lib/repositories/api-key/index.js.map +1 -0
- package/lib/repositories/index.d.ts +3 -0
- package/lib/repositories/index.js +4 -0
- package/lib/repositories/index.js.map +1 -0
- package/lib/repositories/jwt/index.d.ts +1 -0
- package/lib/repositories/jwt/index.js +2 -0
- package/lib/repositories/jwt/index.js.map +1 -0
- package/lib/repositories/jwt/jwt-repository.d.ts +3 -0
- package/lib/repositories/jwt/jwt-repository.js +2 -0
- package/lib/repositories/jwt/jwt-repository.js.map +1 -0
- package/lib/repositories/user/auth-user-repository.d.ts +11 -0
- package/lib/repositories/user/auth-user-repository.js +2 -0
- package/lib/repositories/user/auth-user-repository.js.map +1 -0
- package/lib/repositories/user/index.d.ts +1 -0
- package/lib/repositories/user/index.js +2 -0
- package/lib/repositories/user/index.js.map +1 -0
- package/lib/runtime/auth-module.d.ts +64 -0
- package/lib/runtime/auth-module.js +83 -0
- package/lib/runtime/auth-module.js.map +1 -0
- package/lib/runtime/auth-strategy-registry.d.ts +25 -0
- package/lib/runtime/auth-strategy-registry.js +33 -0
- package/lib/runtime/auth-strategy-registry.js.map +1 -0
- package/lib/runtime/authorization-policy-registry.d.ts +8 -0
- package/lib/runtime/authorization-policy-registry.js +16 -0
- package/lib/runtime/authorization-policy-registry.js.map +1 -0
- package/lib/runtime/create-auth-middleware.d.ts +5 -0
- package/lib/runtime/create-auth-middleware.js +89 -0
- package/lib/runtime/create-auth-middleware.js.map +1 -0
- package/lib/runtime/index.d.ts +4 -0
- package/lib/runtime/index.js +5 -0
- package/lib/runtime/index.js.map +1 -0
- package/lib/strategies/api-key/api-key-strategy.d.ts +22 -0
- package/lib/strategies/api-key/api-key-strategy.js +36 -0
- package/lib/strategies/api-key/api-key-strategy.js.map +1 -0
- package/lib/strategies/api-key/index.d.ts +1 -0
- package/lib/strategies/api-key/index.js +2 -0
- package/lib/strategies/api-key/index.js.map +1 -0
- package/lib/strategies/index.d.ts +2 -0
- package/lib/strategies/index.js +3 -0
- package/lib/strategies/index.js.map +1 -0
- package/lib/strategies/jwt/index.d.ts +2 -0
- package/lib/strategies/jwt/index.js +3 -0
- package/lib/strategies/jwt/index.js.map +1 -0
- package/lib/strategies/jwt/jwt-service.d.ts +50 -0
- package/lib/strategies/jwt/jwt-service.js +87 -0
- package/lib/strategies/jwt/jwt-service.js.map +1 -0
- package/lib/strategies/jwt/jwt-strategy.d.ts +27 -0
- package/lib/strategies/jwt/jwt-strategy.js +45 -0
- package/lib/strategies/jwt/jwt-strategy.js.map +1 -0
- package/lib/tokens.d.ts +11 -0
- package/lib/tokens.js +13 -0
- package/lib/tokens.js.map +1 -0
- package/package.json +56 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025-2026 Andrii Sorokin
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
# @kurdel/auth
|
|
2
|
+
|
|
3
|
+
Storage-agnostic authentication strategies and authorization middleware for
|
|
4
|
+
Kurdel applications.
|
|
5
|
+
|
|
6
|
+
The package authenticates incoming requests, resolves the current application
|
|
7
|
+
user, and exposes the result through `HttpContext`. Persistence is supplied by
|
|
8
|
+
the application or by adapters such as `@kurdel/auth-db`.
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install @kurdel/auth
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Configure authentication
|
|
17
|
+
|
|
18
|
+
Register one or more named strategies with `AuthModule`. A strategy instance
|
|
19
|
+
can be supplied directly or created from the application container:
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
import { ApiKeyStrategy, AUTH_TOKENS, AuthModule } from '@kurdel/auth';
|
|
23
|
+
|
|
24
|
+
const auth = new AuthModule({
|
|
25
|
+
strategies: [
|
|
26
|
+
{
|
|
27
|
+
name: 'api-key',
|
|
28
|
+
useFactory: ioc =>
|
|
29
|
+
new ApiKeyStrategy({
|
|
30
|
+
header: 'x-api-key',
|
|
31
|
+
credentials: ioc.get(AUTH_TOKENS.ApiKeyRepository),
|
|
32
|
+
users: ioc.get(AUTH_TOKENS.UserRepository),
|
|
33
|
+
usage: ioc.get(AUTH_TOKENS.ApiKeyUsageRecorder),
|
|
34
|
+
}),
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
|
+
});
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
`AuthModule` registers the authentication middleware automatically. Strategy
|
|
41
|
+
names are application-defined and are referenced by route metadata.
|
|
42
|
+
|
|
43
|
+
## Protect routes
|
|
44
|
+
|
|
45
|
+
Set `auth.strategy` to require authentication. Add `roles` when at least one of
|
|
46
|
+
the listed roles is required:
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
import { Controller, Ok, route, type HttpContext } from '@kurdel/core/http';
|
|
50
|
+
|
|
51
|
+
export class AccountController extends Controller {
|
|
52
|
+
readonly routes = {
|
|
53
|
+
profile: route({
|
|
54
|
+
method: 'GET',
|
|
55
|
+
path: '/profile',
|
|
56
|
+
auth: { strategy: 'api-key' },
|
|
57
|
+
})(this.profile),
|
|
58
|
+
admin: route({
|
|
59
|
+
method: 'GET',
|
|
60
|
+
path: '/admin',
|
|
61
|
+
auth: { strategy: 'api-key', roles: ['admin'] },
|
|
62
|
+
})(this.admin),
|
|
63
|
+
health: route({
|
|
64
|
+
method: 'GET',
|
|
65
|
+
path: '/health',
|
|
66
|
+
auth: { public: true },
|
|
67
|
+
})(this.health),
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
async profile(ctx: HttpContext) {
|
|
71
|
+
return Ok({ user: ctx.auth?.user });
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async admin(ctx: HttpContext) {
|
|
75
|
+
return Ok({ authenticatedWith: ctx.auth?.strategy });
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async health() {
|
|
79
|
+
return Ok({ status: 'up' });
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Controller-level authentication can define defaults for every route. Route
|
|
85
|
+
metadata may override those defaults, and `{ public: true }` makes an
|
|
86
|
+
individual route public.
|
|
87
|
+
|
|
88
|
+
Authentication failures return `401 Unauthorized`. An authenticated user who
|
|
89
|
+
does not have any required role receives `403 Forbidden`. Referencing an
|
|
90
|
+
unregistered strategy is treated as an application configuration error and
|
|
91
|
+
returns `500 Internal Server Error`.
|
|
92
|
+
|
|
93
|
+
## Authorization policies
|
|
94
|
+
|
|
95
|
+
Named policies handle application-specific access rules that cannot be
|
|
96
|
+
expressed by roles alone. Register them alongside strategies:
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
const auth = new AuthModule({
|
|
100
|
+
strategies: [/* ... */],
|
|
101
|
+
policies: [
|
|
102
|
+
{
|
|
103
|
+
name: 'manage-users',
|
|
104
|
+
use: {
|
|
105
|
+
authorize: (auth, ctx) =>
|
|
106
|
+
auth.credential?.type === 'api-key' &&
|
|
107
|
+
auth.user.roles.includes('admin') &&
|
|
108
|
+
ctx.req.method !== 'TRACE',
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
],
|
|
112
|
+
});
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Reference policies from route metadata:
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
route({
|
|
119
|
+
method: 'POST',
|
|
120
|
+
path: '/users',
|
|
121
|
+
auth: {
|
|
122
|
+
strategy: 'api-key',
|
|
123
|
+
policies: ['manage-users'],
|
|
124
|
+
},
|
|
125
|
+
})(this.createUser);
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
A policy receives the complete `AuthContext` and current `HttpContext`, and may
|
|
129
|
+
return a boolean or a promise. When several policies are listed, every policy
|
|
130
|
+
must grant access. Policies and `roles` may be combined; both checks must then
|
|
131
|
+
succeed. A rejected policy returns `403 Forbidden`, while an unknown policy is
|
|
132
|
+
reported as an application configuration error.
|
|
133
|
+
|
|
134
|
+
Policy providers also support `useFactory`, allowing policies to resolve
|
|
135
|
+
application services from the dependency container.
|
|
136
|
+
|
|
137
|
+
## Security events
|
|
138
|
+
|
|
139
|
+
Configure an event sink to observe sanitized authentication and authorization
|
|
140
|
+
activity:
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
new AuthModule({
|
|
144
|
+
events: {
|
|
145
|
+
useFactory: ioc => ioc.get(APP_TOKENS.AuthEventSink),
|
|
146
|
+
},
|
|
147
|
+
strategies: [/* ... */],
|
|
148
|
+
});
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
The package reports successful and failed authentication plus authorization
|
|
152
|
+
denials. API-key management services may additionally report credential issue
|
|
153
|
+
and revocation events. Events contain timestamps, strategy names, user and
|
|
154
|
+
credential identifiers, safe reason codes, and policy names. Raw API keys,
|
|
155
|
+
JWTs, credential hashes, headers, and request bodies are never part of the
|
|
156
|
+
event contract.
|
|
157
|
+
|
|
158
|
+
Without configuration, `AuthModule` uses `NoopAuthEventSink`. Applications may
|
|
159
|
+
provide an instance or a factory-backed sink. Sink failures are propagated so
|
|
160
|
+
operators can choose an appropriate durable or failure-tolerant implementation
|
|
161
|
+
instead of having audit loss silently hidden by the framework.
|
|
162
|
+
|
|
163
|
+
## Authentication context
|
|
164
|
+
|
|
165
|
+
After successful authentication, middleware attaches an `AuthContext` to
|
|
166
|
+
`ctx.auth`:
|
|
167
|
+
|
|
168
|
+
```ts
|
|
169
|
+
interface AuthContext {
|
|
170
|
+
user: AuthUser;
|
|
171
|
+
strategy: string;
|
|
172
|
+
credential?: {
|
|
173
|
+
type: string;
|
|
174
|
+
id?: string;
|
|
175
|
+
};
|
|
176
|
+
claims?: Record<string, unknown>;
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
- `user` is the current application identity and its current roles.
|
|
181
|
+
- `strategy` is the registered name selected by route metadata.
|
|
182
|
+
- `credential` identifies the credential kind and, when available, its stable
|
|
183
|
+
identifier. It never contains the raw API key or JWT.
|
|
184
|
+
- `claims` contains verified strategy-specific claims, such as a JWT payload.
|
|
185
|
+
|
|
186
|
+
`ctx.user` remains available as an alias of `ctx.auth.user` for compatibility.
|
|
187
|
+
New code that needs authentication metadata should use `ctx.auth`.
|
|
188
|
+
|
|
189
|
+
The built-in API-key strategy exposes `credential.type` as `api-key` and uses
|
|
190
|
+
the repository credential ID when one exists. The JWT strategy exposes
|
|
191
|
+
`credential.type` as `jwt`, uses the `jti` claim as its optional ID, and places
|
|
192
|
+
the verified payload in `claims`.
|
|
193
|
+
|
|
194
|
+
## User and credential repositories
|
|
195
|
+
|
|
196
|
+
Authentication strategies do not own user data. Both built-in strategies load
|
|
197
|
+
the current identity from `AuthUserRepository`, making the repository the
|
|
198
|
+
source of truth for current roles and disabled users:
|
|
199
|
+
|
|
200
|
+
```ts
|
|
201
|
+
interface AuthUserRepository {
|
|
202
|
+
findById(id: string | number): Promise<AuthUser | null>;
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
`ApiKeyStrategy` additionally requires an `ApiKeyRepository`. Its
|
|
207
|
+
implementation must return `null` for unknown credentials and describe known
|
|
208
|
+
credentials without returning their raw secret. Revoked and expired API keys
|
|
209
|
+
are rejected before the user is authenticated.
|
|
210
|
+
|
|
211
|
+
Applications may provide an `ApiKeyUsageRecorder` to capture successful use of
|
|
212
|
+
credentials with stable IDs. The strategy records usage only after the key is
|
|
213
|
+
accepted and its current user is resolved; rejected, expired, revoked, and
|
|
214
|
+
orphaned credentials are never recorded.
|
|
215
|
+
|
|
216
|
+
For database-backed implementations, use `@kurdel/auth-db`. Applications may
|
|
217
|
+
also implement these interfaces for another database, an external identity
|
|
218
|
+
service, or an in-memory test setup.
|
|
219
|
+
|
|
220
|
+
## Custom strategies
|
|
221
|
+
|
|
222
|
+
Implement `AuthStrategy` to support another authentication mechanism:
|
|
223
|
+
|
|
224
|
+
```ts
|
|
225
|
+
import type { AuthStrategy, AuthenticationResult } from '@kurdel/auth';
|
|
226
|
+
import type { HttpRequest } from '@kurdel/common';
|
|
227
|
+
|
|
228
|
+
class SessionStrategy implements AuthStrategy {
|
|
229
|
+
async authenticate(req: HttpRequest): Promise<AuthenticationResult | null> {
|
|
230
|
+
const session = await loadSession(req);
|
|
231
|
+
if (!session) return null;
|
|
232
|
+
|
|
233
|
+
return {
|
|
234
|
+
user: session.user,
|
|
235
|
+
credential: { type: 'session', id: session.id },
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
A strategy returns `null` when the request cannot be authenticated. On
|
|
242
|
+
success, it returns the user and optional safe credential metadata or verified
|
|
243
|
+
claims. The middleware adds the registered strategy name to the final context.
|
|
244
|
+
|
|
245
|
+
## Database integration
|
|
246
|
+
|
|
247
|
+
See [`@kurdel/auth-db`](../auth-db/README.md) for reusable database repository
|
|
248
|
+
adapters and [`sample/auth-db`](../../sample/auth-db/README.md) for a runnable
|
|
249
|
+
SQLite application with API-key authentication and a React administration UI.
|
|
250
|
+
|
|
251
|
+
## License
|
|
252
|
+
|
|
253
|
+
MIT © Andrii Sorokin
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { AuthCredential, AuthUser } from '@kurdel/common';
|
|
2
|
+
export type { AuthContext, AuthCredential } from '@kurdel/common';
|
|
3
|
+
/** Data produced by a strategy before middleware attaches the strategy name. */
|
|
4
|
+
export interface AuthenticationResult<TUser extends AuthUser = AuthUser> {
|
|
5
|
+
user: TUser;
|
|
6
|
+
credential?: AuthCredential;
|
|
7
|
+
claims?: Record<string, unknown>;
|
|
8
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-context.js","sourceRoot":"","sources":["../../src/domain/auth-context.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-event-sink-provider.js","sourceRoot":"","sources":["../../src/domain/auth-event-sink-provider.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { AuthCredential, AuthUser } from '@kurdel/common';
|
|
2
|
+
type AuthEventBase = {
|
|
3
|
+
occurredAt: Date;
|
|
4
|
+
userId?: AuthUser['id'];
|
|
5
|
+
credential?: AuthCredential;
|
|
6
|
+
};
|
|
7
|
+
export type AuthEvent = (AuthEventBase & {
|
|
8
|
+
type: 'authentication.succeeded';
|
|
9
|
+
strategy: string;
|
|
10
|
+
}) | (AuthEventBase & {
|
|
11
|
+
type: 'authentication.failed';
|
|
12
|
+
strategy: string;
|
|
13
|
+
reason: 'invalid-credential';
|
|
14
|
+
}) | (AuthEventBase & {
|
|
15
|
+
type: 'authorization.denied';
|
|
16
|
+
strategy?: string;
|
|
17
|
+
reason: 'missing-role' | 'missing-authentication' | 'policy-rejected';
|
|
18
|
+
policy?: string;
|
|
19
|
+
}) | (AuthEventBase & {
|
|
20
|
+
type: 'api-key.issued' | 'api-key.revoked';
|
|
21
|
+
});
|
|
22
|
+
/** Receives sanitized authentication and authorization lifecycle events. */
|
|
23
|
+
export interface AuthEventSink {
|
|
24
|
+
report(event: AuthEvent): Promise<void> | void;
|
|
25
|
+
}
|
|
26
|
+
/** Default sink used when an application does not configure event reporting. */
|
|
27
|
+
export declare class NoopAuthEventSink implements AuthEventSink {
|
|
28
|
+
report(_event: AuthEvent): void;
|
|
29
|
+
}
|
|
30
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-event.js","sourceRoot":"","sources":["../../src/domain/auth-event.ts"],"names":[],"mappings":"AAiCA,gFAAgF;AAChF,MAAM,OAAO,iBAAiB;IAC5B,MAAM,CAAC,MAAiB,IAAS,CAAC;CACnC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-strategy-provider.js","sourceRoot":"","sources":["../../src/domain/auth-strategy-provider.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { HttpRequest } from '@kurdel/common';
|
|
2
|
+
import type { AuthenticationResult } from './auth-context.js';
|
|
3
|
+
/**
|
|
4
|
+
* ## AuthStrategy
|
|
5
|
+
*
|
|
6
|
+
* A pluggable authentication mechanism.
|
|
7
|
+
* Each strategy decides how to extract and validate credentials
|
|
8
|
+
* from the incoming HTTP request.
|
|
9
|
+
*
|
|
10
|
+
* The strategy:
|
|
11
|
+
* - returns an AuthenticationResult on success
|
|
12
|
+
* - returns null if authentication fails
|
|
13
|
+
* - must NOT throw on invalid credentials
|
|
14
|
+
*/
|
|
15
|
+
export interface AuthStrategy {
|
|
16
|
+
authenticate(req: HttpRequest): Promise<AuthenticationResult | null>;
|
|
17
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-strategy.js","sourceRoot":"","sources":["../../src/domain/auth-strategy.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Container } from '@kurdel/ioc';
|
|
2
|
+
import type { AuthorizationPolicy } from './authorization-policy.js';
|
|
3
|
+
export type AuthorizationPolicyProvider = {
|
|
4
|
+
name: string;
|
|
5
|
+
use: AuthorizationPolicy;
|
|
6
|
+
} | {
|
|
7
|
+
name: string;
|
|
8
|
+
useFactory: (container: Container) => AuthorizationPolicy;
|
|
9
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authorization-policy-provider.js","sourceRoot":"","sources":["../../src/domain/authorization-policy-provider.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { AuthContext } from '@kurdel/common';
|
|
2
|
+
import type { HttpContext } from '@kurdel/core/http';
|
|
3
|
+
/** Performs an application-specific authorization check for a request. */
|
|
4
|
+
export interface AuthorizationPolicy {
|
|
5
|
+
authorize(auth: Readonly<AuthContext>, ctx: HttpContext): boolean | Promise<boolean>;
|
|
6
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authorization-policy.js","sourceRoot":"","sources":["../../src/domain/authorization-policy.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export * from './auth-context.js';
|
|
2
|
+
export * from './auth-event.js';
|
|
3
|
+
export * from './auth-event-sink-provider.js';
|
|
4
|
+
export * from './auth-strategy-provider.js';
|
|
5
|
+
export * from './auth-strategy.js';
|
|
6
|
+
export * from './authorization-policy.js';
|
|
7
|
+
export * from './authorization-policy-provider.js';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export * from './auth-context.js';
|
|
2
|
+
export * from './auth-event.js';
|
|
3
|
+
export * from './auth-event-sink-provider.js';
|
|
4
|
+
export * from './auth-strategy-provider.js';
|
|
5
|
+
export * from './auth-strategy.js';
|
|
6
|
+
export * from './authorization-policy.js';
|
|
7
|
+
export * from './authorization-policy-provider.js';
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/domain/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,oBAAoB,CAAC;AACnC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,oCAAoC,CAAC"}
|
package/lib/index.d.ts
ADDED
package/lib/index.js
ADDED
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,yBAAyB,CAAA;AACvC,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAA;AACrC,cAAc,aAAa,CAAA"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ApiKeyCredential, ApiKeyRepository } from '../../repositories/index.js';
|
|
2
|
+
/** In-memory credential source intended for tests, demos and bootstrap code. */
|
|
3
|
+
export declare class InMemoryApiKeyRepository implements ApiKeyRepository {
|
|
4
|
+
private readonly keys;
|
|
5
|
+
constructor(keys: Record<string, ApiKeyCredential>);
|
|
6
|
+
findByKey(key: string): ApiKeyCredential | null;
|
|
7
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** In-memory credential source intended for tests, demos and bootstrap code. */
|
|
2
|
+
export class InMemoryApiKeyRepository {
|
|
3
|
+
constructor(keys) {
|
|
4
|
+
this.keys = keys;
|
|
5
|
+
}
|
|
6
|
+
findByKey(key) {
|
|
7
|
+
return this.keys[key] ?? null;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=in-memory-api-key-repository.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"in-memory-api-key-repository.js","sourceRoot":"","sources":["../../../src/infra/in-memory/in-memory-api-key-repository.ts"],"names":[],"mappings":"AAEA,gFAAgF;AAChF,MAAM,OAAO,wBAAwB;IACnC,YAA6B,IAAsC;QAAtC,SAAI,GAAJ,IAAI,CAAkC;IAAG,CAAC;IAEvE,SAAS,CAAC,GAAW;QACnB,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC;IAChC,CAAC;CACF"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { AuthUser } from '@kurdel/common';
|
|
2
|
+
import type { AuthUserRepository } from '../../repositories/index.js';
|
|
3
|
+
/** In-memory identity source intended for tests, demos and bootstrap code. */
|
|
4
|
+
export declare class InMemoryAuthUserRepository implements AuthUserRepository {
|
|
5
|
+
private readonly users;
|
|
6
|
+
constructor(users: AuthUser[]);
|
|
7
|
+
findById(id: string | number): AuthUser | null;
|
|
8
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** In-memory identity source intended for tests, demos and bootstrap code. */
|
|
2
|
+
export class InMemoryAuthUserRepository {
|
|
3
|
+
constructor(users) {
|
|
4
|
+
this.users = users;
|
|
5
|
+
}
|
|
6
|
+
findById(id) {
|
|
7
|
+
return this.users.find(user => user.id === id) ?? null;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=in-memory-auth-user-repository.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"in-memory-auth-user-repository.js","sourceRoot":"","sources":["../../../src/infra/in-memory/in-memory-auth-user-repository.ts"],"names":[],"mappings":"AAIA,8EAA8E;AAC9E,MAAM,OAAO,0BAA0B;IACrC,YAA6B,KAAiB;QAAjB,UAAK,GAAL,KAAK,CAAY;IAAG,CAAC;IAElD,QAAQ,CAAC,EAAmB;QAC1B,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,IAAI,IAAI,CAAC;IACzD,CAAC;CACF"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { AuthUser } from '@kurdel/common';
|
|
2
|
+
import type { JwtRepository } from '../../repositories/index.js';
|
|
3
|
+
import { InMemoryAuthUserRepository } from './in-memory-auth-user-repository.js';
|
|
4
|
+
/** @deprecated Use InMemoryAuthUserRepository. */
|
|
5
|
+
export declare class InMemoryJwtRepository extends InMemoryAuthUserRepository implements JwtRepository {
|
|
6
|
+
constructor(users: AuthUser[]);
|
|
7
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { InMemoryAuthUserRepository } from './in-memory-auth-user-repository.js';
|
|
2
|
+
/** @deprecated Use InMemoryAuthUserRepository. */
|
|
3
|
+
export class InMemoryJwtRepository extends InMemoryAuthUserRepository {
|
|
4
|
+
constructor(users) {
|
|
5
|
+
super(users);
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=in-memory-jwt-repository.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"in-memory-jwt-repository.js","sourceRoot":"","sources":["../../../src/infra/in-memory/in-memory-jwt-repository.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC;AAEjF,kDAAkD;AAClD,MAAM,OAAO,qBACX,SAAQ,0BAA0B;IAElC,YAAY,KAAiB;QAC3B,KAAK,CAAC,KAAK,CAAC,CAAC;IACf,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/infra/in-memory/index.ts"],"names":[],"mappings":"AAAA,cAAc,mCAAmC,CAAC;AAClD,cAAc,qCAAqC,CAAC;AACpD,cAAc,+BAA+B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './in-memory/index.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/infra/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export interface ApiKeyCredential {
|
|
2
|
+
/** Stable credential identifier, when the backing store exposes one. */
|
|
3
|
+
id?: string;
|
|
4
|
+
/** Stable identity resolved after credential validation. */
|
|
5
|
+
userId: string | number;
|
|
6
|
+
/** Revoked credentials must never authenticate. */
|
|
7
|
+
revoked?: boolean;
|
|
8
|
+
/** Optional absolute expiry time. */
|
|
9
|
+
expiresAt?: Date;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* ## ApiKeyRepository
|
|
13
|
+
*
|
|
14
|
+
* Abstraction for retrieving credential metadata by API key.
|
|
15
|
+
*
|
|
16
|
+
* A repository implementation may:
|
|
17
|
+
* - load records from an in-memory map
|
|
18
|
+
* - query a database
|
|
19
|
+
* - read from Redis or any other KV store
|
|
20
|
+
* - call an external authentication service
|
|
21
|
+
*
|
|
22
|
+
* Strategies depend only on this interface, not on the storage details.
|
|
23
|
+
*/
|
|
24
|
+
export interface ApiKeyRepository {
|
|
25
|
+
/**
|
|
26
|
+
* Returns credential metadata associated with the given API key.
|
|
27
|
+
* If the key is unknown, must return `null`.
|
|
28
|
+
*/
|
|
29
|
+
findByKey(key: string): Promise<ApiKeyCredential | null> | ApiKeyCredential | null;
|
|
30
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-key-repository.js","sourceRoot":"","sources":["../../../src/repositories/api-key/api-key-repository.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-key-usage-recorder.js","sourceRoot":"","sources":["../../../src/repositories/api-key/api-key-usage-recorder.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/repositories/api-key/index.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC;AACxC,cAAc,6BAA6B,CAAC"}
|