
A cache entry containing tenant data needs an identity that includes the tenant boundary. A record identifier alone is insufficient when two workspaces can use the same identifier. The request also needs authorization before any cached value is returned.
This guide develops a narrow cache review alongside the broader SaaS foundations overview. The SaaS & Client Portal Foundation remains an unimplemented blueprint. A small synthetic teaching example accompanies the worksheet; its scope is application cache-key selection and permission checking, without a database, Redis server or deployed portal.
Resolve the workspace before building the key
Derive the active workspace from an authenticated application session and validate the user's membership. A workspace identifier in a URL can select the requested workspace, but the application must decide whether that selection is permitted.
OWASP recommends permission validation on every request and a deny-by-default policy. A cache hit is still a request for protected information, so it belongs after that permission decision. The key should be built from the validated context. OWASP authorization guidance.
For the example, use a tuple containing the workspace, resource kind and record identifier. A real implementation may need a schema revision or additional visibility dimensions. Add only dimensions that affect the cached representation. If two roles see different fields, either store a role-independent record and filter it after authorization or include the relevant representation boundary in the key.
Test collisions with deliberate identifiers
Prepare two synthetic workspaces with a record bearing the same local identifier. Give each record visibly different content. Warm the cache through workspace A, then request the corresponding record through workspace B. The expected result is B's content, with no field copied from A.
| Proposed check | Setup | Expected result |
|---|---|---|
| Same local ID | A and B each own record 7 | Each receives its own value |
| Guessed workspace | A-only member requests B | Denied before cache lookup |
| Warm cache after revocation | Previously authorized member is removed | Cached data is not returned |
| Wrong write context | Worker attempts another workspace's write | Request is rejected |
| Representation change | Role loses a visible field | Old expanded response is unavailable |

Inspect the paths below and above the cache
Database row security can provide another check on protected records. PostgreSQL documents default denial when row security is enabled without a matching policy. It also documents that superusers and roles with BYPASSRLS bypass it, while table owners normally do too. Test the actual application role so an administrator connection does not conceal the missing boundary. PostgreSQL row security.
Those database checks cannot inspect a response already supplied from an application cache. Preserve request-level authorization even when the underlying table has a carefully tested policy. Conversely, a correctly partitioned cache cannot compensate for a database query that reads another tenant's record on a miss.
HTTP caching adds a separate layer. RFC 9111 restricts shared caching of responses to requests carrying authorization credentials unless specified response directives permit it. The same specification defines private and no-store. Review proxy and browser behavior independently from application key design. HTTP caching.
Make invalidation match the representation
Document what changes when membership or a record changes. In the proposed teaching example, permission is checked on every read against current in-memory membership. Revocation therefore blocks a warm-cache read. This demonstrates one control flow without establishing how a distributed membership service propagates changes.
For a deployed system, name the authority for membership and specify how stale local copies are detected. If the application caches permissions, record the maximum allowed stale interval and the invalidation mechanism. Keep that decision separate from the time-to-live of business data.
A worker that fills the cache also needs an explicit workspace context. Record the workspace on the queued job, validate it when the job runs and construct keys through the same bounded path. A background process should not inherit the last workspace selected by a browser user.
Download the tenant cache review kit to inspect the synthetic example and review worksheet. The worksheet's proposed deployment cases remain Not run; the example's seven passing checks are recorded separately and cover the local model only. They exercise colliding identifiers, denied reads and writes, revocation after cache warmup and scoped invalidation.
Use the SaaS & Client Portal Foundation blueprint to agree workspace roles, cache boundaries and revocation behavior for a custom implementation. A finished downloadable application starter does not exist yet.