@kurdel/auth 0.1.0-beta.2 → 0.1.0-beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/README.md +63 -8
  2. package/lib/domain/auth-event.d.ts +3 -0
  3. package/lib/domain/auth-event.js.map +1 -1
  4. package/lib/domain/authorization-policy-composition.d.ts +7 -0
  5. package/lib/domain/authorization-policy-composition.js +45 -0
  6. package/lib/domain/authorization-policy-composition.js.map +1 -0
  7. package/lib/domain/authorization-policy.d.ts +9 -1
  8. package/lib/domain/authorization-policy.js +4 -1
  9. package/lib/domain/authorization-policy.js.map +1 -1
  10. package/lib/domain/index.d.ts +2 -0
  11. package/lib/domain/index.js +2 -0
  12. package/lib/domain/index.js.map +1 -1
  13. package/lib/domain/permission.d.ts +6 -0
  14. package/lib/domain/permission.js +13 -0
  15. package/lib/domain/permission.js.map +1 -0
  16. package/lib/index.d.ts +1 -0
  17. package/lib/index.js +1 -0
  18. package/lib/index.js.map +1 -1
  19. package/lib/password/index.d.ts +3 -0
  20. package/lib/password/index.js +4 -0
  21. package/lib/password/index.js.map +1 -0
  22. package/lib/password/password-authentication-service.d.ts +11 -0
  23. package/lib/password/password-authentication-service.js +19 -0
  24. package/lib/password/password-authentication-service.js.map +1 -0
  25. package/lib/password/password-hasher.d.ts +4 -0
  26. package/lib/password/password-hasher.js +2 -0
  27. package/lib/password/password-hasher.js.map +1 -0
  28. package/lib/password/scrypt-password-hasher.d.ts +21 -0
  29. package/lib/password/scrypt-password-hasher.js +66 -0
  30. package/lib/password/scrypt-password-hasher.js.map +1 -0
  31. package/lib/repositories/index.d.ts +1 -0
  32. package/lib/repositories/index.js +1 -0
  33. package/lib/repositories/index.js.map +1 -1
  34. package/lib/repositories/jwt/index.d.ts +1 -0
  35. package/lib/repositories/jwt/index.js +1 -0
  36. package/lib/repositories/jwt/index.js.map +1 -1
  37. package/lib/repositories/jwt/jwt-session-repository.d.ts +10 -0
  38. package/lib/repositories/jwt/jwt-session-repository.js +2 -0
  39. package/lib/repositories/jwt/jwt-session-repository.js.map +1 -0
  40. package/lib/repositories/password/index.d.ts +1 -0
  41. package/lib/repositories/password/index.js +2 -0
  42. package/lib/repositories/password/index.js.map +1 -0
  43. package/lib/repositories/password/password-credential-repository.d.ts +8 -0
  44. package/lib/repositories/password/password-credential-repository.js +2 -0
  45. package/lib/repositories/password/password-credential-repository.js.map +1 -0
  46. package/lib/runtime/create-auth-middleware.js +4 -2
  47. package/lib/runtime/create-auth-middleware.js.map +1 -1
  48. package/lib/strategies/jwt/jwt-strategy.d.ts +4 -1
  49. package/lib/strategies/jwt/jwt-strategy.js +14 -0
  50. package/lib/strategies/jwt/jwt-strategy.js.map +1 -1
  51. package/lib/tokens.d.ts +3 -0
  52. package/lib/tokens.js +3 -0
  53. package/lib/tokens.js.map +1 -1
  54. package/package.json +4 -4
package/README.md CHANGED
@@ -97,7 +97,9 @@ expressed by roles alone. Register them alongside strategies:
97
97
 
98
98
  ```ts
99
99
  const auth = new AuthModule({
100
- strategies: [/* ... */],
100
+ strategies: [
101
+ /* ... */
102
+ ],
101
103
  policies: [
102
104
  {
103
105
  name: 'manage-users',
@@ -126,14 +128,43 @@ route({
126
128
  ```
127
129
 
128
130
  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.
131
+ return a boolean, an `AuthorizationDecision`, or a promise. Decisions can carry
132
+ a safe reason code that is included in authorization-denied events. When
133
+ several policies are listed, every policy must grant access. Policies and
134
+ `roles` may be combined; both checks must then succeed. A rejected policy
135
+ returns `403 Forbidden`, while an unknown policy is reported as an application
136
+ configuration error.
133
137
 
134
138
  Policy providers also support `useFactory`, allowing policies to resolve
135
139
  application services from the dependency container.
136
140
 
141
+ For role-permission models, strategies may resolve `AuthUser.permissions` and
142
+ policies can use the built-in helpers:
143
+
144
+ ```ts
145
+ import { allOf, anyOf, permissionPolicy } from '@kurdel/auth';
146
+
147
+ const apiKeyOnly = {
148
+ authorize: auth => auth.credential?.type === 'api-key'
149
+ ? { allowed: true }
150
+ : { allowed: false, reason: 'api-key-required' },
151
+ };
152
+ const ownsRequestedUser = {
153
+ authorize: (auth, ctx) => String(auth.user.id) === ctx.params.id
154
+ ? { allowed: true }
155
+ : { allowed: false, reason: 'self-access-required' },
156
+ };
157
+
158
+ const manageUsers = allOf(apiKeyOnly, permissionPolicy('users.manage'));
159
+ const viewUser = anyOf(permissionPolicy('users.view.any'), ownsRequestedUser);
160
+ ```
161
+
162
+ Permissions express reusable capabilities, while policies remain executable
163
+ rules that may also inspect the request, credential, or target resource.
164
+ `allOf`, `anyOf`, and `not` compose policies and short-circuit evaluation while
165
+ preserving a nested denial reason for diagnostics. Boolean policies remain
166
+ fully supported.
167
+
137
168
  ## Security events
138
169
 
139
170
  Configure an event sink to observe sanitized authentication and authorization
@@ -144,14 +175,17 @@ new AuthModule({
144
175
  events: {
145
176
  useFactory: ioc => ioc.get(APP_TOKENS.AuthEventSink),
146
177
  },
147
- strategies: [/* ... */],
178
+ strategies: [
179
+ /* ... */
180
+ ],
148
181
  });
149
182
  ```
150
183
 
151
184
  The package reports successful and failed authentication plus authorization
152
185
  denials. API-key management services may additionally report credential issue
153
186
  and revocation events. Events contain timestamps, strategy names, user and
154
- credential identifiers, safe reason codes, and policy names. Raw API keys,
187
+ credential identifiers, safe reason codes, policy names, and optional policy
188
+ decision reasons. Raw API keys,
155
189
  JWTs, credential hashes, headers, and request bodies are never part of the
156
190
  event contract.
157
191
 
@@ -177,7 +211,8 @@ interface AuthContext {
177
211
  }
178
212
  ```
179
213
 
180
- - `user` is the current application identity and its current roles.
214
+ - `user` is the current application identity, its current roles, and optional
215
+ resolved permissions.
181
216
  - `strategy` is the registered name selected by route metadata.
182
217
  - `credential` identifies the credential kind and, when available, its stable
183
218
  identifier. It never contains the raw API key or JWT.
@@ -191,6 +226,19 @@ the repository credential ID when one exists. The JWT strategy exposes
191
226
  `credential.type` as `jwt`, uses the `jti` claim as its optional ID, and places
192
227
  the verified payload in `claims`.
193
228
 
229
+ To make JWTs revocable before their cryptographic expiration, configure a
230
+ `JwtSessionRepository` on the strategy. Session-backed JWTs must contain a
231
+ `jti`; authentication then verifies that the referenced session exists, belongs
232
+ to the token subject, has not been revoked, and has not expired:
233
+
234
+ ```ts
235
+ new JwtStrategy(jwtService, users, {
236
+ sessions: jwtSessions,
237
+ });
238
+ ```
239
+
240
+ Without `sessions`, JWT verification remains stateless and backward compatible.
241
+
194
242
  ## User and credential repositories
195
243
 
196
244
  Authentication strategies do not own user data. Both built-in strategies load
@@ -213,6 +261,13 @@ credentials with stable IDs. The strategy records usage only after the key is
213
261
  accepted and its current user is resolved; rejected, expired, revoked, and
214
262
  orphaned credentials are never recorded.
215
263
 
264
+ Password login is composed from `PasswordAuthenticationService`, a
265
+ `PasswordCredentialRepository`, and a `PasswordHasher`. The built-in
266
+ `ScryptPasswordHasher` stores a random salt and its work parameters in a
267
+ self-describing encoded value. The service returns the current `AuthUser` only
268
+ after both the password and user state have been verified; unknown logins and
269
+ invalid passwords both return `null`.
270
+
216
271
  For database-backed implementations, use `@kurdel/auth-db`. Applications may
217
272
  also implement these interfaces for another database, an external identity
218
273
  service, or an in-memory test setup.
@@ -16,8 +16,11 @@ export type AuthEvent = (AuthEventBase & {
16
16
  strategy?: string;
17
17
  reason: 'missing-role' | 'missing-authentication' | 'policy-rejected';
18
18
  policy?: string;
19
+ decisionReason?: string;
19
20
  }) | (AuthEventBase & {
20
21
  type: 'api-key.issued' | 'api-key.revoked';
22
+ }) | (AuthEventBase & {
23
+ type: 'jwt-session.created' | 'jwt-session.revoked';
21
24
  });
22
25
  /** Receives sanitized authentication and authorization lifecycle events. */
23
26
  export interface AuthEventSink {
@@ -1 +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"}
1
+ {"version":3,"file":"auth-event.js","sourceRoot":"","sources":["../../src/domain/auth-event.ts"],"names":[],"mappings":"AAqCA,gFAAgF;AAChF,MAAM,OAAO,iBAAiB;IAC5B,MAAM,CAAC,MAAiB,IAAS,CAAC;CACnC"}
@@ -0,0 +1,7 @@
1
+ import { type AuthorizationPolicy } from './authorization-policy.js';
2
+ /** Grants access only when every nested policy grants access. */
3
+ export declare function allOf(...policies: AuthorizationPolicy[]): AuthorizationPolicy;
4
+ /** Grants access when at least one nested policy grants access. */
5
+ export declare function anyOf(...policies: AuthorizationPolicy[]): AuthorizationPolicy;
6
+ /** Inverts a nested policy and uses the supplied reason when inversion denies access. */
7
+ export declare function not(policy: AuthorizationPolicy, reason?: string): AuthorizationPolicy;
@@ -0,0 +1,45 @@
1
+ import { authorizationDecision, } from './authorization-policy.js';
2
+ async function evaluate(policy, auth, ctx) {
3
+ return authorizationDecision(await policy.authorize(auth, ctx));
4
+ }
5
+ /** Grants access only when every nested policy grants access. */
6
+ export function allOf(...policies) {
7
+ return {
8
+ async authorize(auth, ctx) {
9
+ for (const policy of policies) {
10
+ const decision = await evaluate(policy, auth, ctx);
11
+ if (!decision.allowed)
12
+ return decision;
13
+ }
14
+ return { allowed: true };
15
+ },
16
+ };
17
+ }
18
+ /** Grants access when at least one nested policy grants access. */
19
+ export function anyOf(...policies) {
20
+ return {
21
+ async authorize(auth, ctx) {
22
+ let denied = { allowed: false };
23
+ for (const policy of policies) {
24
+ const decision = await evaluate(policy, auth, ctx);
25
+ if (decision.allowed)
26
+ return decision;
27
+ if (decision.reason)
28
+ denied = decision;
29
+ }
30
+ return denied;
31
+ },
32
+ };
33
+ }
34
+ /** Inverts a nested policy and uses the supplied reason when inversion denies access. */
35
+ export function not(policy, reason) {
36
+ return {
37
+ async authorize(auth, ctx) {
38
+ const decision = await evaluate(policy, auth, ctx);
39
+ return decision.allowed
40
+ ? { allowed: false, ...(reason ? { reason } : {}) }
41
+ : { allowed: true };
42
+ },
43
+ };
44
+ }
45
+ //# sourceMappingURL=authorization-policy-composition.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authorization-policy-composition.js","sourceRoot":"","sources":["../../src/domain/authorization-policy-composition.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,qBAAqB,GAGtB,MAAM,2BAA2B,CAAC;AAEnC,KAAK,UAAU,QAAQ,CACrB,MAA2B,EAC3B,IAA2B,EAC3B,GAAgB;IAEhB,OAAO,qBAAqB,CAAC,MAAM,MAAM,CAAC,SAAS,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC;AAClE,CAAC;AAED,iEAAiE;AACjE,MAAM,UAAU,KAAK,CAAC,GAAG,QAA+B;IACtD,OAAO;QACL,KAAK,CAAC,SAAS,CAAC,IAAI,EAAE,GAAG;YACvB,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;gBAC9B,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;gBACnD,IAAI,CAAC,QAAQ,CAAC,OAAO;oBAAE,OAAO,QAAQ,CAAC;YACzC,CAAC;YACD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QAC3B,CAAC;KACF,CAAC;AACJ,CAAC;AAED,mEAAmE;AACnE,MAAM,UAAU,KAAK,CAAC,GAAG,QAA+B;IACtD,OAAO;QACL,KAAK,CAAC,SAAS,CAAC,IAAI,EAAE,GAAG;YACvB,IAAI,MAAM,GAA0B,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;YACvD,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;gBAC9B,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;gBACnD,IAAI,QAAQ,CAAC,OAAO;oBAAE,OAAO,QAAQ,CAAC;gBACtC,IAAI,QAAQ,CAAC,MAAM;oBAAE,MAAM,GAAG,QAAQ,CAAC;YACzC,CAAC;YACD,OAAO,MAAM,CAAC;QAChB,CAAC;KACF,CAAC;AACJ,CAAC;AAED,yFAAyF;AACzF,MAAM,UAAU,GAAG,CAAC,MAA2B,EAAE,MAAe;IAC9D,OAAO;QACL,KAAK,CAAC,SAAS,CAAC,IAAI,EAAE,GAAG;YACvB,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;YACnD,OAAO,QAAQ,CAAC,OAAO;gBACrB,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE;gBACnD,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QACxB,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -1,6 +1,14 @@
1
1
  import type { AuthContext } from '@kurdel/common';
2
2
  import type { HttpContext } from '@kurdel/core/http';
3
+ export type AuthorizationDecision = {
4
+ allowed: boolean;
5
+ /** Safe, non-sensitive reason code suitable for authorization audit events. */
6
+ reason?: string;
7
+ };
8
+ export type AuthorizationPolicyResult = boolean | AuthorizationDecision;
3
9
  /** Performs an application-specific authorization check for a request. */
4
10
  export interface AuthorizationPolicy {
5
- authorize(auth: Readonly<AuthContext>, ctx: HttpContext): boolean | Promise<boolean>;
11
+ authorize(auth: Readonly<AuthContext>, ctx: HttpContext): AuthorizationPolicyResult | Promise<AuthorizationPolicyResult>;
6
12
  }
13
+ /** Converts a boolean-compatible policy result into a diagnostic decision. */
14
+ export declare function authorizationDecision(result: AuthorizationPolicyResult): AuthorizationDecision;
@@ -1,2 +1,5 @@
1
- export {};
1
+ /** Converts a boolean-compatible policy result into a diagnostic decision. */
2
+ export function authorizationDecision(result) {
3
+ return typeof result === 'boolean' ? { allowed: result } : result;
4
+ }
2
5
  //# sourceMappingURL=authorization-policy.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"authorization-policy.js","sourceRoot":"","sources":["../../src/domain/authorization-policy.ts"],"names":[],"mappings":""}
1
+ {"version":3,"file":"authorization-policy.js","sourceRoot":"","sources":["../../src/domain/authorization-policy.ts"],"names":[],"mappings":"AAmBA,8EAA8E;AAC9E,MAAM,UAAU,qBAAqB,CAAC,MAAiC;IACrE,OAAO,OAAO,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;AACpE,CAAC"}
@@ -4,4 +4,6 @@ export * from './auth-event-sink-provider.js';
4
4
  export * from './auth-strategy-provider.js';
5
5
  export * from './auth-strategy.js';
6
6
  export * from './authorization-policy.js';
7
+ export * from './authorization-policy-composition.js';
7
8
  export * from './authorization-policy-provider.js';
9
+ export * from './permission.js';
@@ -4,5 +4,7 @@ export * from './auth-event-sink-provider.js';
4
4
  export * from './auth-strategy-provider.js';
5
5
  export * from './auth-strategy.js';
6
6
  export * from './authorization-policy.js';
7
+ export * from './authorization-policy-composition.js';
7
8
  export * from './authorization-policy-provider.js';
9
+ export * from './permission.js';
8
10
  //# sourceMappingURL=index.js.map
@@ -1 +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"}
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,uCAAuC,CAAC;AACtD,cAAc,oCAAoC,CAAC;AACnD,cAAc,iBAAiB,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { AuthUser } from '@kurdel/common';
2
+ import type { AuthorizationPolicy } from './authorization-policy.js';
3
+ /** Returns whether an authenticated user has a resolved capability. */
4
+ export declare function hasPermission(user: Readonly<AuthUser>, permission: string): boolean;
5
+ /** Creates a policy that requires one resolved permission. */
6
+ export declare function permissionPolicy(permission: string): AuthorizationPolicy;
@@ -0,0 +1,13 @@
1
+ /** Returns whether an authenticated user has a resolved capability. */
2
+ export function hasPermission(user, permission) {
3
+ return user.permissions?.includes(permission) ?? false;
4
+ }
5
+ /** Creates a policy that requires one resolved permission. */
6
+ export function permissionPolicy(permission) {
7
+ return {
8
+ authorize: auth => hasPermission(auth.user, permission)
9
+ ? { allowed: true }
10
+ : { allowed: false, reason: `missing-permission:${permission}` },
11
+ };
12
+ }
13
+ //# sourceMappingURL=permission.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permission.js","sourceRoot":"","sources":["../../src/domain/permission.ts"],"names":[],"mappings":"AAIA,uEAAuE;AACvE,MAAM,UAAU,aAAa,CAAC,IAAwB,EAAE,UAAkB;IACxE,OAAO,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,UAAU,CAAC,IAAI,KAAK,CAAC;AACzD,CAAC;AAED,8DAA8D;AAC9D,MAAM,UAAU,gBAAgB,CAAC,UAAkB;IACjD,OAAO;QACL,SAAS,EAAE,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC;YACrD,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE;YACnB,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,sBAAsB,UAAU,EAAE,EAAE;KACnE,CAAC;AACJ,CAAC"}
package/lib/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export * from './domain/index.js';
2
2
  export * from './infra/index.js';
3
+ export * from './password/index.js';
3
4
  export * from './repositories/index.js';
4
5
  export * from './runtime/index.js';
5
6
  export * from './strategies/index.js';
package/lib/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  export * from './domain/index.js';
2
2
  export * from './infra/index.js';
3
+ export * from './password/index.js';
3
4
  export * from './repositories/index.js';
4
5
  export * from './runtime/index.js';
5
6
  export * from './strategies/index.js';
package/lib/index.js.map CHANGED
@@ -1 +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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,yBAAyB,CAAA;AACvC,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAA;AACrC,cAAc,aAAa,CAAA"}
@@ -0,0 +1,3 @@
1
+ export * from './password-authentication-service.js';
2
+ export * from './password-hasher.js';
3
+ export * from './scrypt-password-hasher.js';
@@ -0,0 +1,4 @@
1
+ export * from './password-authentication-service.js';
2
+ export * from './password-hasher.js';
3
+ export * from './scrypt-password-hasher.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/password/index.ts"],"names":[],"mappings":"AAAA,cAAc,sCAAsC,CAAC;AACrD,cAAc,sBAAsB,CAAC;AACrC,cAAc,6BAA6B,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { AuthUser } from '@kurdel/common';
2
+ import type { PasswordCredentialRepository } from '../repositories/password/index.js';
3
+ import type { AuthUserRepository } from '../repositories/user/index.js';
4
+ import type { PasswordHasher } from './password-hasher.js';
5
+ export declare class PasswordAuthenticationService {
6
+ private readonly credentials;
7
+ private readonly users;
8
+ private readonly hasher;
9
+ constructor(credentials: PasswordCredentialRepository, users: AuthUserRepository, hasher: PasswordHasher);
10
+ authenticate(login: string, password: string): Promise<AuthUser | null>;
11
+ }
@@ -0,0 +1,19 @@
1
+ export class PasswordAuthenticationService {
2
+ constructor(credentials, users, hasher) {
3
+ this.credentials = credentials;
4
+ this.users = users;
5
+ this.hasher = hasher;
6
+ }
7
+ async authenticate(login, password) {
8
+ const credential = await this.credentials.findByLogin(login);
9
+ if (!credential) {
10
+ // Keep the expensive password operation on the unknown-login path too.
11
+ await this.hasher.hash(password);
12
+ return null;
13
+ }
14
+ if (!(await this.hasher.verify(password, credential.passwordHash)))
15
+ return null;
16
+ return this.users.findById(credential.userId);
17
+ }
18
+ }
19
+ //# sourceMappingURL=password-authentication-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"password-authentication-service.js","sourceRoot":"","sources":["../../src/password/password-authentication-service.ts"],"names":[],"mappings":"AAMA,MAAM,OAAO,6BAA6B;IACxC,YACmB,WAAyC,EACzC,KAAyB,EACzB,MAAsB;QAFtB,gBAAW,GAAX,WAAW,CAA8B;QACzC,UAAK,GAAL,KAAK,CAAoB;QACzB,WAAM,GAAN,MAAM,CAAgB;IACtC,CAAC;IAEJ,KAAK,CAAC,YAAY,CAAC,KAAa,EAAE,QAAgB;QAChD,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QAC7D,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,uEAAuE;YACvE,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACjC,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,UAAU,CAAC,YAAY,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;QAChF,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;IAChD,CAAC;CACF"}
@@ -0,0 +1,4 @@
1
+ export interface PasswordHasher {
2
+ hash(password: string): Promise<string> | string;
3
+ verify(password: string, encodedHash: string): Promise<boolean> | boolean;
4
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=password-hasher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"password-hasher.js","sourceRoot":"","sources":["../../src/password/password-hasher.ts"],"names":[],"mappings":""}
@@ -0,0 +1,21 @@
1
+ import type { PasswordHasher } from './password-hasher.js';
2
+ export interface ScryptPasswordHasherOptions {
3
+ cost?: number;
4
+ blockSize?: number;
5
+ parallelization?: number;
6
+ keyLength?: number;
7
+ saltLength?: number;
8
+ }
9
+ /** Password hasher with a self-describing format that supports future rehashing. */
10
+ export declare class ScryptPasswordHasher implements PasswordHasher {
11
+ private readonly cost;
12
+ private readonly blockSize;
13
+ private readonly parallelization;
14
+ private readonly keyLength;
15
+ private readonly saltLength;
16
+ constructor(options?: ScryptPasswordHasherOptions);
17
+ hash(password: string): Promise<string>;
18
+ verify(password: string, encodedHash: string): Promise<boolean>;
19
+ private derive;
20
+ private validParameters;
21
+ }
@@ -0,0 +1,66 @@
1
+ import crypto from 'node:crypto';
2
+ /** Password hasher with a self-describing format that supports future rehashing. */
3
+ export class ScryptPasswordHasher {
4
+ constructor(options = {}) {
5
+ this.cost = options.cost ?? 16384;
6
+ this.blockSize = options.blockSize ?? 8;
7
+ this.parallelization = options.parallelization ?? 1;
8
+ this.keyLength = options.keyLength ?? 64;
9
+ this.saltLength = options.saltLength ?? 16;
10
+ }
11
+ async hash(password) {
12
+ const salt = crypto.randomBytes(this.saltLength);
13
+ const derived = await this.derive(password, salt, this.cost, this.blockSize, this.parallelization, this.keyLength);
14
+ return [
15
+ 'scrypt',
16
+ this.cost,
17
+ this.blockSize,
18
+ this.parallelization,
19
+ salt.toString('base64url'),
20
+ derived.toString('base64url'),
21
+ ].join('$');
22
+ }
23
+ async verify(password, encodedHash) {
24
+ const parts = encodedHash.split('$');
25
+ if (parts.length !== 6 || parts[0] !== 'scrypt')
26
+ return false;
27
+ const [cost, blockSize, parallelization] = parts.slice(1, 4).map(Number);
28
+ const salt = Buffer.from(parts[4], 'base64url');
29
+ const expected = Buffer.from(parts[5], 'base64url');
30
+ if (!this.validParameters(cost, blockSize, parallelization, salt, expected))
31
+ return false;
32
+ try {
33
+ const actual = await this.derive(password, salt, cost, blockSize, parallelization, expected.length);
34
+ return crypto.timingSafeEqual(actual, expected);
35
+ }
36
+ catch {
37
+ return false;
38
+ }
39
+ }
40
+ async derive(password, salt, cost, blockSize, parallelization, keyLength) {
41
+ return new Promise((resolve, reject) => {
42
+ crypto.scrypt(password, salt, keyLength, {
43
+ N: cost,
44
+ r: blockSize,
45
+ p: parallelization,
46
+ maxmem: Math.max(32 * 1024 * 1024, 256 * cost * blockSize),
47
+ }, (error, derivedKey) => (error ? reject(error) : resolve(derivedKey)));
48
+ });
49
+ }
50
+ validParameters(cost, blockSize, parallelization, salt, hash) {
51
+ return (Number.isInteger(cost) &&
52
+ cost >= 1024 &&
53
+ cost <= 1048576 &&
54
+ Number.isInteger(blockSize) &&
55
+ blockSize >= 1 &&
56
+ blockSize <= 32 &&
57
+ Number.isInteger(parallelization) &&
58
+ parallelization >= 1 &&
59
+ parallelization <= 16 &&
60
+ salt.length >= 8 &&
61
+ salt.length <= 64 &&
62
+ hash.length >= 32 &&
63
+ hash.length <= 128);
64
+ }
65
+ }
66
+ //# sourceMappingURL=scrypt-password-hasher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scrypt-password-hasher.js","sourceRoot":"","sources":["../../src/password/scrypt-password-hasher.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
1
  export * from './api-key/index.js';
2
2
  export * from './jwt/index.js';
3
+ export * from './password/index.js';
3
4
  export * from './user/index.js';
@@ -1,4 +1,5 @@
1
1
  export * from './api-key/index.js';
2
2
  export * from './jwt/index.js';
3
+ export * from './password/index.js';
3
4
  export * from './user/index.js';
4
5
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/repositories/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/repositories/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC"}
@@ -1 +1,2 @@
1
1
  export * from './jwt-repository.js';
2
+ export * from './jwt-session-repository.js';
@@ -1,2 +1,3 @@
1
1
  export * from './jwt-repository.js';
2
+ export * from './jwt-session-repository.js';
2
3
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/repositories/jwt/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/repositories/jwt/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,6BAA6B,CAAC"}
@@ -0,0 +1,10 @@
1
+ export type JwtSession = {
2
+ id: string;
3
+ userId: string | number;
4
+ revoked: boolean;
5
+ expiresAt?: Date;
6
+ };
7
+ /** Resolves server-side JWT session state used for token revocation. */
8
+ export interface JwtSessionRepository {
9
+ findById(id: string): Promise<JwtSession | null>;
10
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=jwt-session-repository.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwt-session-repository.js","sourceRoot":"","sources":["../../../src/repositories/jwt/jwt-session-repository.ts"],"names":[],"mappings":""}
@@ -0,0 +1 @@
1
+ export * from './password-credential-repository.js';
@@ -0,0 +1,2 @@
1
+ export * from './password-credential-repository.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/repositories/password/index.ts"],"names":[],"mappings":"AAAA,cAAc,qCAAqC,CAAC"}
@@ -0,0 +1,8 @@
1
+ export interface PasswordCredential {
2
+ userId: string | number;
3
+ passwordHash: string;
4
+ }
5
+ /** Resolves a password credential by an application-defined login. */
6
+ export interface PasswordCredentialRepository {
7
+ findByLogin(login: string): Promise<PasswordCredential | null> | PasswordCredential | null;
8
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=password-credential-repository.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"password-credential-repository.js","sourceRoot":"","sources":["../../../src/repositories/password/password-credential-repository.ts"],"names":[],"mappings":""}
@@ -1,4 +1,4 @@
1
- import { NoopAuthEventSink } from '../domain/index.js';
1
+ import { authorizationDecision, NoopAuthEventSink, } from '../domain/index.js';
2
2
  import { AuthorizationPolicyRegistry } from './authorization-policy-registry.js';
3
3
  export function createAuthMiddleware(registry, policies = new AuthorizationPolicyRegistry(), events = new NoopAuthEventSink(), now = () => new Date()) {
4
4
  return async (ctx, next) => {
@@ -69,7 +69,8 @@ export function createAuthMiddleware(registry, policies = new AuthorizationPolic
69
69
  if (!policy) {
70
70
  return ctx.json(500, { error: `Unknown authorization policy '${name}'` });
71
71
  }
72
- if (!(await policy.authorize(auth, ctx))) {
72
+ const decision = authorizationDecision(await policy.authorize(auth, ctx));
73
+ if (!decision.allowed) {
73
74
  await events.report({
74
75
  type: 'authorization.denied',
75
76
  occurredAt: now(),
@@ -78,6 +79,7 @@ export function createAuthMiddleware(registry, policies = new AuthorizationPolic
78
79
  ...(auth.credential ? { credential: auth.credential } : {}),
79
80
  reason: 'policy-rejected',
80
81
  policy: name,
82
+ ...(decision.reason ? { decisionReason: decision.reason } : {}),
81
83
  });
82
84
  return ctx.json(403, { error: 'Forbidden' });
83
85
  }
@@ -1 +1 @@
1
- {"version":3,"file":"create-auth-middleware.js","sourceRoot":"","sources":["../../src/runtime/create-auth-middleware.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"create-auth-middleware.js","sourceRoot":"","sources":["../../src/runtime/create-auth-middleware.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import type { HttpRequest } from '@kurdel/common';
2
2
  import type { AuthenticationResult, AuthStrategy } from '../../domain/index.js';
3
- import type { AuthUserRepository } from '../../repositories/index.js';
3
+ import type { AuthUserRepository, JwtSessionRepository } from '../../repositories/index.js';
4
4
  import type { JwtService } from '../../strategies/index.js';
5
5
  /**
6
6
  * ## JwtStrategyOptions
@@ -10,6 +10,8 @@ import type { JwtService } from '../../strategies/index.js';
10
10
  export interface JwtStrategyOptions {
11
11
  header?: string;
12
12
  prefix?: string;
13
+ /** When configured, every token must reference an active session through `jti`. */
14
+ sessions?: JwtSessionRepository;
13
15
  }
14
16
  /**
15
17
  * ## JwtStrategy
@@ -22,6 +24,7 @@ export declare class JwtStrategy implements AuthStrategy {
22
24
  private readonly users;
23
25
  private readonly header;
24
26
  private readonly prefix;
27
+ private readonly sessions?;
25
28
  constructor(service: JwtService, users: AuthUserRepository, opts?: JwtStrategyOptions);
26
29
  authenticate(req: HttpRequest): Promise<AuthenticationResult | null>;
27
30
  }
@@ -10,6 +10,7 @@ export class JwtStrategy {
10
10
  this.users = users;
11
11
  this.header = (opts.header ?? 'authorization').toLowerCase();
12
12
  this.prefix = (opts.prefix ?? 'Bearer').toLowerCase();
13
+ this.sessions = opts.sessions;
13
14
  }
14
15
  async authenticate(req) {
15
16
  const raw = req.headers?.[this.header];
@@ -25,6 +26,19 @@ export class JwtStrategy {
25
26
  const payload = this.service.verify(token);
26
27
  if (!payload.sub)
27
28
  return null;
29
+ if (this.sessions) {
30
+ if (typeof payload.jti !== 'string')
31
+ return null;
32
+ const session = await this.sessions.findById(payload.jti);
33
+ if (!session || session.revoked || String(session.userId) !== String(payload.sub)) {
34
+ return null;
35
+ }
36
+ if (session.expiresAt) {
37
+ const expiresAt = session.expiresAt.getTime();
38
+ if (!Number.isFinite(expiresAt) || expiresAt <= Date.now())
39
+ return null;
40
+ }
41
+ }
28
42
  const user = await this.users.findById(payload.sub);
29
43
  if (!user)
30
44
  return null;
@@ -1 +1 @@
1
- {"version":3,"file":"jwt-strategy.js","sourceRoot":"","sources":["../../../src/strategies/jwt/jwt-strategy.ts"],"names":[],"mappings":"AAgBA;;;;;GAKG;AACH,MAAM,OAAO,WAAW;IAItB,YACmB,OAAmB,EACnB,KAAyB,EAC1C,OAA2B,EAAE;QAFZ,YAAO,GAAP,OAAO,CAAY;QACnB,UAAK,GAAL,KAAK,CAAoB;QAG1C,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,MAAM,IAAI,eAAe,CAAC,CAAC,WAAW,EAAE,CAAC;QAC7D,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,MAAM,IAAI,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;IACxD,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,GAAgB;QACjC,MAAM,GAAG,GAAG,GAAG,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACvC,IAAI,CAAC,GAAG;YAAE,OAAO,IAAI,CAAC;QAEtB,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;QAC9C,MAAM,KAAK,GAAG,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAExD,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC;YAC/D,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;QAErD,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAE3C,IAAI,CAAC,OAAO,CAAC,GAAG;gBAAE,OAAO,IAAI,CAAC;YAE9B,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YACpD,IAAI,CAAC,IAAI;gBAAE,OAAO,IAAI,CAAC;YAEvB,OAAO;gBACL,IAAI;gBACJ,UAAU,EAAE;oBACV,IAAI,EAAE,KAAK;oBACX,GAAG,CAAC,OAAO,OAAO,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;iBAChE;gBACD,MAAM,EAAE,OAAO;aAChB,CAAC;QACJ,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;CACF"}
1
+ {"version":3,"file":"jwt-strategy.js","sourceRoot":"","sources":["../../../src/strategies/jwt/jwt-strategy.ts"],"names":[],"mappings":"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"}
package/lib/tokens.d.ts CHANGED
@@ -7,5 +7,8 @@ export declare const AUTH_TOKENS: {
7
7
  JwtRepository: symbol;
8
8
  ApiKeyRepository: symbol;
9
9
  ApiKeyUsageRecorder: symbol;
10
+ JwtSessionRepository: symbol;
11
+ PasswordCredentialRepository: symbol;
12
+ PasswordAuthenticationService: symbol;
10
13
  JwtService: symbol;
11
14
  };
package/lib/tokens.js CHANGED
@@ -8,6 +8,9 @@ export const AUTH_TOKENS = {
8
8
  JwtRepository: UserRepository,
9
9
  ApiKeyRepository: Symbol('ApiKeyRepository'),
10
10
  ApiKeyUsageRecorder: Symbol('ApiKeyUsageRecorder'),
11
+ JwtSessionRepository: Symbol('JwtSessionRepository'),
12
+ PasswordCredentialRepository: Symbol('PasswordCredentialRepository'),
13
+ PasswordAuthenticationService: Symbol('PasswordAuthenticationService'),
11
14
  JwtService: Symbol('JwtService'),
12
15
  };
13
16
  //# sourceMappingURL=tokens.js.map
package/lib/tokens.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"tokens.js","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"AAAA,MAAM,cAAc,GAAG,MAAM,CAAC,oBAAoB,CAAC,CAAC;AAEpD,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,gBAAgB,EAAE,MAAM,CAAC,sBAAsB,CAAC;IAChD,cAAc,EAAE,MAAM,CAAC,6BAA6B,CAAC;IACrD,SAAS,EAAE,MAAM,CAAC,eAAe,CAAC;IAClC,cAAc;IACd,sCAAsC;IACtC,aAAa,EAAE,cAAc;IAC7B,gBAAgB,EAAE,MAAM,CAAC,kBAAkB,CAAC;IAC5C,mBAAmB,EAAE,MAAM,CAAC,qBAAqB,CAAC;IAClD,UAAU,EAAE,MAAM,CAAC,YAAY,CAAC;CACjC,CAAC"}
1
+ {"version":3,"file":"tokens.js","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"AAAA,MAAM,cAAc,GAAG,MAAM,CAAC,oBAAoB,CAAC,CAAC;AAEpD,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,gBAAgB,EAAE,MAAM,CAAC,sBAAsB,CAAC;IAChD,cAAc,EAAE,MAAM,CAAC,6BAA6B,CAAC;IACrD,SAAS,EAAE,MAAM,CAAC,eAAe,CAAC;IAClC,cAAc;IACd,sCAAsC;IACtC,aAAa,EAAE,cAAc;IAC7B,gBAAgB,EAAE,MAAM,CAAC,kBAAkB,CAAC;IAC5C,mBAAmB,EAAE,MAAM,CAAC,qBAAqB,CAAC;IAClD,oBAAoB,EAAE,MAAM,CAAC,sBAAsB,CAAC;IACpD,4BAA4B,EAAE,MAAM,CAAC,8BAA8B,CAAC;IACpE,6BAA6B,EAAE,MAAM,CAAC,+BAA+B,CAAC;IACtE,UAAU,EAAE,MAAM,CAAC,YAAY,CAAC;CACjC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kurdel/auth",
3
- "version": "0.1.0-beta.2",
3
+ "version": "0.1.0-beta.4",
4
4
  "description": "Authentication and authorization primitives for Kurdel applications",
5
5
  "type": "module",
6
6
  "exports": {
@@ -49,8 +49,8 @@
49
49
  "tsc-alias": "^1.8.16"
50
50
  },
51
51
  "dependencies": {
52
- "@kurdel/common": "0.1.0-beta.2",
53
- "@kurdel/core": "0.1.0-beta.2",
54
- "@kurdel/ioc": "0.1.0-beta.2"
52
+ "@kurdel/common": "0.1.0-beta.4",
53
+ "@kurdel/core": "0.1.0-beta.4",
54
+ "@kurdel/ioc": "0.1.0-beta.4"
55
55
  }
56
56
  }