Concept lesson · Foundations
Authentication, authorization, and tenant isolation
Start here
Definition
Authentication establishes who a caller is; authorization decides whether that caller may perform a particular action on a particular resource. Tenant isolation prevents one customer’s users or workloads from accessing or improperly affecting another customer’s data and resources in a shared service.
Why it matters: A valid login, an unguessable ID, or encrypted storage does not stop an application from returning the wrong customer’s record.
A trusted tenant context constrains every database query, cache entry and job. Knowing an identifier is not authorization.
Read the diagram step by step
- Authenticate user U9, then check active membership in tenant Acme and permission to read invoice I17.
- The database lookup includes tenantId=Acme and invoiceId=I17 plus the finer owner or role policy. The authorized content version is the one returned; a later content fetch must not silently return a different private version.
- Cache and job identities retain the same server-derived tenant scope. Caller-supplied tenant IDs are not trusted authority.
- An unauthorized user U10 must not receive I17 merely by requesting the same URL.
Worked example
Invoice I17 in tenant Acme has amount $45.00. User U10 is authenticated for Birch; GET /tenants/Acme/invoices/I17 must deny access despite the valid login.
Key takeaways
- Authenticate the caller, then authorize the exact action and resource.
- Derive tenant scope from verified membership and carry it through every data path.
- Encryption and dedicated storage help specific threats; they do not replace access checks.
You will learn to
- Separate identity from permission with a concrete record.
- Carry trusted tenant scope through databases, caches, search, and jobs.
- Explain encryption, least privilege, and resource isolation.
Practice in this chapter
8 interview questions with model answers and follow-ups.
Go to interview practiceUseful foundations: HTTP APIs and request lifecycle · Databases, data models, and ACID transactions · Caching: cache hits, misses, write policies and invalidation
Workload and timing examples are interview assumptions.
Dotted concept links open the relevant explanation in a new tab.
01Authentication, authorization, and tenant isolation: definitions
Authentication establishes who a caller is. Authorization decides whether that caller may perform a particular action on a particular resource. A tenant is a customer or organization whose users, data, and access policies are managed as one group; multi-tenancy means one service supports several tenants, often on shared infrastructure. Tenant isolation keeps one tenant’s users and workloads from improperly accessing or affecting another tenant’s data and resources.
Tenant isolation must hold across every path that returns data or creates an effect. For example, user U9 belongs to tenant Acme and may read invoice I17; user U10 belongs to Birch and has no such permission. Knowing I17 or copying its URL must not authorize access, including through search, exports, attachments, or background jobs.
A random identifier makes guessing harder; it does not establish permission. HTTPS protects a communication channel; it does not tell the application whether the caller owns the invoice. Building security into the request and data model gives each protection a specific job.
02Trusted principal, membership, roles, and revocation
A user may belong to multiple tenants. Switching from Acme to Birch requires a verified membership decision. A support administrator may have additional narrowly scoped privileges that should be explicit and auditable. Service-to-service identity similarly needs a bounded permission set; an internal network address is not sufficient authorization.
Limit credential permissions and lifetime, and decide how revocation takes effect. After a user is removed, a cached membership check may still allow access. Expire or invalidate that decision according to the maximum revocation delay the service promises.
Keep the mechanisms distinct:
| Mechanism | What it supplies | What the invoice service still checks |
|---|---|---|
| Server session referenced by a cookie | A server-managed authenticated session | Session validity, tenant membership and action/resource policy |
| OAuth access token | Delegated access for its intended resource and scope | Token validation, audience and current object permission |
| OpenID Connect | Authentication built on OAuth, including identity claims | Establish the application session; an ID token is not an API access-token contract |
| Mutual TLS | Authenticated peer identities on a connection | Which tenant and actions that service identity may perform |
A JSON Web Token (JWT) is a token format, not an authorization policy or an encryption guarantee. A signed token can remain cryptographically valid after membership changes; strict current-membership checks need current server state or a revocation mechanism. Role-based access control (RBAC) assigns permissions to roles. Attribute-based access control (ABAC) also evaluates properties such as tenant, owner, classification or environment. An invoice rule might require active membership AND invoice-read permission AND matching tenant AND any required owner restriction.
03Tenant-scoped authorization: worked invoice read
Consider the stored record Invoice(tenantId=Acme, invoiceId=I17, amountMinor=4500, ownerId=U9).
- U9 requests
GET /tenants/Acme/invoices/I17with a valid credential. - The API authenticates principal U9 and verifies active Acme membership plus the invoice-read permission.
- Data access executes a tenant-scoped lookup using both
AcmeandI17, then applies any finer owner or role rule. - The response includes only permitted invoice fields. A broad database row is not automatically an appropriate response representation.
- An audit event records the principal, tenant, action, resource, decision, and trace ID without copying credentials or unnecessary invoice contents.
U10's identical URL fails authorization. Whether the external status is forbidden or not-found depends on the API's deliberate information-disclosure policy, but the record is never returned. Every object action—including update, attachment download, bulk export, and support tools—needs the same policy enforcement.
Define when revocation takes effect. An admission-time policy checks permission when accepting a request and allows that authorized request to finish even if access is later revoked. A release-time policy checks the required policy revisions as part of the protected decision to release the response, withholding it if they have changed. Neither can withdraw bytes the recipient already received.
- 1 → 2credential and requested contextU9 + Acme request → Validate identity and membership
- 2 → 3trusted principal and tenantValidate identity and membership → Authorize I17 version + policy
- 3 → 4tenant + version + policy revisionAuthorize I17 version + policy → Fetch matching scoped version
- 4 → 5match decision; otherwise reauthorizeFetch matching scoped version → Return permitted fields
- 3 → 6record decision without secretsAuthorize I17 version + policy → Protected audit event
04Shared tables, separate databases, and dedicated deployments
Tenant data can share progressively less infrastructure: rows within the same tables, separate databases, or separate application deployments. The choice changes how much routing and policy enforcement is shared, how failures spread, and how many resources must be operated separately. Every option still needs to map the authenticated caller to the correct tenant.
| Model | Mechanism | Benefit | Cost and risk |
|---|---|---|---|
| Shared tables | Tenant key on rows and scoped access | Efficient pooled operation | A missed scope can expose another tenant |
| Separate schema/database | Tenant-specific logical data boundary | Easier per-tenant lifecycle and some isolation | More migrations, connections, and operational overhead |
| Separate deployment | Dedicated compute and data plane | Stronger resource and failure separation | Higher cost and fleet management complexity |
Database row-level security applies policies that restrict which rows a database role may read or change, providing another enforcement layer. In PostgreSQL, enabled row security without an applicable policy defaults to denial, but owners normally bypass it unless forced, and privileged roles can bypass it. Running the application with a broadly privileged role defeats the intended boundary. Understand the chosen database's exact behavior and keep application authorization as well.
A separate database does not fix a router that selects the wrong tenant database. Shared infrastructure can be safe with disciplined boundaries; dedicated infrastructure still needs correct identity, routing, backups, and operations.
05Tenant isolation in caches, search, jobs, and signed URLs
Suppose the cache key is only invoice:I17. Acme and Birch can both have an invoice I17, so one tenant can receive the other's cached value. Use a key such as tenant:Acme:invoice:I17:v3, and avoid sharing responses across different permission scopes when field visibility varies by user.
Search and vector retrieval must restrict candidate documents to those the caller may access before unauthorized content enters a response or an LLM prompt. Filtering only the final displayed citations is too late. A background export stores trusted tenant and principal context and checks whether its authorization remains valid when it runs or delivers results.
06Encryption in transit, encryption at rest, and data lifecycle
TLS encrypts data in transit and authenticates the intended peer under its trust model. Encryption at rest protects stored bytes against some storage-access threats. Neither protects against an application that legitimately decrypts and then sends a record to the wrong caller.
Use managed key storage or an equivalent protected mechanism, tightly scope decryption permissions, and rotate credentials without putting secrets in source code or browser bundles. Tenant-specific keys can improve separation and lifecycle control but add management and availability dependencies. If the service must search plaintext, explain where decryption occurs and who can access it.
Backups, analytics extracts, dead-letter queues, logs, and support exports also contain data. Apply retention, access control, and deletion workflows to those paths. A deletion request may require immediate loss of application access followed by documented physical cleanup and backup-expiry behavior, rather than an impossible claim that every historical byte vanishes instantly.
For large files, the key service should control access to decryption keys without processing every file byte. Envelope encryption separates those jobs: the application encrypts the bulk data, while a protected service controls the key needed to decrypt it. The following two-key arrangement makes that separation possible.
Envelope encryption separates the key encrypting data from the key protecting that key. Generate a data-encryption key, encrypt the object with an authenticated-encryption scheme, then wrap the data key under a protected key-encryption key, commonly managed by a key management service (KMS). Store the ciphertext (encrypted bytes), wrapped data key, and algorithm/version metadata. Also store the algorithm’s required nonce or initialization vector (IV), an input used for that encryption operation, and its authentication tag, which lets decryption detect tampering. Use a vetted encryption library and follow the selected algorithm’s nonce-uniqueness rules. An authorized reader unwraps the key and decrypts; plaintext keys must not appear in logs or persistent metadata.
This keeps bulk data encryption outside the key service and permits rewrapping keys without necessarily rewriting all ciphertext. That benefit comes with key-service latency, quotas, permissions and recovery dependencies. Rotating a wrapping key is not the same as changing every data key or erasing old data. Application authorization remains necessary after decryption.
07Noisy-neighbor controls and cross-tenant security tests
A noisy neighbor is a tenant whose workload consumes shared resources and degrades others. If Acme launches 10,000 exports, Birch's invoice reads should not wait behind an unbounded queue. Apply per-tenant quotas, bounded concurrency, fair scheduling, and separate pools for expensive background work.
At an assumed two CPU-seconds per export, 10,000 exports need 20,000 CPU-seconds before I/O overhead. A pool limited to 20 fully utilized cores needs roughly 1,000 seconds, or 16.7 minutes, just for that work. Queueing and asynchronous delivery are reasonable; pretending every export can finish immediately is not.
Audit access and quota decisions, alert on unusual cross-tenant denial patterns, and test with two real tenant fixtures. Include negative tests: a valid Birch credential requesting Acme resources, an old signed link after the allowed expiry, and a job whose initiator lost membership. The result should prove the boundary at each route, not merely prove successful login.
Practise the interview questions
Say your answer aloud before opening the model answer. Then answer the follow-up and compare the reasoning.
What is the difference between authentication, authorization, and tenant isolation?
Reveal a model answer
Authentication establishes a caller’s identity. Authorization checks a specific action on a specific resource. Tenant isolation requires those checks and data boundaries to prevent cross-tenant exposure through every path. For example, authenticated principal U10 belongs to Birch and must not read Acme invoice I17 through the API, cache, search, export, or file endpoint.
Interviewer follow-up
Would using unguessable invoice UUIDs remove the need for object authorization?
Reveal the follow-up answer
No. IDs can leak, be shared, or appear in logs. The service must check the actor, tenant, resource, and action regardless of how hard the ID is to guess.
What the answer must demonstrate: Use an actual permitted and forbidden resource path.
Can the API trust an X-Tenant-ID header?
Reveal a model answer
“It can treat it as a requested tenant, then verify the authenticated principal’s membership and permission. I never let a caller-selected tenant ID bypass that decision, and I propagate the verified scope into data access.”
Interviewer follow-up
What about a background worker?
Reveal the follow-up answer
It receives authenticated job context and an explicit execution/delivery authorization policy, not an unvalidated tenant string.
What the answer must demonstrate: Trace how the scope becomes trusted.
Why can invoice:I17 be an unsafe cache key?
Reveal a model answer
Two tenants may share invoice I17, and users may have different field permissions. I key cached bodies by tenant and immutable representation version, authorize the exact version and current policy scope, then return only that authorized representation. If the fetched body or required policy revision differs from the decision, I reauthorize or withhold it.
Interviewer follow-up
Would a global cache flush solve the design?
Reveal the follow-up answer
It can contain an incident, but the durable fix is correct keys, authorization boundaries, and revocation behavior.
What the answer must demonstrate: A fast cache can consistently leak data.
Is row-level security sufficient on its own?
Reveal a model answer
“It is useful defense in depth when policies, roles, and connection context are correct. I still enforce object/action permission in the application and verify privileged-role bypass behavior. A database policy cannot secure an unscoped object-storage or cache path.”
Interviewer follow-up
What if the app connects as the table owner?
Reveal the follow-up answer
In PostgreSQL owners normally bypass row security unless forced, and superusers/BYPASSRLS roles remain privileged. I use a restricted runtime role and transaction-local tenant context, then test reads and WITH CHECK behavior on writes through the actual pooled connections.
What the answer must demonstrate: Know the enforcement boundary.
Does encryption at rest prevent one tenant seeing another’s records?
Reveal a model answer
“No. If the application can decrypt both tenants’ records, it can still send the wrong one. Check tenant permissions, route to the correct data and return only allowed fields. Encryption protects stored bytes; it does not make those application decisions.”
Interviewer follow-up
Where should keys live?
Reveal the follow-up answer
In protected key or secret infrastructure with scoped access and rotation, outside source control and client bundles.
What the answer must demonstrate: Name the threat each mechanism addresses.
Is a signed download URL private to the logged-in user?
Reveal a model answer
“Usually it is a bearer capability, so another person holding it can use it until its conditions expire. I authorize before issuance, limit scope and lifetime, and use an application-mediated access check when immediate revocation is required.”
Interviewer follow-up
Should URLs appear in ordinary logs?
Reveal the follow-up answer
Avoid recording capability tokens or query strings that expose access; use safe resource identifiers for observability.
What the answer must demonstrate: Possession can confer access.
How do you stop one tenant’s exports slowing every customer?
Reveal a model answer
“I bound per-tenant concurrency and total queues, schedule fairly, and separate heavy export workers from interactive reads. Quotas describe an enforceable budget; admission control prevents accepting more work than we can serve.”
Interviewer follow-up
What happens above the quota?
Reveal the follow-up answer
Return a clear retry or asynchronous scheduling contract rather than letting memory and latency grow without a bound.
What the answer must demonstrate: Security includes resource isolation.
What would you test beyond successful login?
Reveal a model answer
“Use two tenants and attempt cross-tenant reads, writes, search, exports, attachment downloads, and cache hits. Also test revoked membership and expired capabilities. Each denied operation must leave data and side effects unchanged under its contract.”
Interviewer follow-up
Can error messages leak information?
Reveal the follow-up answer
Yes. Choose a consistent external disclosure policy while retaining detailed protected audit information for operators.
What the answer must demonstrate: Exercise alternate access paths.
Blank-page exercise · 20 minutes
Build the answer yourself
Design an invoice API shared by Acme and Birch. Try to leak Acme invoice I17 through each secondary data path.
- Trace identity, membership, action, and object checks.
- Specify row, cache, search, export, and file boundaries.
- Explain signed-link expiry and membership revocation.
- Bound tenant resource consumption and audit sensitive actions.
Check that each component and design decision follows from your requirements and workload.
Recall the key ideas
Answer from memory before opening each card. Explain why the choice works and what it costs. Revisit missed cards tomorrow.
Authentication, authorization, and tenant isolationAuthentication (AuthN) / authorization (AuthZ)Recall first, then reveal
Authentication, authorization, and tenant isolationAcme and Birch both have invoice I17. What must a cache key include?Recall first, then reveal
The verified tenant ID as well as the invoice ID, with permission scope when users can see different fields. Apply tenant checks to database, search, job and file paths too.
Same record ID can belong to different tenants.
Return to lessonAuthentication, authorization, and tenant isolationEncryptionRecall first, then reveal
Protects bytes and channels; does not decide who may receive decrypted data.
A lock needs a permission rule.
Return to lessonFinal revision
Summary and interview notes
Authentication identifies the caller; authorization evaluates the requested action on the exact resource and representation. Tenant isolation must carry that trusted decision through primary data, caches, search, background jobs, files and operational tools, while resource controls limit noisy neighbors.
Remember these points
- A caller-selected tenant header is a request for context, not proof of membership.
- Authorization must apply to the returned content version and policy context; if the fetched content does not match the authorized version, check permission again before returning it.
- Row-level security (RLS) is an additional enforcement layer with correct roles and transaction scope, not a replacement for cache/file/API authorization.
- Anyone holding a signed download link can use the access it grants. Define its allowed resource, expiry and revocation limits.
- Encryption protects bytes and channels; fair quotas and pools protect shared capacity.
Interview tips
- Use test users and records from two tenants, with one permitted request and one forbidden cross-tenant request, and exercise every alternate read and write path.
- State when a permission revocation takes effect and whether requests authorized before that point may finish.
- Explain how pooled connections acquire and clear verified tenant scope, including failed transactions.
Important qualifications
- OIDC authenticates users on top of OAuth; a JWT format does not by itself prove current object access.
- An application with access to decrypted records can still leak them through a wrong authorization decision.
Technical references
- OWASP: broken object-level authorizationObject IDs do not replace authorization checks.
- PostgreSQL row securityPolicy semantics and privileged-role bypass behavior.
- Azure multitenant architectureIsolation and shared-resource design considerations.
- OpenID Connect Core 1.0, errata set 2Authentication layer over OAuth and distinction between identity and API access.
- PostgreSQL: SETTransaction-local versus session configuration lifetime for pooled connection context.
- AWS KMS cryptography essentialsData keys, envelope encryption and the distinction between data encryption and protection of the data key.
Practice marks stay in this browser.