Separate App Identity from User and Tenant Identity

Two frontend applications can safely share one backend, but they should not be indistinguishable. Treat the calling application, authenticated user, and selected tenant as three separate facts. A shared secret embedded in browser JavaScript is not a trustworthy way to identify an app.

Last updated: November 5, 2026.

{
  "iss": "https://identity.example.com/",
  "sub": "user-1842",
  "aud": "orders-api",
  "azp": "customer-portal",
  "tenant_id": "tenant-73",
  "scope": "orders:read"
}

The API must verify the token signature, issuer, audience, expiry, and authorized-party or client claim. It must then confirm that the user still belongs to the selected tenant and has the required permission.

Use a distinct public client for each frontend

OAuth distinguishes confidential clients that can protect credentials from public clients that cannot. The OAuth client-types definition places browser applications in the public-client category. Give App A and App B different client IDs and redirect origins, but do not place a reusable API secret in either JavaScript bundle.

Separate client IDs improve audit trails, revocation, rate limits, and incident response. They do not authorize tenant data by themselves. The backend should apply app-specific scopes or policy only after validating the user token. Follow the current safeguards in OAuth 2.0 Security Best Current Practice, including exact redirect URI matching and protection against token replay and mix-up attacks.

Enforce tenant membership on every request

A tenant claim or subdomain may select a tenant, but it is not proof of access. The OWASP multi-tenant guidance recommends binding tenant context to a server-verified identity and current membership or service authorization. Resolve that context in middleware, then pass an immutable verified tenant ID to repositories, caches, queues, and logs.

Record app_id, user_id, tenant_id, action, target, and request ID in audit events. If the apps need different permissions, keep separate policy sets keyed by app and user role; a shared deployment does not require one combined permission model.

Split the backend only when scaling, release ownership, compliance, or fault isolation justifies it. Begin with SaaS roles and permissions, tenant-safe SQL queries, and central authorization middleware.

Related Web Cheat Sheet guides

Sergey Kornilov

Sergey Kornilov