Skip to content

feat(cache): scope GET caching by public/private API#26

Merged
antoinehage merged 1 commit into
developfrom
feature/cache-scope-public-private
Jun 15, 2026
Merged

feat(cache): scope GET caching by public/private API#26
antoinehage merged 1 commit into
developfrom
feature/cache-scope-public-private

Conversation

@antoinehage

Copy link
Copy Markdown
Member

Summary

GET response caching was keyed only by tenant id, so two users in the same tenant hitting a private GET shared one cache entry — allowing one user to be served another user's response (a cross-user data leak, not just staleness).

The cache now resolves a scope per API:

  • Public APIs (no access_token required) → tenant scope (key = tenant id) — unchanged behavior
  • Private APIs → tenant_user scope (key also includes the URAC user id)

The default is inferred from req.soajs.controller.serviceParams.isAPIPublic (already set upstream by the mt middleware and used by the traffic middleware). It can be overridden per API in the custom registry via a new scope field ("tenant" | "tenant_user").

Safety: a tenant_user request with no resolved user is not cached — a misconfiguration becomes a cache miss, never a cross-user leak.

Also included

unref() the periodic cleanup timers in the three in-memory models (cache, idempotency, traffic) so they no longer hold the Node event loop open. The unit suite now self-terminates without mocha's --exit.

Tests

  • 7 new unit tests covering public/private scoping, per-user key isolation, the safety skip, both override directions, and invalid-scope fallback.
  • Existing cache tests updated to set isAPIPublic.
  • Unit: 174 passing, 0 failing (self-exits).
  • Integration (against live Mongo): 37 passing, 0 failing.

Docs

docs/middleware/cache.md updated: new scope config field, public-vs-private scope section, safety behavior, and corrected cache-key structure / examples.

Cache responses were keyed only by tenant id, so two users in the same
tenant hitting a private GET shared one entry, allowing one user to be
served another user's response.

Cache now resolves a scope per API:
- public APIs (no access_token) -> "tenant"
- private APIs -> "tenant_user" (key includes the URAC user id)
Default is inferred from serviceParams.isAPIPublic and can be overridden
per API via the custom registry "scope" field. A tenant_user request with
no resolved user is not cached (safety: never leak across users).

Also unref the periodic cleanup timers in the memory models (cache,
idempotency, traffic) so they no longer hold the event loop open.

Adds unit tests for public/private scoping and overrides; documents the
scope field in docs/middleware/cache.md.
@antoinehage antoinehage merged commit 28af4d7 into develop Jun 15, 2026
3 checks passed
@antoinehage antoinehage deleted the feature/cache-scope-public-private branch June 15, 2026 13:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant