@web-ts-toolkit/express-oidc-vault-mongodb-store 0.43.0 → 0.48.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -64,20 +64,25 @@ app.use(
64
64
  const server = app.listen(3000);
65
65
 
66
66
  process.once('SIGTERM', async () => {
67
- server.close();
67
+ await new Promise<void>((resolve, reject) => {
68
+ server.close((error) => (error ? reject(error) : resolve()));
69
+ });
70
+ // Also settle any store work started outside HTTP requests before closing.
68
71
  await mongo.close();
69
72
  });
70
73
  ```
71
74
 
72
75
  ## Collection Names
73
76
 
74
- The provider uses five separate MongoDB collections by default:
77
+ The provider uses seven separate MongoDB collections by default:
75
78
 
76
79
  - `oidc_vault_authorization_transactions`: authorization transaction state, nonce, PKCE verifier, and metadata
77
80
  - `oidc_vault_exchange_codes`: short-lived frontend exchange codes
78
81
  - `oidc_vault_sessions`: sessions, user data, and bearer-equivalent token material
79
82
  - `oidc_vault_backchannel_logout_token_jtis`: consumed backchannel logout token JTIs
80
83
  - `oidc_vault_rotated_session_aliases`: stale rotated session IDs mapped to active logical sessions
84
+ - `oidc_vault_dpop_proofs`: unique DPoP proof IDs with a TTL expiry index
85
+ - `oidc_vault_dpop_replay_capacity`: shared capacity/serialization row and indexed, non-TTL expiry-accounting rows
81
86
 
82
87
  Override collection names when your deployment needs explicit naming:
83
88
 
@@ -89,24 +94,52 @@ const storeProvider = createMongoOidcVaultStore({
89
94
  sessionsCollectionName: 'auth_oidc_sessions',
90
95
  backchannelLogoutTokenJtisCollectionName: 'auth_oidc_backchannel_logout_jtis',
91
96
  rotatedSessionAliasesCollectionName: 'auth_oidc_rotated_session_aliases',
97
+ dpopProofsCollectionName: 'auth_dpop_proofs',
98
+ dpopReplayCapacityCollectionName: 'auth_dpop_capacity',
92
99
  });
93
100
  ```
94
101
 
95
- ## Notes
102
+ ## Startup And Client Ownership
96
103
 
97
104
  - use MongoDB when your team already standardizes on Mongo and you want the auth vault data in the same operational platform
98
- - the provider uses separate collections for authorization transactions, exchange codes, sessions, backchannel logout token JTIs, and rotated-session aliases
99
- - TTL indexes are created on expiring records; authorization transactions, exchange codes, backchannel logout token JTIs, and rotated-session aliases are also checked for expiration during relevant reads or consumes so behavior does not depend only on Mongo's background TTL monitor timing
100
- - session rotation requires MongoDB transactions; use a replica set or sharded deployment because standalone servers fail closed instead of using non-atomic multi-write rotation
105
+ - the provider uses seven separate collections: transactions, exchange codes, sessions, backchannel JTIs, aliases, DPoP proofs and replay capacity/accounting
106
+ - TTL indexes are created on expiring records; sessions, authorization transactions, exchange codes, backchannel logout token JTIs, and rotated-session aliases are also checked for expiration during relevant reads or consumes (`expiresAt <= now()` is expired), so behavior does not depend only on Mongo's background TTL monitor timing
107
+ - session rotation, coherent revocation-context reads, replay-capacity admission and inactive-lineage alias cleanup require MongoDB transactions; use a replica set or sharded deployment because standalone servers fail readiness instead of using non-atomic fallbacks
101
108
  - startup readiness creates required indexes and verifies transaction-capable topology; connect the MongoDB client, create the store, await `storeProvider.ready()`, then accept traffic
102
109
  - session deletion by subject or provider session ID uses compound scoped indexes on the identity field plus `provider.issuer` and `provider.clientId`; these replace single-field identity indexes because the leading key still supports identity-only deletes while scoped logout deletes avoid scanning every repeated identity across tenants
103
110
  - the application owns MongoDB client shutdown; this package does not close the client
104
- - rotation requires a distinct unused target session ID; missing-source, same-ID, and existing-target rotation conflicts throw `OidcVaultStoreConflictError` without changing source or target records
105
- - rotated-session aliases are retained only long enough to bridge in-flight refresh/logout requests; sessions without explicit expiry use a finite 5 minute alias retention window by default, configurable with `rotatedSessionAliasRetentionMs`
106
- - deleting by current session ID, stale rotated ID, logical session ID, subject, or provider session ID removes aliases for the affected logical sessions
107
- - `createAuthorizationTransaction`, `createExchangeCode`, and `createSession` are upserts; metadata should be JSON-compatible for portability across store providers
111
+
112
+ Drain HTTP requests and any other in-flight store operations before closing the caller-owned `MongoClient`. The store has no shutdown method or background cleanup timer. Its explicit transaction sessions are ended in `finally` on success and failure; MongoDB's TTL monitor belongs to the server. Shared state and durability depend on your deployment, replication and backup configuration.
113
+
114
+ ## Rotation Aliases And Lifetime
115
+
116
+ - rotation requires a distinct unused target session ID; missing-source, same-ID, existing-target, changed-source, and expired-source rotation conflicts throw `OidcVaultStoreConflictError` without changing source or target records (the source document is re-read inside the transaction and must still match the generation seen before the transaction, including liveness, so a same-ID replacement committed after the rotation's source read aborts instead of being consumed)
117
+ - an expired target document still present before TTL cleanup can conflict; use fresh target IDs for portable rotation
118
+ - each alias takes its immediate successor's `expiresAt`, not the source's; later rotations never extend it. With `A -> B (expiresAt=T1) -> C (expiresAt=T2)`, A stops revoking at T1 even if T2 is later or absent. B uses C's deadline. `getSession(A)` returns `null`: aliases are only revocation handles
119
+ - without successor `expiresAt`, MongoDB uses `now() + rotatedSessionAliasRetentionMs` (default five minutes, finite positive duration). Memory/Redis instead have no alias time limit and can accumulate aliases for a long-lived lineage. Finite session expiry is the portable policy; core refresh preserves it
120
+ - omitting the next logical ID preserves the source lineage. With `A/L1 -> B/L1 -> C/L2`, the new B alias revokes L2; earlier A keeps L1 and its original deadline, never C. MongoDB does not eagerly retire L1 aliases merely because rotation/upsert moves its last member elsewhere (memory does); they can remain until expiry or explicit lineage cleanup. Use distinct logical IDs for unrelated login families rather than relying on retained handles disappearing on reuse
121
+ - after an alias expires, use the live ID or logical/subject/provider-session deletion, not that stale handle
122
+
123
+ ## Deletion, Counts And Concurrency
124
+
125
+ - deleting a live public ID removes that record; deleting an unexpired alias revokes its logical lineage. Logical deletion and aliases have no issuer/client filter. Subject/provider-session object inputs match each supplied `issuer` and `clientId`; string inputs omit both filters and match across providers
126
+ - deleting by current session ID, subject, or provider session ID preserves unexpired aliases while any live member of the logical session survives, including another issuer/client scope; a stale rotated ID still revokes its logical lineage
127
+ - after session deletion commits, alias cleanup checks live membership and removes inactive-lineage aliases in a snapshot transaction. Concurrently inserted rotation aliases are outside that snapshot; updating an existing alias conflicts and retries cleanup, including identical lineage/expiry reuse (an internal alias revision makes every rotation a write). Cleanup sessions are closed on success and failure. This is not a global logout snapshot: later arrivals can survive, and cleanup failure can reject after sessions were already deleted
128
+ - compatibility: scoped/direct deletion no longer discards the surviving lineage's revocation handles. Alias deadlines and the create-ID-reuse variation below are unchanged. Cleanup still materializes affected logical IDs and surviving members; very large `$in` batches remain a scale-dependent limit
129
+
130
+ Subject/provider-session deletion repeats find/delete/cleanup passes until a find observes no matches. It can catch a rotation or matching arrival on a later pass, but arrivals after the final query can survive; continuously arriving matches can prolong the call without a fixed pass bound. Logical deletion uses one `deleteMany` followed by alias cleanup. Counts sum MongoDB `deletedCount` for primary session documents, possibly including expired documents awaiting TTL cleanup; alias removal is never counted. Memory excludes expired sessions, and Redis counts primary deletions from its cursor traversal. Counts are not a global remaining-session census or a cross-provider live-user metric. An error can follow partial/committed deletion. Vault deletion does not revoke outstanding stateless access tokens or call upstream logout.
131
+
132
+ ## Creation And Data Ownership
133
+
134
+ - `createAuthorizationTransaction`, `createExchangeCode`, and `createSession` are upserts; a `createSession` replacement takes over the session ID with its own subject/logical/provider-session scope
135
+ - unlike memory/Redis, a `createSession` replacement does not clear a stale rotation alias row held under the reused ID; that row can remain until expiry or lineage cleanup. After removing the replacement, another delete of that ID can invoke its former lineage. Portable callers must create sessions with a fresh unused ID and handle `OidcVaultStoreConflictError` (reusing a live ID replaces here but rejects on Redis; concurrent reuse also races rotation source checks)
136
+ - portable data consists of strings, finite numbers, booleans, null, arrays, and plain objects; exclude cycles, custom prototypes/serializers, functions, symbols, and undefined properties. This applies to nested provider/user/metadata fields, not just top-level metadata
137
+ - portable plain-object/array inputs are snapshotted at invocation, before readiness or other asynchronous work; later caller mutation cannot change session/transaction data, rotation retries, JTI identity, or deletion scope. Returned session containers are independent from caller input, including nested provider/user/metadata arrays
138
+ - compatibility: ownership snapshots do not JSON-round-trip values or flatten BSON wrappers. MongoDB's native serialization still applies outside the portable subset (including Dates, BSON values, undefined properties and custom `toBSON` hooks); opaque non-plain objects are not recursively copied and have no portable mutation-isolation guarantee
108
139
  - backchannel logout token JTI records are consumed only when `expiresAt` is finite and greater than the store clock at consume time
109
140
 
141
+ Authorization transactions and exchange codes are atomically consumed once by state/code, returning `null` when absent or expired. JTI reservations return `false` for duplicate, past, exact-boundary, NaN, or infinite expiries. Core passes an opaque issuer/client/JTI-namespaced key; the store uses it verbatim. Session creation defaults omitted logical ID to session ID and omitted timestamps to the store clock.
142
+
110
143
  ## Security And Operations
111
144
 
112
145
  Session records contain refresh tokens, ID tokens, access tokens, and related bearer-equivalent secrets. Treat the MongoDB database and every backup, log, trace, metric label, and export path that can expose these records as sensitive auth infrastructure.
@@ -120,6 +153,8 @@ Recommended controls:
120
153
  - define an explicit data-retention policy for sessions, aliases, authorization transactions, exchange codes, and consumed logout JTIs
121
154
  - close the caller-owned `MongoClient` from application shutdown code; this package never closes it
122
155
 
156
+ The store does not emit record/error logs or sanitize arbitrary MongoDB/client exceptions for application logging. Use fixed operation names and allowlisted diagnostic categories; do not log whole errors, connection URLs, session IDs, state/PKCE values, exchange codes or token-valued labels. A private error observer is not an automatic redaction boundary.
157
+
123
158
  This package does not implement application-level field encryption or client-side field-level encryption. Add those controls at your MongoDB/client configuration layer if your deployment requires them.
124
159
 
125
160
  ## Scoped Deletion Indexes
@@ -136,7 +171,53 @@ The package intentionally creates one compound index per public scoped identity
136
171
 
137
172
  ## Main Exports
138
173
 
174
+ Use named imports from the package root; there is no default export or public subpath API. Use Node.js `>=22.12.0` for the core dependency's CJS/ESM runtime support. TypeScript apps also need `@types/node` and `@types/express`. Both ESM (`import`, `index.d.mts`) and CJS (`require`, `index.d.ts`) declaration conditions are shipped; consumer imports always use the package name.
175
+
139
176
  - `createMongoOidcVaultStore(...)`
140
177
  - `type OidcVaultMongoStoreProvider`
141
178
  - `type MongoOidcVaultStoreOptions`
142
179
  - `DEFAULT_ROTATED_SESSION_ALIAS_RETENTION_MS`
180
+
181
+ ## Device-Binding Store Capabilities
182
+
183
+ `OidcVaultMongoStoreProvider` extends the core `OidcVaultDeviceBindingStoreProvider`, retaining `ready()`. `getAuthorizationTransaction(state)` / `getExchangeCode(code)` return detached live snapshots without consumption. They are preflight, not locks. `consumeAuthorizationTransactionIfMatches({ state, match })` and `consumeExchangeCodeIfMatches({ code, expectedSessionId, match })` use **filtered atomic `findOneAndDelete`**, comparing expiry, both security fields and (for exchange) the observed session ID in the delete predicate. No get followed by unconditional deletion is used. Matching concurrent clients have one winner; mismatch returns `null` and leaves the live record available for an honest retry.
184
+
185
+ Import shared stronger-provider/match/consume/replay/revocation types and `OidcVaultDpopReplayCapacityError` from the **core package root**. This package's root exports its factory, Mongo options/provider and alias-retention constant. Either vault opt-in feature checks all six stronger capabilities; fingerprint-only does not reserve proofs. Core's shipped README contains the complete bound issuer/request-aware API/browser recipe, using the provider as API replayStore.
186
+
187
+ `match` includes both `deviceBinding` and `browserBindingHash`. Non-null values match exactly; **null matches field absence only (`$exists: false`)**, never BSON null or an ignored field. Legacy records have neither field, cookie-only POST records have a browser hash, and bound POST records have that hash plus `{ type: 'dpop', jkt }`. Both hashes are canonical 43-character SHA-256 base64url. Key-without-hash, stored null, malformed/noncanonical hashes or extra binding fields are invalid. Security-field writes reject invalid input; explicit undefined fields are omitted before BSON serialization so they cannot turn into null. Binding comparison is independent of BSON field order. Original legacy consumes refuse guarded records without consumption. Corrupt records return no credentials and may remain until TTL cleanup/replacement.
188
+
189
+ Session documents persist only the thumbprint binding, never a JWK, proof algorithm or historical mode. Rotation inherits omitted/undefined binding, accepts the same key and rejects null/malformed binding, changing a key or enrolling an unbound source before mutation. Binding is also included in the transaction's source-generation comparison, so replacement/retry cannot consume a new source under the old key. Existing ID upsert, target conflict, alias-retention and deletion-count variations above are preserved.
190
+
191
+ Migration detail: the pre-binding Mongo mapper wrote BSON null for omitted **provider metadata and session expiry**. Those two non-binding fields are normalized to absence on genuinely unbound legacy rows, preserving their read/rotation/revocation behavior. This does not normalize `deviceBinding` or `browserBindingHash`: their stored null values are always invalid. Bound records with malformed provider/expiry still fail closed.
192
+
193
+ `getSessionRevocationContext(sessionId)` resolves a live handle or unexpired alias to a currently live lineage using one snapshot transaction. It projects only logical ID/subject/provider/binding/expiry (no refresh/ID/access tokens fetched) and returns only `logicalSessionId`, allowlisted `provider.issuer/clientId`, and optional original `deviceBinding`. No profile/metadata/arbitrary provider fields are returned. Aliases remain token/binding-free; they resolve surviving session authority rather than treating missing alias binding as unbound. Malformed/inconsistent lineage binding/provider authority throws a fixed private diagnostic. Expired aliases/empty lineages return `null`; `getSession(alias)` remains `null`. Lineage queries materialize their surviving candidates; this is not bounded replay-admission work.
194
+
195
+ ## Per-Request DPoP Replay, Capacity And TTL Accounting
196
+
197
+ | Mongo replay option | Default | Contract |
198
+ | ---------------------------------- | --------------------------------- | ------------------------------------------------------------------------------- |
199
+ | `dpopReplayMaxEntries` | `100000` | Positive safe integer, same on all clients sharing the collection pair |
200
+ | `dpopProofsCollectionName` | `oidc_vault_dpop_proofs` | Unique proof IDs and TTL expiry; distinct from all other collections |
201
+ | `dpopReplayCapacityCollectionName` | `oidc_vault_dpop_replay_capacity` | Capacity/revision + indexed non-TTL expiry ledger; TTL indexes reject readiness |
202
+
203
+ ```ts
204
+ const storeProvider = createMongoOidcVaultStore({
205
+ db: mongo.db('app-auth'),
206
+ dpopReplayMaxEntries: 100_000,
207
+ dpopProofsCollectionName: 'oidc_vault_dpop_proofs',
208
+ dpopReplayCapacityCollectionName: 'oidc_vault_dpop_replay_capacity',
209
+ });
210
+ await storeProvider.ready();
211
+ ```
212
+
213
+ `dpopReplayMaxEntries` is a positive safe integer, default **100000**, shared across independent clients using the paired replay collections. All seven collection names must be distinct and valid. Every shared client must use the same capacity and proof/accounting collection pairing; readiness fails if the persisted capacity configuration disagrees. Changing names starts an independent namespace, not a migration. No instance-local admission counter or replay fallback is used.
214
+
215
+ `reserveDpopProof({ replayKey, expiresAt })` reserves an opaque key verbatim after proof verification. Expiry must be a safe-integer future millisecond epoch with remaining TTL **<=360000 ms**. Nonfinite/unsafe/fractional/expired (`<= now()`) or overlong windows return `false` without allocation. A duplicate returns `false` without extending expiry, before capacity checks. Valid expired IDs may be admitted again.
216
+
217
+ Admission is a **snapshot transaction serialized by an actual revision write** to the shared capacity row. It checks the unique proof ID and its accounting entry, removes at most **64** indexed expired accounting entries plus the requested expired key, then commits the proof write, accounting insertion and capacity update together. No full proof-collection count/scan is required per request. New reservations at capacity throw core `OidcVaultDpopReplayCapacityError` (import from `@web-ts-toolkit/express-oidc-vault`); live reservations are never evicted. Write failures roll back all admission changes; driver transaction retries repeat against the same invocation-owned input and a fresh snapshot. Every allocated transaction session is ended in `finally`.
218
+
219
+ **TTL deletion cannot leak capacity:** only `dpopProofs` has a TTL index. Each admitted key also has an indexed expiry-accounting row in `dpopReplayCapacity`, which deliberately has **no TTL index**; readiness rejects any pre-existing TTL index on that collection. Even if MongoDB's monitor already deleted a proof row, the next bounded cleanup still knows when/how much to decrement. A missing physical proof with an unexpired accounting entry remains a duplicate, not an acceptance bypass. Corrupt accounting fails closed. At most the configured number of proof rows and accounting rows, plus one capacity row, are retained by normal operation. Expired accounting rows awaiting traffic-driven cleanup can conservatively occupy capacity; when traffic stops they remain bounded and are reclaimed on later admissions.
220
+
221
+ DPoP replay is a **write per accepted proof/API request**, much higher-volume than backchannel logout JTIs. The common no-cleanup admission uses seven sequential data commands plus transaction commit; a live duplicate uses a capacity write, proof lookup and commit. Expired-row cleanup adds bounded queries/deletes, and contention/retries add work. The single shared capacity row serializes admissions and can become a throughput bottleneck. Size for unique proofs/second × validity window plus headroom (approved defaults: at most 70 seconds), share identical namespaces/windows and synchronized clocks, and load-test the intended rate. This provides atomic capacity, not a latency/throughput SLA.
222
+
223
+ Never release a reservation after downstream failure, extend duplicate expiry, or accept a proof when replay storage fails. Retries require a fresh proof. Core API/vault middleware maps capacity/provider failure to sanitized **503 OIDC_VAULT_DPOP_REPLAY_UNAVAILABLE**; private diagnostics are not automatically safe to log. The store supplies atomic state, not HTTP proof authentication. Replica-set tests verify these operations; sharded topology/distributed failure durability and throughput remain deployment-specific checks. Losing live replay data on restore/failover weakens replay protection until its acceptance window expires.
package/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Db } from 'mongodb';
2
- import { OidcVaultStoreProvider } from '@web-ts-toolkit/express-oidc-vault';
2
+ import { OidcVaultDeviceBindingStoreProvider } from '@web-ts-toolkit/express-oidc-vault';
3
3
 
4
4
  /**
5
5
  * Options for `createMongoOidcVaultStore`.
@@ -7,7 +7,7 @@ import { OidcVaultStoreProvider } from '@web-ts-toolkit/express-oidc-vault';
7
7
  * Pass a `Db` from an already-connected caller-owned `MongoClient`. The store
8
8
  * validates collection names, creates indexes, and verifies transaction support
9
9
  * from `ready()`, so applications should await readiness before accepting
10
- * traffic. Session rotation requires MongoDB transactions; standalone servers
10
+ * traffic. Rotation and shared replay admission require transactions; standalone servers
11
11
  * fail closed instead of using non-atomic multi-write fallback behavior.
12
12
  */
13
13
  interface MongoOidcVaultStoreOptions {
@@ -23,6 +23,12 @@ interface MongoOidcVaultStoreOptions {
23
23
  backchannelLogoutTokenJtisCollectionName?: string;
24
24
  /** Collection mapping rotated stale session IDs to active logical sessions. */
25
25
  rotatedSessionAliasesCollectionName?: string;
26
+ /** Unique replay IDs + TTL expiry. Default `oidc_vault_dpop_proofs`. Must be distinct from all other collections. */
27
+ dpopProofsCollectionName?: string;
28
+ /** Serialized capacity and indexed non-TTL expiry accounting. Default `oidc_vault_dpop_replay_capacity`; readiness rejects TTL indexes here. */
29
+ dpopReplayCapacityCollectionName?: string;
30
+ /** Positive safe integer shared by both replay collections; default 100000. All clients must configure the same limit. */
31
+ dpopReplayMaxEntries?: number;
26
32
  /**
27
33
  * Finite alias retention for sessions without explicit expiry, in
28
34
  * milliseconds. Defaults to `DEFAULT_ROTATED_SESSION_ALIAS_RETENTION_MS`.
@@ -38,12 +44,13 @@ interface MongoOidcVaultStoreOptions {
38
44
  * before accepting traffic. The application owns the MongoDB client lifecycle,
39
45
  * including shutdown.
40
46
  */
41
- interface OidcVaultMongoStoreProvider extends OidcVaultStoreProvider {
47
+ interface OidcVaultMongoStoreProvider extends OidcVaultDeviceBindingStoreProvider {
42
48
  /**
43
49
  * Waits for startup validation to complete.
44
50
  *
45
51
  * Readiness validates collection names, creates required indexes, and verifies
46
- * the MongoDB deployment supports transactions required by session rotation.
52
+ * the MongoDB deployment supports rotation/replay transactions and matching
53
+ * shared replay-capacity configuration.
47
54
  * If readiness fails, every store operation rejects with the same error.
48
55
  */
49
56
  ready(): Promise<void>;
@@ -58,8 +65,8 @@ declare const DEFAULT_ROTATED_SESSION_ALIAS_RETENTION_MS: number;
58
65
  * Pass a `Db` from an already-connected caller-owned `MongoClient`, await
59
66
  * `store.ready()` before accepting traffic, and close the client from your own
60
67
  * shutdown path. Readiness validates all configured collection names, creates
61
- * required indexes for the five store collections, and verifies that the
62
- * MongoDB deployment supports transactions required by session rotation.
68
+ * required indexes for the seven store collections, validates shared replay
69
+ * capacity, and verifies transaction support for rotation/replay admission.
63
70
  */
64
71
  declare function createMongoOidcVaultStore(options: MongoOidcVaultStoreOptions): OidcVaultMongoStoreProvider;
65
72
 
package/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Db } from 'mongodb';
2
- import { OidcVaultStoreProvider } from '@web-ts-toolkit/express-oidc-vault';
2
+ import { OidcVaultDeviceBindingStoreProvider } from '@web-ts-toolkit/express-oidc-vault';
3
3
 
4
4
  /**
5
5
  * Options for `createMongoOidcVaultStore`.
@@ -7,7 +7,7 @@ import { OidcVaultStoreProvider } from '@web-ts-toolkit/express-oidc-vault';
7
7
  * Pass a `Db` from an already-connected caller-owned `MongoClient`. The store
8
8
  * validates collection names, creates indexes, and verifies transaction support
9
9
  * from `ready()`, so applications should await readiness before accepting
10
- * traffic. Session rotation requires MongoDB transactions; standalone servers
10
+ * traffic. Rotation and shared replay admission require transactions; standalone servers
11
11
  * fail closed instead of using non-atomic multi-write fallback behavior.
12
12
  */
13
13
  interface MongoOidcVaultStoreOptions {
@@ -23,6 +23,12 @@ interface MongoOidcVaultStoreOptions {
23
23
  backchannelLogoutTokenJtisCollectionName?: string;
24
24
  /** Collection mapping rotated stale session IDs to active logical sessions. */
25
25
  rotatedSessionAliasesCollectionName?: string;
26
+ /** Unique replay IDs + TTL expiry. Default `oidc_vault_dpop_proofs`. Must be distinct from all other collections. */
27
+ dpopProofsCollectionName?: string;
28
+ /** Serialized capacity and indexed non-TTL expiry accounting. Default `oidc_vault_dpop_replay_capacity`; readiness rejects TTL indexes here. */
29
+ dpopReplayCapacityCollectionName?: string;
30
+ /** Positive safe integer shared by both replay collections; default 100000. All clients must configure the same limit. */
31
+ dpopReplayMaxEntries?: number;
26
32
  /**
27
33
  * Finite alias retention for sessions without explicit expiry, in
28
34
  * milliseconds. Defaults to `DEFAULT_ROTATED_SESSION_ALIAS_RETENTION_MS`.
@@ -38,12 +44,13 @@ interface MongoOidcVaultStoreOptions {
38
44
  * before accepting traffic. The application owns the MongoDB client lifecycle,
39
45
  * including shutdown.
40
46
  */
41
- interface OidcVaultMongoStoreProvider extends OidcVaultStoreProvider {
47
+ interface OidcVaultMongoStoreProvider extends OidcVaultDeviceBindingStoreProvider {
42
48
  /**
43
49
  * Waits for startup validation to complete.
44
50
  *
45
51
  * Readiness validates collection names, creates required indexes, and verifies
46
- * the MongoDB deployment supports transactions required by session rotation.
52
+ * the MongoDB deployment supports rotation/replay transactions and matching
53
+ * shared replay-capacity configuration.
47
54
  * If readiness fails, every store operation rejects with the same error.
48
55
  */
49
56
  ready(): Promise<void>;
@@ -58,8 +65,8 @@ declare const DEFAULT_ROTATED_SESSION_ALIAS_RETENTION_MS: number;
58
65
  * Pass a `Db` from an already-connected caller-owned `MongoClient`, await
59
66
  * `store.ready()` before accepting traffic, and close the client from your own
60
67
  * shutdown path. Readiness validates all configured collection names, creates
61
- * required indexes for the five store collections, and verifies that the
62
- * MongoDB deployment supports transactions required by session rotation.
68
+ * required indexes for the seven store collections, validates shared replay
69
+ * capacity, and verifies transaction support for rotation/replay admission.
63
70
  */
64
71
  declare function createMongoOidcVaultStore(options: MongoOidcVaultStoreOptions): OidcVaultMongoStoreProvider;
65
72