@owlmeans/server-auth 0.1.18-rc.35 → 0.1.18-rc.36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -13,7 +13,7 @@ account/profile records `@owlmeans/server-auth-identity`, and the browser side `
13
13
  ## Installation
14
14
 
15
15
  ```bash
16
- bun add @owlmeans/server-auth@^0.1.18-rc.35
16
+ bun add @owlmeans/server-auth@^0.1.18-rc.36
17
17
  ```
18
18
 
19
19
  ## Concepts
@@ -222,7 +222,7 @@ This package ships embedded agent skills under `agent-meta/`. After installing y
222
222
  your project's skill store (`.agents/skills/`):
223
223
 
224
224
  ```sh
225
- npx @owlmeans/agent-skills@^0.1.18-rc.28
225
+ npx @owlmeans/agent-skills@^0.1.18-rc.30
226
226
  ```
227
227
 
228
228
  The embedded files are version-matched to this package release. Do not edit them
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": 2,
3
3
  "package": "@owlmeans/server-auth",
4
- "version": "0.1.18-rc.35",
5
- "generatedAt": "2026-09-17T08:16:11.216Z",
4
+ "version": "0.1.18-rc.36",
5
+ "generatedAt": "2026-09-19T13:42:56.244Z",
6
6
  "canonicalRepo": "https://github.com/owlmeans/common",
7
7
  "entries": [
8
8
  {
@@ -8,7 +8,7 @@ user-invocable: false
8
8
  # @owlmeans/server-auth
9
9
 
10
10
  **Layer:** Server
11
- **Install:** `"@owlmeans/server-auth": "^0.1.18-rc.35"` in `dependencies`
11
+ **Install:** `"@owlmeans/server-auth": "^0.1.18-rc.36"` in `dependencies`
12
12
 
13
13
  Two halves, deliberately split by subpath:
14
14
 
@@ -30,6 +30,7 @@ An ordinary service imports the root. Only the auth manager imports `./manager`.
30
30
  | `AUTH_CACHE` | `'auth-cache'` — the single-use challenge store |
31
31
  | `AUTH_SRV_KEY` | `'auth-service'` — the TRUSTED record whose key signs credential envelopes |
32
32
  | `AUTHEN_TIMEFRAME` | `15 * 60 * 1000` — challenge lifetime and anti-replay window, in ms |
33
+ | `AUTH_SESSION_MANAGER` / `appendMemoryAuthSessionManager` | Seven-day session registry contract and the process-local default; use the Redis implementation from `@owlmeans/server-auth-session` for a shared authority |
33
34
  | `AuthService`, `AuthServiceAppend`, `AuthSpent` | Types |
34
35
  | `makeRelyModel`, `makeProviderRely`, `makeConsumerRely`, `RelyOptions` | The rely (wallet handshake) models |
35
36
 
@@ -103,6 +104,13 @@ registerPlugin('my-method', context => ({
103
104
  register a Redis resource under the same alias before calling it in any scaled deployment.
104
105
  - A plugin's `init` must return a challenge that is unique per request. A challenge that repeats
105
106
  across independent attempts collides in `AUTH_CACHE` and surfaces as `AuthenFailed('challenge')`.
107
+ - Bearers issued by this service carry an absolute seven-day expiry and an opaque session id. In a
108
+ context with `AUTH_SESSION_MANAGER`, the guard rejects an absent, expired, pending or revoked
109
+ session and re-signs fresh profile claims after a registry revision. Registry or identity-store
110
+ failure is `AuthUnavailable` (503), never a false 401/logout.
111
+ - `appendAuthService` installs the memory session manager only as a single-process default. A
112
+ central or multi-replica issuer registers `appendRedisAuthSessionManager(context)` before it;
113
+ the manager is the authority that fences, refreshes or revokes an organization profile's sessions.
106
114
  - The manager canonicalizes the organization entity: whatever slug (current, retired, or the frozen
107
115
  key) a plugin leaves on `credential.entitySlug` is resolved through `ENTITY_RESOLVER` and replaced
108
116
  with the current slug before the envelope is signed. An unresolvable value throws
@@ -1,9 +1,3 @@
1
1
  /** Server entrypoints for the full authentication manager. */
2
- export declare const entrypoints: (import("@owlmeans/server-entrypoint").ServerProtocolEntrypoint<import("@owlmeans/entrypoint").EntrypointProtocol<import("@owlmeans/entrypoint").OpenRequest, import("@owlmeans/entrypoint").OpenValue>> | import("@owlmeans/server-entrypoint").ServerProtocolEntrypoint<import("@owlmeans/entrypoint").EntrypointProtocol<{
3
- body: import("@owlmeans/auth").AllowanceRequest;
4
- }, import("@owlmeans/auth").AllowanceResponse>> | import("@owlmeans/server-entrypoint").ServerProtocolEntrypoint<import("@owlmeans/entrypoint").EntrypointProtocol<{
5
- body: import("@owlmeans/auth").AuthCredentials;
6
- }, import("@owlmeans/auth").AuthToken>> | import("@owlmeans/server-entrypoint").ServerProtocolEntrypoint<import("@owlmeans/entrypoint").EntrypointProtocol<{
7
- query: Partial<import("@owlmeans/auth").AuthToken>;
8
- }, undefined>>)[];
2
+ export declare const entrypoints: any[];
9
3
  //# sourceMappingURL=entrypoints.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"entrypoints.d.ts","sourceRoot":"","sources":["../../src/manager/entrypoints.ts"],"names":[],"mappings":"AAiBA,8DAA8D;AAC9D,eAAO,MAAM,WAAW;;;;;;iBAOvB,CAAA"}
1
+ {"version":3,"file":"entrypoints.d.ts","sourceRoot":"","sources":["../../src/manager/entrypoints.ts"],"names":[],"mappings":"AAiBA,8DAA8D;AAC9D,eAAO,MAAM,WAAW,OAOvB,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../src/manager/model.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAkBlE,eAAO,MAAM,aAAa,YAAa,UAAU,CAAC,SAAS,CAAC,KAAG,SAyF9D,CAAA"}
1
+ {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../src/manager/model.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAmBlE,eAAO,MAAM,aAAa,YAAa,UAAU,CAAC,SAAS,CAAC,KAAG,SA2F9D,CAAA"}
@@ -5,6 +5,7 @@ import { AUTH_CACHE, AUTHEN_TIMEFRAME } from '../consts.js';
5
5
  import { EnvelopeKind, makeEnvelopeModel } from '@owlmeans/basic-envelope';
6
6
  import { createRelyFlow } from './rely/flow.js';
7
7
  import { trusted } from './utils/trusted.js';
8
+ import { AuthChallengeReplayPolicy } from './plugins/replay-policy.js';
8
9
  export const makeAuthModel = (context) => {
9
10
  const cache = (context) => context.resource(AUTH_CACHE);
10
11
  const model = {
@@ -31,20 +32,22 @@ export const makeAuthModel = (context) => {
31
32
  throw new AuthenFailed('challenge');
32
33
  }
33
34
  const msg = envelope.message(true);
34
- try {
35
- await cache(context).create({ id: msg }, { ttl: (envelope.envelope.ttl ?? AUTHEN_TIMEFRAME) / 1000 });
36
- }
37
- catch (e) {
38
- const error = new AuthenFailed('challenge');
39
- if (e instanceof Error) {
40
- error.oiriginalStack = `${e} : ${e.stack}`;
35
+ const plugin = await getPlugin(envelope.type(), context);
36
+ if (plugin.challengeReplayPolicy !== AuthChallengeReplayPolicy.Plugin) {
37
+ try {
38
+ await cache(context).create({ id: msg }, { ttl: (envelope.envelope.ttl ?? AUTHEN_TIMEFRAME) / 1000 });
39
+ }
40
+ catch (e) {
41
+ const error = new AuthenFailed('challenge');
42
+ if (e instanceof Error) {
43
+ error.oiriginalStack = `${e} : ${e.stack}`;
44
+ }
45
+ throw error;
41
46
  }
42
- throw error;
43
47
  }
44
48
  if (credential.userId == null) {
45
49
  throw new AuthenPayloadError('userId');
46
50
  }
47
- const plugin = await getPlugin(envelope.type(), context);
48
51
  // @TODO this token PROBABLY needs to be registered somewhere and rechecked
49
52
  // from time to time to make sure that the session is not deleted
50
53
  // or permission hasn't changed.
@@ -1 +1 @@
1
- {"version":3,"file":"model.js","sourceRoot":"","sources":["../../src/manager/model.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"model.js","sourceRoot":"","sources":["../../src/manager/model.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  export type * from './types.js';
2
+ export * from './replay-policy.js';
2
3
  export * from './basic-ed25519.js';
3
4
  export * from './re-captcha.js';
4
5
  export * from './basic-rely.js';
@@ -1 +1 @@
1
- {"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../../../src/manager/plugins/export.ts"],"names":[],"mappings":"AACA,mBAAmB,YAAY,CAAA;AAC/B,cAAc,oBAAoB,CAAA;AAClC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,YAAY,CAAA;AAC1B,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA"}
1
+ {"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../../../src/manager/plugins/export.ts"],"names":[],"mappings":"AACA,mBAAmB,YAAY,CAAA;AAC/B,cAAc,oBAAoB,CAAA;AAClC,cAAc,oBAAoB,CAAA;AAClC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,YAAY,CAAA;AAC1B,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA"}
@@ -1,3 +1,4 @@
1
+ export * from './replay-policy.js';
1
2
  export * from './basic-ed25519.js';
2
3
  export * from './re-captcha.js';
3
4
  export * from './basic-rely.js';
@@ -1 +1 @@
1
- {"version":3,"file":"export.js","sourceRoot":"","sources":["../../../src/manager/plugins/export.ts"],"names":[],"mappings":"AAEA,cAAc,oBAAoB,CAAA;AAClC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,YAAY,CAAA;AAC1B,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA"}
1
+ {"version":3,"file":"export.js","sourceRoot":"","sources":["../../../src/manager/plugins/export.ts"],"names":[],"mappings":"AAEA,cAAc,oBAAoB,CAAA;AAClC,cAAc,oBAAoB,CAAA;AAClC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,YAAY,CAAA;AAC1B,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA"}
@@ -0,0 +1,8 @@
1
+ /** Ownership of atomic replay protection for a verified authentication challenge. */
2
+ export declare enum AuthChallengeReplayPolicy {
3
+ /** Default: the auth manager consumes the challenge before plugin authentication. */
4
+ Manager = "manager",
5
+ /** The plugin owns bounded attempts and atomic success consumption. */
6
+ Plugin = "plugin"
7
+ }
8
+ //# sourceMappingURL=replay-policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replay-policy.d.ts","sourceRoot":"","sources":["../../../src/manager/plugins/replay-policy.ts"],"names":[],"mappings":"AAAA,qFAAqF;AACrF,oBAAY,yBAAyB;IACnC,qFAAqF;IACrF,OAAO,YAAY;IACnB,uEAAuE;IACvE,MAAM,WAAW;CAClB"}
@@ -0,0 +1,9 @@
1
+ /** Ownership of atomic replay protection for a verified authentication challenge. */
2
+ export var AuthChallengeReplayPolicy;
3
+ (function (AuthChallengeReplayPolicy) {
4
+ /** Default: the auth manager consumes the challenge before plugin authentication. */
5
+ AuthChallengeReplayPolicy["Manager"] = "manager";
6
+ /** The plugin owns bounded attempts and atomic success consumption. */
7
+ AuthChallengeReplayPolicy["Plugin"] = "plugin";
8
+ })(AuthChallengeReplayPolicy || (AuthChallengeReplayPolicy = {}));
9
+ //# sourceMappingURL=replay-policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replay-policy.js","sourceRoot":"","sources":["../../../src/manager/plugins/replay-policy.ts"],"names":[],"mappings":"AAAA,qFAAqF;AACrF,MAAM,CAAN,IAAY,yBAKX;AALD,WAAY,yBAAyB;IACnC,qFAAqF;IACrF,gDAAmB,CAAA;IACnB,uEAAuE;IACvE,8CAAiB,CAAA;AACnB,CAAC,EALW,yBAAyB,KAAzB,yBAAyB,QAKpC"}
@@ -3,8 +3,14 @@ import type { AuthModel } from '../types.js';
3
3
  import type { AbstractRequest } from '@owlmeans/entrypoint';
4
4
  import type { RedisResource } from '@owlmeans/redis-resource';
5
5
  import type { ResourceRecord } from '@owlmeans/resource';
6
+ import type { AuthChallengeReplayPolicy } from './replay-policy.js';
6
7
  export interface AuthPlugin extends Omit<AuthModel, "rely"> {
7
8
  type: string;
9
+ /**
10
+ * Who atomically consumes a verified challenge. The manager remains the default; a plugin may
11
+ * opt in only when its own credential protocol needs a bounded retry budget before consumption.
12
+ */
13
+ challengeReplayPolicy?: AuthChallengeReplayPolicy;
8
14
  }
9
15
  export interface RecpatchaResponse {
10
16
  success: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/manager/plugins/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AACvD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAExD,MAAM,WAAW,UAAW,SAAQ,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC;IACzD,IAAI,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAA;IAChB,YAAY,EAAE,MAAM,CAAA;IACpB,QAAQ,EAAE,MAAM,CAAA;IAChB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;CACzB;AAED,MAAM,WAAW,gBAAiB,SAAQ,eAAe,CAAC;IACxD,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB,CAAC;CAAI;AAEN,MAAM,WAAW,UAAW,SAAQ,cAAc,EAAE,iBAAiB;CACpE;AAED,MAAM,WAAW,iBAAkB,SAAQ,aAAa,CAAC,UAAU,CAAC;CAAG"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/manager/plugins/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AACvD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AACxD,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAA;AAEnE,MAAM,WAAW,UAAW,SAAQ,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC;IACzD,IAAI,EAAE,MAAM,CAAA;IACZ;;;OAGG;IACH,qBAAqB,CAAC,EAAE,yBAAyB,CAAA;CAClD;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAA;IAChB,YAAY,EAAE,MAAM,CAAA;IACpB,QAAQ,EAAE,MAAM,CAAA;IAChB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;CACzB;AAED,MAAM,WAAW,gBAAiB,SAAQ,eAAe,CAAC;IACxD,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB,CAAC;CAAI;AAEN,MAAM,WAAW,UAAW,SAAQ,cAAc,EAAE,iBAAiB;CACpE;AAED,MAAM,WAAW,iBAAkB,SAAQ,aAAa,CAAC,UAAU,CAAC;CAAG"}
@@ -1 +1 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAG3E,OAAO,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAa,MAAM,YAAY,CAAA;AAU3E,KAAK,MAAM,GAAG,YAAY,CAAA;AAG1B,eAAO,MAAM,eAAe,WAAW,MAAM,KAAmB,WA4F/D,CAAA;AAED,eAAO,MAAM,iBAAiB,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,aAAa,CAAC,CAAC,CAAC,OACvE,CAAC,UAAS,MAAM,KACpB,CAAC,GAAG,iBAaN,CAAA"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAG3E,OAAO,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAa,MAAM,YAAY,CAAA;AAoB3E,KAAK,MAAM,GAAG,YAAY,CAAA;AAG1B,eAAO,MAAM,eAAe,WAAW,MAAM,KAAmB,WAqL/D,CAAA;AAED,eAAO,MAAM,iBAAiB,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,aAAa,CAAC,CAAC,CAAC,OACvE,CAAC,UAAS,MAAM,KACpB,CAAC,GAAG,iBAiBN,CAAA"}
package/build/service.js CHANGED
@@ -2,12 +2,61 @@ import { TRUSTED } from '@owlmeans/config';
2
2
  import { AUTH_CACHE, AUTH_SRV_KEY, AUTHEN_TIMEFRAME, DEFAULT_ALIAS } from './consts.js';
3
3
  import { assertContext, createService } from '@owlmeans/context';
4
4
  import { EnvelopeKind, makeEnvelopeModel } from '@owlmeans/basic-envelope';
5
- import { AuthenFailed, AuthorizationError, AuthroizationType } from '@owlmeans/auth';
5
+ import { AuthenFailed, AuthorizationError, AuthroizationType, AuthUnavailable } from '@owlmeans/auth';
6
6
  import { createStaticResource } from '@owlmeans/static-resource';
7
7
  import { trust, extractAuthToken } from '@owlmeans/auth-common/utils';
8
+ import { ENTITY_RESOLVER } from '@owlmeans/auth-common';
9
+ import { AUTH_IDENTITY_PROFILE } from '@owlmeans/server-auth-identity';
10
+ import { appendMemoryAuthSessionManager, AUTH_SESSION_MANAGER, AUTH_SESSION_TTL } from '@owlmeans/server-auth-session';
11
+ import { uuid } from '@owlmeans/basic-ids';
12
+ import { TOKEN_UPDATE } from '@owlmeans/auth-common';
8
13
  export const makeAuthService = (alias = DEFAULT_ALIAS) => {
9
14
  const location = `server-auth:${alias}`;
10
15
  const cache = (context) => context.resource(AUTH_CACHE);
16
+ const sessions = (context) => context.hasService(AUTH_SESSION_MANAGER)
17
+ ? context.service(AUTH_SESSION_MANAGER)
18
+ : null;
19
+ const entityIdFor = async (context, entitySlug) => {
20
+ if (entitySlug == null || entitySlug === '')
21
+ return null;
22
+ if (!context.hasService(ENTITY_RESOLVER))
23
+ return entitySlug;
24
+ const entity = await context.service(ENTITY_RESOLVER).resolve(entitySlug);
25
+ return entity?.id ?? null;
26
+ };
27
+ const refresh = async (context, auth, version) => {
28
+ const entityId = await entityIdFor(context, auth.entitySlug);
29
+ if (entityId == null || auth.profileId == null || !context.hasResource(AUTH_IDENTITY_PROFILE))
30
+ return null;
31
+ const profiles = context.resource(AUTH_IDENTITY_PROFILE);
32
+ let profile = null;
33
+ try {
34
+ profile = await profiles.load({ entityId, profileId: auth.profileId });
35
+ }
36
+ catch {
37
+ // A missing profile is a definitive authentication refusal; a failed profile store is an
38
+ // availability dependency and must not look like a revoked browser session.
39
+ throw new AuthUnavailable('identity-profile');
40
+ }
41
+ if (profile == null || (profile.expiresAt != null && new Date(profile.expiresAt).getTime() <= Date.now()))
42
+ return null;
43
+ return {
44
+ ...auth,
45
+ userId: profile.userId ?? auth.userId,
46
+ role: profile.role,
47
+ scopes: profile.scopes ?? [],
48
+ ...(profile.permissions != null ? { permissions: profile.permissions } : {}),
49
+ authorizationVersion: version,
50
+ createdAt: new Date()
51
+ };
52
+ };
53
+ const sign = async (context, auth) => {
54
+ const trusted = await trust(context, TRUSTED, context.cfg.alias ?? context.cfg.service);
55
+ const ttl = auth.expiresAt == null ? AUTH_SESSION_TTL : Math.max(0, new Date(auth.expiresAt).getTime() - Date.now());
56
+ const authorization = await makeEnvelopeModel(AuthroizationType.Ed25519BasicToken)
57
+ .send(auth, ttl).sign(trusted.key, EnvelopeKind.Token);
58
+ return `${AuthroizationType.Ed25519BasicToken.toUpperCase()} ${authorization}`;
59
+ };
11
60
  const service = createService(alias, {
12
61
  match: async (req) => extractAuthToken(req, AuthroizationType.Ed25519BasicToken) != null,
13
62
  handle: async (req, res) => {
@@ -21,7 +70,32 @@ export const makeAuthService = (alias = DEFAULT_ALIAS) => {
21
70
  if (!await envelope.verify(trusted.key)) {
22
71
  return false;
23
72
  }
24
- res.resolve(envelope.message());
73
+ let auth = envelope.message();
74
+ const manager = sessions(context);
75
+ if (manager != null) {
76
+ if (auth.sessionId == null)
77
+ return false;
78
+ let decision;
79
+ try {
80
+ decision = await manager.inspect(auth.sessionId);
81
+ }
82
+ catch {
83
+ // Registry availability is a security dependency. A guard cannot authenticate through it.
84
+ throw new AuthUnavailable('session-registry');
85
+ }
86
+ if (decision.state !== 'active' && decision.state !== 'refresh')
87
+ return false;
88
+ if (decision.state === 'refresh') {
89
+ const refreshed = await refresh(context, auth, decision.version);
90
+ if (refreshed == null)
91
+ return false;
92
+ auth = refreshed;
93
+ const replacement = await sign(context, auth);
94
+ res.responseProvider?.header(TOKEN_UPDATE, replacement);
95
+ req.headers = { ...req.headers, authorization: replacement };
96
+ }
97
+ }
98
+ res.resolve(auth);
25
99
  return true;
26
100
  },
27
101
  unpack: async (token) => {
@@ -32,7 +106,22 @@ export const makeAuthService = (alias = DEFAULT_ALIAS) => {
32
106
  if (!await envelope.verify(trusted.key)) {
33
107
  throw new AuthorizationError('unpack');
34
108
  }
35
- return envelope.message();
109
+ const auth = envelope.message();
110
+ const manager = sessions(context);
111
+ if (manager != null) {
112
+ if (auth.sessionId == null)
113
+ throw new AuthorizationError('session');
114
+ let decision;
115
+ try {
116
+ decision = await manager.inspect(auth.sessionId);
117
+ }
118
+ catch {
119
+ throw new AuthUnavailable('session-registry');
120
+ }
121
+ if (decision.state !== 'active')
122
+ throw new AuthorizationError('session');
123
+ }
124
+ return auth;
36
125
  },
37
126
  authenticated: async () => {
38
127
  return null;
@@ -57,6 +146,8 @@ export const makeAuthService = (alias = DEFAULT_ALIAS) => {
57
146
  throw new AuthenFailed();
58
147
  }
59
148
  // @TODO Move to a plugin
149
+ const issuedAt = Date.now();
150
+ const expiresAt = new Date(issuedAt + AUTH_SESSION_TTL);
60
151
  const auth = {
61
152
  token: credentials.challenge,
62
153
  userId: credentials.userId,
@@ -67,12 +158,25 @@ export const makeAuthService = (alias = DEFAULT_ALIAS) => {
67
158
  profileId: credentials.profileId,
68
159
  entitySlug: credentials.entitySlug,
69
160
  isUser: true,
70
- createdAt: new Date()
161
+ createdAt: new Date(issuedAt),
162
+ expiresAt,
163
+ sessionId: uuid(),
164
+ authorizationVersion: 1
71
165
  };
72
- const trusted = await trust(context, TRUSTED, context.cfg.alias ?? context.cfg.service);
73
- const authorization = await makeEnvelopeModel(AuthroizationType.Ed25519BasicToken)
74
- .send(auth, null).sign(trusted.key, EnvelopeKind.Token);
75
- return { token: `${AuthroizationType.Ed25519BasicToken.toUpperCase()} ${authorization}` };
166
+ const manager = sessions(context);
167
+ if (manager != null) {
168
+ const entityId = await entityIdFor(context, auth.entitySlug);
169
+ if (entityId == null || auth.profileId == null)
170
+ throw new AuthenFailed('session');
171
+ const decision = await manager.register({
172
+ id: auth.sessionId, kind: 'bearer', entityId, profileId: auth.profileId,
173
+ issuedAt, expiresAt: expiresAt.getTime()
174
+ });
175
+ if (decision.state !== 'active')
176
+ throw new AuthenFailed('session');
177
+ auth.authorizationVersion = decision.version;
178
+ }
179
+ return { token: await sign(context, auth) };
76
180
  }
77
181
  });
78
182
  return service;
@@ -81,6 +185,9 @@ export const appendAuthService = (ctx, alias = DEFAULT_ALIAS) => {
81
185
  if (!ctx.hasResource(AUTH_CACHE)) {
82
186
  ctx.registerResource(createStaticResource(AUTH_CACHE));
83
187
  }
188
+ // Every standalone server gets an expiring process-local registry. Scaled deployments replace
189
+ // it with appendRedisAuthSessionManager before calling this helper.
190
+ appendMemoryAuthSessionManager(ctx);
84
191
  const service = makeAuthService(alias);
85
192
  const context = ctx;
86
193
  context.registerService(service);
@@ -1 +1 @@
1
- {"version":3,"file":"service.js","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"service.js","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@owlmeans/server-auth",
3
- "version": "0.1.18-rc.35",
3
+ "version": "0.1.18-rc.36",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -37,29 +37,31 @@
37
37
  },
38
38
  "dependencies": {
39
39
  "@noble/hashes": "^1.5.0",
40
- "@owlmeans/api": "^0.1.18-rc.29",
41
- "@owlmeans/api-config-server": "^0.1.18-rc.33",
42
- "@owlmeans/auth": "^0.1.18-rc.27",
43
- "@owlmeans/auth-common": "^0.1.18-rc.29",
44
- "@owlmeans/basic-envelope": "^0.1.18-rc.28",
45
- "@owlmeans/basic-ids": "^0.1.18-rc.26",
46
- "@owlmeans/basic-keys": "^0.1.18-rc.30",
47
- "@owlmeans/client-config": "^0.1.18-rc.29",
48
- "@owlmeans/client-entrypoint": "^0.1.18-rc.29",
49
- "@owlmeans/config": "^0.1.18-rc.29",
50
- "@owlmeans/context": "^0.1.18-rc.25",
51
- "@owlmeans/kluster": "^0.1.18-rc.28",
52
- "@owlmeans/entrypoint": "^0.1.18-rc.28",
53
- "@owlmeans/redis-resource": "^0.1.18-rc.28",
54
- "@owlmeans/resource": "^0.1.18-rc.27",
55
- "@owlmeans/route": "^0.1.18-rc.26",
56
- "@owlmeans/server-api": "^0.1.18-rc.33",
57
- "@owlmeans/server-context": "^0.1.18-rc.28",
58
- "@owlmeans/server-entrypoint": "^0.1.18-rc.27",
59
- "@owlmeans/server-route": "^0.1.18-rc.25",
60
- "@owlmeans/server-socket": "^0.1.18-rc.35",
61
- "@owlmeans/socket": "^0.1.18-rc.25",
62
- "@owlmeans/static-resource": "^0.1.18-rc.25",
40
+ "@owlmeans/api": "^0.1.18-rc.30",
41
+ "@owlmeans/api-config-server": "^0.1.18-rc.34",
42
+ "@owlmeans/auth": "^0.1.18-rc.28",
43
+ "@owlmeans/auth-common": "^0.1.18-rc.30",
44
+ "@owlmeans/basic-envelope": "^0.1.18-rc.29",
45
+ "@owlmeans/basic-ids": "^0.1.18-rc.27",
46
+ "@owlmeans/basic-keys": "^0.1.18-rc.31",
47
+ "@owlmeans/client-config": "^0.1.18-rc.30",
48
+ "@owlmeans/client-entrypoint": "^0.1.18-rc.30",
49
+ "@owlmeans/config": "^0.1.18-rc.30",
50
+ "@owlmeans/context": "^0.1.18-rc.26",
51
+ "@owlmeans/kluster": "^0.1.18-rc.29",
52
+ "@owlmeans/entrypoint": "^0.1.18-rc.29",
53
+ "@owlmeans/redis-resource": "^0.1.18-rc.29",
54
+ "@owlmeans/resource": "^0.1.18-rc.28",
55
+ "@owlmeans/route": "^0.1.18-rc.27",
56
+ "@owlmeans/server-api": "^0.1.18-rc.34",
57
+ "@owlmeans/server-auth-identity": "^0.1.18-rc.30",
58
+ "@owlmeans/server-auth-session": "^0.1.18-rc.1",
59
+ "@owlmeans/server-context": "^0.1.18-rc.29",
60
+ "@owlmeans/server-entrypoint": "^0.1.18-rc.28",
61
+ "@owlmeans/server-route": "^0.1.18-rc.26",
62
+ "@owlmeans/server-socket": "^0.1.18-rc.36",
63
+ "@owlmeans/socket": "^0.1.18-rc.26",
64
+ "@owlmeans/static-resource": "^0.1.18-rc.26",
63
65
  "@scure/base": "^2.3.0"
64
66
  },
65
67
  "peerDependencies": {
@@ -67,7 +69,7 @@
67
69
  },
68
70
  "devDependencies": {
69
71
  "@owlmeans/dep-config": "workspace:*",
70
- "@owlmeans/test-auth": "^0.1.18-rc.28",
72
+ "@owlmeans/test-auth": "^0.1.18-rc.29",
71
73
  "@types/bun": "^1.4.0",
72
74
  "@types/node": "^26.1.0",
73
75
  "nodemon": "^3.1.14",
@@ -38,7 +38,7 @@ The manager is built on the OwlMeans entrypoint system, providing:
38
38
  This manager app is part of the `@owlmeans/server-auth` package:
39
39
 
40
40
  ```bash
41
- npm install @owlmeans/server-auth@^0.1.18-rc.35
41
+ npm install @owlmeans/server-auth@^0.1.18-rc.36
42
42
  ```
43
43
 
44
44
  ## API Reference
@@ -12,6 +12,7 @@ import { trusted } from './utils/trusted.js'
12
12
  import type { ServerConfig, ServerContext } from '@owlmeans/server-context'
13
13
  import type { Resource } from '@owlmeans/resource'
14
14
  import type { AuthSpent } from '../types.js'
15
+ import { AuthChallengeReplayPolicy } from './plugins/replay-policy.js'
15
16
 
16
17
  type Config = ServerConfig
17
18
  type Context = ServerContext<Config>
@@ -51,22 +52,24 @@ export const makeAuthModel = (context: AppContext<AppConfig>): AuthModel => {
51
52
 
52
53
  const msg: string = envelope.message(true)
53
54
 
54
- try {
55
- await cache(context).create({ id: msg }, { ttl: (envelope.envelope.ttl ?? AUTHEN_TIMEFRAME) / 1000 })
56
- } catch (e) {
57
- const error = new AuthenFailed('challenge')
58
- if (e instanceof Error) {
59
- error.oiriginalStack = `${e} : ${e.stack}`
55
+ const plugin = await getPlugin(envelope.type(), context)
56
+
57
+ if (plugin.challengeReplayPolicy !== AuthChallengeReplayPolicy.Plugin) {
58
+ try {
59
+ await cache(context).create({ id: msg }, { ttl: (envelope.envelope.ttl ?? AUTHEN_TIMEFRAME) / 1000 })
60
+ } catch (e) {
61
+ const error = new AuthenFailed('challenge')
62
+ if (e instanceof Error) {
63
+ error.oiriginalStack = `${e} : ${e.stack}`
64
+ }
65
+ throw error
60
66
  }
61
- throw error
62
67
  }
63
68
 
64
69
  if (credential.userId == null) {
65
70
  throw new AuthenPayloadError('userId')
66
71
  }
67
72
 
68
- const plugin = await getPlugin(envelope.type(), context)
69
-
70
73
  // @TODO this token PROBABLY needs to be registered somewhere and rechecked
71
74
  // from time to time to make sure that the session is not deleted
72
75
  // or permission hasn't changed.
@@ -1,5 +1,6 @@
1
1
 
2
2
  export type * from './types.js'
3
+ export * from './replay-policy.js'
3
4
  export * from './basic-ed25519.js'
4
5
  export * from './re-captcha.js'
5
6
  export * from './basic-rely.js'
@@ -0,0 +1,7 @@
1
+ /** Ownership of atomic replay protection for a verified authentication challenge. */
2
+ export enum AuthChallengeReplayPolicy {
3
+ /** Default: the auth manager consumes the challenge before plugin authentication. */
4
+ Manager = 'manager',
5
+ /** The plugin owns bounded attempts and atomic success consumption. */
6
+ Plugin = 'plugin',
7
+ }
@@ -3,9 +3,15 @@ import type { AuthModel } from '../types.js'
3
3
  import type { AbstractRequest } from '@owlmeans/entrypoint'
4
4
  import type { RedisResource } from '@owlmeans/redis-resource'
5
5
  import type { ResourceRecord } from '@owlmeans/resource'
6
+ import type { AuthChallengeReplayPolicy } from './replay-policy.js'
6
7
 
7
8
  export interface AuthPlugin extends Omit<AuthModel, "rely"> {
8
9
  type: string
10
+ /**
11
+ * Who atomically consumes a verified challenge. The manager remains the default; a plugin may
12
+ * opt in only when its own credential protocol needs a bounded retry budget before consumption.
13
+ */
14
+ challengeReplayPolicy?: AuthChallengeReplayPolicy
9
15
  }
10
16
 
11
17
  export interface RecpatchaResponse {
package/src/service.ts CHANGED
@@ -5,11 +5,21 @@ import type { AuthServiceAppend, AuthService, AuthSpent } from './types.js'
5
5
  import { assertContext, createService } from '@owlmeans/context'
6
6
  import { EnvelopeKind, makeEnvelopeModel } from '@owlmeans/basic-envelope'
7
7
  import type { Auth, AuthCredentials } from '@owlmeans/auth'
8
- import { AuthenFailed, AuthorizationError, AuthroizationType } from '@owlmeans/auth'
8
+ import { AuthenFailed, AuthorizationError, AuthroizationType, AuthUnavailable } from '@owlmeans/auth'
9
9
  import type { AbstractRequest, AbstractResponse } from '@owlmeans/entrypoint'
10
10
  import type { Resource } from '@owlmeans/resource'
11
11
  import { createStaticResource } from '@owlmeans/static-resource'
12
12
  import { trust, extractAuthToken } from '@owlmeans/auth-common/utils'
13
+ import { ENTITY_RESOLVER } from '@owlmeans/auth-common'
14
+ import type { EntityResolverService } from '@owlmeans/auth-common'
15
+ import { AUTH_IDENTITY_PROFILE } from '@owlmeans/server-auth-identity'
16
+ import type { IdentityProfile, IdentityProfileResource } from '@owlmeans/server-auth-identity'
17
+ import {
18
+ appendMemoryAuthSessionManager, AUTH_SESSION_MANAGER, AUTH_SESSION_TTL
19
+ } from '@owlmeans/server-auth-session'
20
+ import type { AuthSessionManager } from '@owlmeans/server-auth-session'
21
+ import { uuid } from '@owlmeans/basic-ids'
22
+ import { TOKEN_UPDATE } from '@owlmeans/auth-common'
13
23
 
14
24
  type Config = ServerConfig
15
25
  type Context = ServerContext<Config>
@@ -20,6 +30,50 @@ export const makeAuthService = (alias: string = DEFAULT_ALIAS): AuthService => {
20
30
  const cache = (context: Context): Resource<AuthSpent> =>
21
31
  context.resource<Resource<AuthSpent>>(AUTH_CACHE)
22
32
 
33
+ const sessions = (context: Context): AuthSessionManager | null =>
34
+ context.hasService(AUTH_SESSION_MANAGER)
35
+ ? context.service<AuthSessionManager>(AUTH_SESSION_MANAGER)
36
+ : null
37
+
38
+ const entityIdFor = async (context: Context, entitySlug: string | undefined): Promise<string | null> => {
39
+ if (entitySlug == null || entitySlug === '') return null
40
+ if (!context.hasService(ENTITY_RESOLVER)) return entitySlug
41
+ const entity = await context.service<EntityResolverService>(ENTITY_RESOLVER).resolve(entitySlug)
42
+ return entity?.id ?? null
43
+ }
44
+
45
+ const refresh = async (context: Context, auth: Auth, version: number): Promise<Auth | null> => {
46
+ const entityId = await entityIdFor(context, auth.entitySlug)
47
+ if (entityId == null || auth.profileId == null || !context.hasResource(AUTH_IDENTITY_PROFILE)) return null
48
+ const profiles = context.resource<IdentityProfileResource>(AUTH_IDENTITY_PROFILE)
49
+ let profile: IdentityProfile | null = null
50
+ try {
51
+ profile = await profiles.load({ entityId, profileId: auth.profileId })
52
+ } catch {
53
+ // A missing profile is a definitive authentication refusal; a failed profile store is an
54
+ // availability dependency and must not look like a revoked browser session.
55
+ throw new AuthUnavailable('identity-profile')
56
+ }
57
+ if (profile == null || (profile.expiresAt != null && new Date(profile.expiresAt).getTime() <= Date.now())) return null
58
+ return {
59
+ ...auth,
60
+ userId: profile.userId ?? auth.userId,
61
+ role: profile.role,
62
+ scopes: profile.scopes ?? [],
63
+ ...(profile.permissions != null ? { permissions: profile.permissions } : {}),
64
+ authorizationVersion: version,
65
+ createdAt: new Date()
66
+ }
67
+ }
68
+
69
+ const sign = async (context: Context, auth: Auth): Promise<string> => {
70
+ const trusted = await trust<Config, Context>(context, TRUSTED, context.cfg.alias ?? context.cfg.service)
71
+ const ttl = auth.expiresAt == null ? AUTH_SESSION_TTL : Math.max(0, new Date(auth.expiresAt).getTime() - Date.now())
72
+ const authorization = await makeEnvelopeModel<Auth>(AuthroizationType.Ed25519BasicToken)
73
+ .send(auth, ttl).sign(trusted.key, EnvelopeKind.Token)
74
+ return `${AuthroizationType.Ed25519BasicToken.toUpperCase()} ${authorization}`
75
+ }
76
+
23
77
  const service: AuthService = createService<AuthService>(alias, {
24
78
  match: async req => extractAuthToken(req, AuthroizationType.Ed25519BasicToken) != null,
25
79
 
@@ -37,7 +91,29 @@ export const makeAuthService = (alias: string = DEFAULT_ALIAS): AuthService => {
37
91
  return false as T
38
92
  }
39
93
 
40
- res.resolve(envelope.message())
94
+ let auth = envelope.message()
95
+ const manager = sessions(context)
96
+ if (manager != null) {
97
+ if (auth.sessionId == null) return false as T
98
+ let decision
99
+ try {
100
+ decision = await manager.inspect(auth.sessionId)
101
+ } catch {
102
+ // Registry availability is a security dependency. A guard cannot authenticate through it.
103
+ throw new AuthUnavailable('session-registry')
104
+ }
105
+ if (decision.state !== 'active' && decision.state !== 'refresh') return false as T
106
+ if (decision.state === 'refresh') {
107
+ const refreshed = await refresh(context, auth, decision.version)
108
+ if (refreshed == null) return false as T
109
+ auth = refreshed
110
+ const replacement = await sign(context, auth)
111
+ res.responseProvider?.header(TOKEN_UPDATE, replacement)
112
+ req.headers = { ...req.headers, authorization: replacement }
113
+ }
114
+ }
115
+
116
+ res.resolve(auth)
41
117
 
42
118
  return true as T
43
119
  },
@@ -51,8 +127,19 @@ export const makeAuthService = (alias: string = DEFAULT_ALIAS): AuthService => {
51
127
  if (!await envelope.verify(trusted.key)) {
52
128
  throw new AuthorizationError('unpack')
53
129
  }
54
-
55
- return envelope.message()
130
+ const auth = envelope.message()
131
+ const manager = sessions(context)
132
+ if (manager != null) {
133
+ if (auth.sessionId == null) throw new AuthorizationError('session')
134
+ let decision
135
+ try {
136
+ decision = await manager.inspect(auth.sessionId)
137
+ } catch {
138
+ throw new AuthUnavailable('session-registry')
139
+ }
140
+ if (decision.state !== 'active') throw new AuthorizationError('session')
141
+ }
142
+ return auth
56
143
  },
57
144
 
58
145
  authenticated: async () => {
@@ -84,6 +171,8 @@ export const makeAuthService = (alias: string = DEFAULT_ALIAS): AuthService => {
84
171
  }
85
172
 
86
173
  // @TODO Move to a plugin
174
+ const issuedAt = Date.now()
175
+ const expiresAt = new Date(issuedAt + AUTH_SESSION_TTL)
87
176
  const auth: Auth = {
88
177
  token: credentials.challenge,
89
178
  userId: credentials.userId,
@@ -94,14 +183,24 @@ export const makeAuthService = (alias: string = DEFAULT_ALIAS): AuthService => {
94
183
  profileId: credentials.profileId,
95
184
  entitySlug: credentials.entitySlug,
96
185
  isUser: true,
97
- createdAt: new Date()
186
+ createdAt: new Date(issuedAt),
187
+ expiresAt,
188
+ sessionId: uuid(),
189
+ authorizationVersion: 1
190
+ }
191
+ const manager = sessions(context)
192
+ if (manager != null) {
193
+ const entityId = await entityIdFor(context, auth.entitySlug)
194
+ if (entityId == null || auth.profileId == null) throw new AuthenFailed('session')
195
+ const decision = await manager.register({
196
+ id: auth.sessionId!, kind: 'bearer', entityId, profileId: auth.profileId,
197
+ issuedAt, expiresAt: expiresAt.getTime()
198
+ })
199
+ if (decision.state !== 'active') throw new AuthenFailed('session')
200
+ auth.authorizationVersion = decision.version
98
201
  }
99
202
 
100
- const trusted = await trust<Config, Context>(context, TRUSTED, context.cfg.alias ?? context.cfg.service)
101
- const authorization = await makeEnvelopeModel<Auth>(AuthroizationType.Ed25519BasicToken)
102
- .send(auth, null).sign(trusted.key, EnvelopeKind.Token)
103
-
104
- return { token: `${AuthroizationType.Ed25519BasicToken.toUpperCase()} ${authorization}` }
203
+ return { token: await sign(context, auth) }
105
204
  }
106
205
  })
107
206
 
@@ -116,6 +215,10 @@ export const appendAuthService = <C extends Config, T extends ServerContext<C>>(
116
215
  ctx.registerResource(createStaticResource(AUTH_CACHE))
117
216
  }
118
217
 
218
+ // Every standalone server gets an expiring process-local registry. Scaled deployments replace
219
+ // it with appendRedisAuthSessionManager before calling this helper.
220
+ appendMemoryAuthSessionManager(ctx)
221
+
119
222
  const service = makeAuthService(alias)
120
223
  const context = ctx as T & AuthServiceAppend
121
224
 
package/tests/context.ts CHANGED
@@ -25,6 +25,8 @@ export const makeTestContext = () => {
25
25
  id: authServiceKP.exportAddress(),
26
26
  name: AUTH_SRV_KEY,
27
27
  credential: authServiceKP.exportPublic(),
28
+ // Local, deterministic test-only key: the manager signs its synthetic exchange envelope.
29
+ secret: authServiceKP.export(),
28
30
  scopes: ['*'],
29
31
  }
30
32
 
@@ -0,0 +1,36 @@
1
+ import { describe, expect, test } from 'bun:test'
2
+ import { AuthenFailed, AuthRole } from '@owlmeans/auth'
3
+ import { makeAuthModel } from '../src/manager/model.js'
4
+ import { AuthChallengeReplayPolicy } from '../src/manager/plugins/replay-policy.js'
5
+ import { registerPlugin } from '../src/manager/plugins/index.js'
6
+ import { makeTestContext } from './context.js'
7
+
8
+ describe('@owlmeans/server-auth — plugin-owned challenge replay', () => {
9
+ test('lets a bounded-retry plugin receive a second credential attempt', async () => {
10
+ const type = `replay-policy-${Date.now()}`
11
+ let attempts = 0
12
+ registerPlugin(type, () => ({
13
+ type,
14
+ challengeReplayPolicy: AuthChallengeReplayPolicy.Plugin,
15
+ init: async () => ({ challenge: 'opaque-issuance' }),
16
+ authenticate: async () => {
17
+ attempts += 1
18
+ if (attempts === 1) throw new AuthenFailed('first-guess')
19
+ return { token: '' }
20
+ },
21
+ }))
22
+
23
+ const { context } = makeTestContext()
24
+ await context.configure().init()
25
+ const model = makeAuthModel(context as never)
26
+ const { challenge } = await model.init({ type, userId: 'retry@example.com' })
27
+ const credential = () => ({
28
+ type, challenge, credential: 'guess', userId: 'retry@example.com',
29
+ role: AuthRole.User, scopes: ['*'],
30
+ })
31
+
32
+ await expect(model.authenticate(credential())).rejects.toBeInstanceOf(AuthenFailed)
33
+ await expect(model.authenticate(credential())).resolves.toHaveProperty('token')
34
+ expect(attempts).toBe(2)
35
+ })
36
+ })