Guide April 18, 2026 · 19 mins · The D23 Team

Embedded Analytics Authentication: JWT, RLS, and Multi-Tenancy

Secure multi-tenant embedded analytics with JWT authentication, row-level security, and isolation patterns. Technical guide for SaaS teams.

Embedded Analytics Authentication: JWT, RLS, and Multi-Tenancy

Understanding the Authentication Challenge in Embedded Analytics

When you embed analytics into your SaaS product, you’re not just dropping a dashboard into a web page. You’re creating a security perimeter that must authenticate users, isolate their data, and prevent cross-tenant access—all while maintaining the performance expectations your customers demand.

The stakes are high. A single misconfigured authentication layer can expose customer data across your entire product. Worse, a slow or brittle auth system becomes a bottleneck that degrades the analytics experience your users depend on. You need a strategy that’s simultaneously bulletproof and invisible.

This guide walks through the technical architecture for embedding analytics securely in multi-tenant SaaS applications. We’ll focus on three core pillars: JSON Web Tokens (JWT) for stateless authentication, row-level security (RLS) for data isolation, and multi-tenancy patterns that keep customer data separated at every layer.

What Is JWT and Why It Matters for Embedded Analytics

A JSON Web Token is a cryptographically signed, URL-safe string that contains claims about a user’s identity and permissions. Instead of your analytics platform making a round-trip call to your authentication server for every request, the token itself carries all the information needed to verify who the user is and what they can access.

JWT has three parts, separated by periods:

  • Header: Specifies the token type (JWT) and the signing algorithm (typically HS256 or RS256)
  • Payload: Contains claims—structured data about the user, their organization, role, and any custom attributes your analytics platform needs
  • Signature: Cryptographic proof that the token wasn’t tampered with

For embedded analytics, JWT solves a critical problem: you can’t rely on browser cookies or session storage alone when your analytics is embedded in your product. The analytics platform (whether it’s D23’s managed Apache Superset or another solution) needs to trust the identity assertion without calling back to your auth server on every single query.

When your user logs into your SaaS product, your backend generates a JWT with claims that identify them, their organization, and their role. That token gets passed to the embedded analytics frontend. The analytics platform validates the signature (proving it came from your backend) and extracts the claims to enforce access control.

The key advantage: stateless authentication. The analytics platform doesn’t need to maintain session state or make synchronous calls to verify identity. The token is self-contained and cryptographically verifiable.

Row-Level Security: The Data Isolation Layer

JWT handles user identity. Row-level security (RLS) handles data isolation. These two mechanisms work together but solve different problems.

RLS is a database-level feature that filters query results based on the user’s identity or attributes. Instead of trusting your analytics application layer to enforce access control, you push that enforcement into the database itself. This is the “defense in depth” principle: even if a bug exists in your application code, the database refuses to return unauthorized data.

Here’s how it works in practice:

  1. A user makes a query through the embedded analytics interface
  2. The query includes a context variable—typically the user’s organization ID or tenant ID, extracted from their JWT claims
  3. The database evaluates RLS policies before returning any rows
  4. Only rows matching the user’s context are returned

For example, imagine a SaaS product serving multiple e-commerce companies. Company A and Company B both use the embedded analytics. A user from Company A should never see Company B’s revenue data, even if they somehow craft a SQL query that tries to access it.

Without RLS, you rely entirely on your application layer to filter results. With RLS, the database itself enforces the boundary:

CREATE POLICY company_isolation ON orders
  FOR SELECT
  USING (company_id = current_user_id);

This policy means: “Only return rows where the company_id matches the current user’s company_id.” The database enforces this on every query, regardless of what SQL the user submits.

RLS is not unique to one database vendor. Supabase’s authentication documentation shows how to integrate JWT claims with PostgreSQL RLS policies. Multi-tenant database architectures explain the same pattern across different platforms. The principle is universal: push security enforcement as close to the data as possible.

Multi-Tenancy Architecture Patterns

Multi-tenancy is the structural pattern that allows you to serve multiple customers from a single analytics instance. There are three main approaches, each with different security and complexity trade-offs.

Shared Database, Separate Schema

In this pattern, all customers’ data lives in one database, but each customer gets their own schema (namespace). Queries are routed to the correct schema based on the user’s JWT claims.

Pros:

  • Easier to manage backups and migrations
  • Simpler operational overhead
  • Good for teams with moderate data volumes per tenant

Cons:

  • A single database failure affects all customers
  • Harder to enforce strict resource limits per tenant
  • Scaling becomes complex as total data volume grows

Shared Database, Shared Schema with RLS

All customers’ data lives in the same tables, distinguished by a tenant ID column. Row-level security policies filter data based on the tenant ID in the user’s JWT claims.

Pros:

  • Highest operational efficiency
  • Easiest to scale (single database can serve many tenants)
  • RLS enforces isolation at the database layer, not the application

Cons:

  • Requires careful RLS policy design
  • Debugging cross-tenant issues can be harder
  • A single RLS policy bug affects all customers

This is the pattern most commonly recommended for embedded analytics at scale. Multi-tenant analytics for healthcare SaaS discusses this approach using encrypted URL embedding with signed tokens and server-side RLS. Best practices for dynamic pages and multi-organization authentication show JWT claims being used for user organizations and roles with database RLS integration.

Separate Database Per Tenant

Each customer gets their own database instance. This is the strongest isolation model but operationally the most complex.

Pros:

  • Complete isolation between customers
  • Can customize schemas and configurations per customer
  • Easiest to comply with data residency requirements

Cons:

  • Significant operational overhead (managing many databases)
  • Higher infrastructure costs
  • Harder to maintain consistency across instances

Most SaaS teams start with shared database + RLS and only move to separate databases if they have extreme isolation requirements (often driven by regulatory or compliance needs).

JWT Claims Design for Analytics Access Control

The power of JWT lies in the claims you include in the token. These claims become the input to your RLS policies and your analytics platform’s access control decisions.

A well-designed JWT for embedded analytics includes:

Core identity claims:

  • sub (subject): Unique user ID
  • iat (issued at): Token creation timestamp
  • exp (expiration): When the token becomes invalid
  • iss (issuer): Your backend service

Tenant/organization claims:

  • org_id: The customer’s organization ID
  • tenant_id: Equivalent to org_id in some systems
  • workspace_id: If your SaaS supports multiple workspaces per customer

Role and permission claims:

  • role: User’s role (admin, analyst, viewer)
  • permissions: Array of specific permissions (“view_dashboards”, “edit_queries”, etc.)
  • dataset_ids: Array of specific datasets the user can access

Custom analytics claims:

  • department: If analytics should be filtered by department
  • region: If data is region-specific
  • cost_center: For cost allocation across your product

Here’s an example JWT payload for a user embedded in your SaaS:

{
  "sub": "user_12345",
  "org_id": "org_acme",
  "role": "analyst",
  "permissions": ["view_dashboards", "edit_queries"],
  "dataset_ids": ["sales_data", "customer_data"],
  "iat": 1704067200,
  "exp": 1704153600,
  "iss": "https://yoursaas.com"
}

When this token reaches your analytics platform, it can immediately determine:

  • Who the user is
  • Which organization they belong to
  • What datasets they can query
  • What actions they’re allowed to perform

The RLS policy in your database uses the org_id claim to filter rows. The analytics platform uses the permissions and dataset_ids claims to control UI visibility and API access.

Implementing RLS Policies for Tenant Isolation

RLS policies are database rules that filter query results before they’re returned to the application. They’re the enforcement mechanism that makes multi-tenancy actually secure.

The basic structure in PostgreSQL (which powers Supabase Auth and RLS integration) looks like this:

CREATE TABLE orders (
  id UUID PRIMARY KEY,
  org_id UUID NOT NULL,
  customer_id UUID NOT NULL,
  amount DECIMAL,
  created_at TIMESTAMP
);

ALTER TABLE orders ENABLE ROW LEVEL SECURITY;

CREATE POLICY org_isolation ON orders
  FOR SELECT
  USING (org_id = current_setting('app.current_org_id')::uuid);

CREATE POLICY org_isolation_insert ON orders
  FOR INSERT
  WITH CHECK (org_id = current_setting('app.current_org_id')::uuid);

These policies say: “Only show/insert orders where the org_id matches the current organization.” The current_setting() function retrieves the org_id from your application context, which you set when the user’s JWT is validated.

In practice, your analytics platform (like D23’s managed Apache Superset) would:

  1. Receive the user’s JWT
  2. Validate the signature
  3. Extract the org_id claim
  4. Set that org_id in the database session before executing any queries
  5. The database enforces RLS policies automatically

This happens for every query, every time. It’s not a one-time check; it’s continuous enforcement.

Signing and Validating JWTs

JWT security depends entirely on proper signing and validation. There are two common approaches: symmetric signing (shared secret) and asymmetric signing (public/private key pair).

Symmetric Signing (HS256)

Your backend and analytics platform share a secret key. The backend uses it to sign JWTs; the analytics platform uses the same key to verify the signature.

When to use:

  • Both the token issuer and verifier are under your control
  • You can safely share a secret between them
  • Simpler to implement initially

When to avoid:

  • The analytics platform is third-party or distributed
  • You need to rotate keys frequently
  • You want to minimize the blast radius if a key is compromised

Asymmetric Signing (RS256)

Your backend uses a private key to sign JWTs. The analytics platform uses your public key to verify them. The private key never leaves your backend.

When to use:

  • The analytics platform is third-party or you want to limit its access
  • You need to publish your public key for external verification
  • You want better key rotation practices
  • Compliance requirements demand it

When to avoid:

  • You need maximum simplicity and lowest latency
  • Key distribution is complex in your infrastructure

For embedded analytics in a multi-tenant SaaS, asymmetric signing is generally recommended. It lets you maintain tighter control over who can verify your JWTs.

Validation should always check:

  1. Signature: Cryptographic proof the token came from your backend
  2. Expiration: The token hasn’t expired (check the exp claim)
  3. Issuer: The iss claim matches your expected issuer
  4. Audience: If applicable, the token was issued for the right audience

If any check fails, reject the token immediately. Don’t grant access.

Securing the Token Delivery Mechanism

A JWT is only as secure as the channel through which it’s delivered. If you send it in plain HTTP, over an unencrypted connection, or store it insecurely, all the cryptography is worthless.

In transit:

  • Always use HTTPS. Never send JWTs over HTTP
  • Use secure, HttpOnly cookies if storing tokens client-side (prevents JavaScript access)
  • Or generate tokens server-side and pass them in the initial page load

At rest:

  • Don’t store tokens in localStorage (vulnerable to XSS)
  • Use HttpOnly, Secure cookies instead
  • Or regenerate tokens on each page load (if your backend can do this efficiently)

In the embedded analytics context:

  • Generate the JWT on your backend when rendering the embedded analytics page
  • Pass it to the frontend as part of the initial HTML or as a secure cookie
  • The embedded analytics iframe or component reads the token and uses it for all subsequent API calls
  • Set a short expiration time (15 minutes to 1 hour) to limit exposure if a token is compromised
  • Provide a refresh mechanism so users can get new tokens without re-authenticating

Top 21 Authorization Systems and Tools for 2025 discusses tools like ZITADEL for multi-tenant SaaS authentication and authorization, which can integrate with your analytics platform’s JWT requirements.

Implementing Fine-Grained Access Control

Once you have authentication (JWT) and data isolation (RLS) in place, the next layer is fine-grained access control: limiting which dashboards, datasets, and queries specific users can access.

This happens at the application layer, not the database layer. While RLS prevents unauthorized data access at the database level, you still want to hide dashboards and datasets that users shouldn’t see.

Common patterns:

Role-based access control (RBAC): Users have roles (admin, analyst, viewer). Each role has a set of permissions. Your analytics platform checks the user’s role before showing UI elements or allowing actions.

Attribute-based access control (ABAC): Access decisions are based on attributes in the JWT (department, region, cost_center, etc.). A dashboard might only be visible to users with department = "sales".

Dataset-level permissions: Include a dataset_ids array in the JWT. Only show dashboards and queries that use datasets in that array.

For example, a user from the sales department should see sales dashboards. A user from finance should see financial dashboards. This is enforced by including department: "sales" in the JWT and checking it in the analytics platform’s permission logic.

The principle: the JWT carries all the information needed to make access decisions. The analytics platform (and database via RLS) use that information to enforce boundaries.

Handling Token Refresh and Expiration

Tokens have expiration times for security: if a token is compromised, the window of exposure is limited. But you can’t ask users to log in again every 15 minutes.

The solution: refresh tokens. A refresh token is a longer-lived token that can be used to obtain new short-lived access tokens.

Flow:

  1. User logs into your SaaS
  2. Backend issues an access token (15-60 minute expiration) and a refresh token (days or weeks)
  3. Access token is used for API calls to the analytics platform
  4. When the access token expires, the frontend uses the refresh token to get a new access token
  5. Refresh token is stored securely (HttpOnly cookie) and never exposed to JavaScript

For embedded analytics, this typically means:

  • Your backend provides an endpoint that issues new access tokens
  • The embedded analytics frontend calls this endpoint when its token is about to expire
  • A new token is issued and used for subsequent requests
  • The refresh token itself should also have an expiration and should be rotated periodically

This balances security (short-lived access tokens) with usability (users don’t need to re-authenticate constantly).

Practical Implementation with Apache Superset

D23’s managed Apache Superset provides native support for JWT-based authentication and RLS integration. Here’s how the pieces fit together:

  1. Backend integration: Your SaaS backend generates a JWT with the user’s org_id, role, and dataset permissions

  2. Embedded URL generation: Your backend creates an embedded analytics URL with the JWT as a parameter or in a secure cookie

  3. Superset validation: Superset validates the JWT signature and extracts claims

  4. RLS enforcement: Superset passes the org_id claim to your database, which enforces RLS policies

  5. UI filtering: Superset hides dashboards and datasets based on the user’s permissions

This architecture ensures that:

  • Users can’t forge tokens (signatures are verified)
  • Users can’t access data outside their organization (RLS enforces it)
  • Users can’t see dashboards they’re not authorized for (UI filtering enforces it)
  • Every layer has security controls (defense in depth)

Common Pitfalls and How to Avoid Them

Pitfall 1: Storing secrets in code Never commit your JWT signing keys to version control. Use environment variables, secret management systems (AWS Secrets Manager, HashiCorp Vault), or your SaaS provider’s built-in secret management.

Pitfall 2: Not validating token expiration Always check the exp claim. A token that’s been sitting on disk for a month should be rejected, even if the signature is valid.

Pitfall 3: RLS policies that are too permissive If your RLS policy accidentally allows cross-tenant access, it defeats the entire purpose. Test RLS policies thoroughly. Try to query data you shouldn’t have access to; verify the database rejects it.

Pitfall 4: Forgetting to set the org_id context If you validate the JWT but forget to set the org_id in the database session, RLS policies won’t work. Make this a required step in your authentication middleware.

Pitfall 5: Mixing authentication and authorization Authentication answers “Who are you?” (JWT validates this). Authorization answers “What are you allowed to do?” (RLS and fine-grained policies enforce this). Don’t conflate them. A valid JWT proves identity; it doesn’t automatically grant access to all data.

Pitfall 6: Not rotating keys If you use symmetric signing (shared secret), rotate the key periodically. If a key is compromised, you have a limited window to rotate it before old tokens become invalid. Plan for this operationally.

Pitfall 7: Overly complex JWT payloads Don’t put everything in the JWT. Keep it to identity, organization, role, and essential context. Large JWTs add latency and increase the surface area for bugs. If you need to grant access to 500 datasets, use a permissions service instead of listing them all in the JWT.

Monitoring and Auditing Authentication Events

Security is not a one-time implementation; it’s ongoing. You need visibility into what’s happening.

Log and monitor:

  • Failed token validations: Someone tried to use an invalid or expired token
  • RLS policy violations: A query was rejected by an RLS policy (this is a red flag)
  • Permission denials: A user tried to access a dashboard they’re not authorized for
  • Token refresh events: When users refresh their access tokens
  • Unusual access patterns: Same user accessing data from multiple regions simultaneously, accessing datasets they normally don’t use, etc.

Set up alerts for:

  • Repeated failed authentication attempts (potential brute force or misconfiguration)
  • RLS policy violations (potential security issue or bug)
  • Tokens with unusually long expiration times (configuration error)

Multi-tenant embedding in Amazon QuickSight discusses implementing RLS with tag-based rules and dataset parameters, and monitoring is a critical part of that implementation.

Scaling Authentication and RLS

As your SaaS grows, authentication and RLS need to scale with it.

Token generation at scale:

  • Token generation is fast (just cryptographic signing), but if you’re issuing millions of tokens per day, make sure your JWT library is efficient
  • Consider caching tokens for the same user (if they refresh within a short window, return the same token)
  • Use async token generation if you’re issuing them on every request

RLS policy performance:

  • RLS policies add a small overhead to every query (they’re evaluated for every row)
  • With millions of rows, this can add latency
  • Optimize by indexing on the tenant ID column and ensuring RLS policies can use those indexes
  • Consider partitioning tables by tenant ID for extreme scale

Database connection pooling:

  • Each connection needs to have the org_id context set
  • Connection pools can help manage this, but make sure the context is set correctly for each request
  • Don’t reuse connections without clearing the previous context

Multi-tenant analytics for healthcare SaaS discusses scaling embedded analytics with encrypted URL embedding and server-side RLS, which applies to any SaaS vertical.

Compliance and Data Residency Considerations

If you’re serving regulated industries (healthcare, finance, data residency requirements), authentication and RLS design affects your compliance posture.

HIPAA (healthcare):

  • Data must be encrypted in transit (HTTPS) and at rest
  • Access must be logged and auditable
  • JWT and RLS support both, but you need to implement logging
  • User authentication must be strong (JWT with proper key management)

GDPR (EU data protection):

  • Users have a right to access their data
  • RLS supports this: you can grant a user access to their own data
  • Data must be deleted on request
  • RLS can help enforce deletion (if a user’s data is deleted, RLS prevents any access to it)

Data residency:

  • If data must stay in a specific region, RLS can’t enforce this alone
  • You need separate databases per region or a single database with strict RLS policies that check the data’s region
  • Separate databases per region is operationally simpler

Embed multi-tenant analytics in applications with Amazon QuickSight discusses how to use QuickSight’s features for RLS and custom permissions in compliance-sensitive scenarios.

Building Your Authentication Architecture

Here’s a step-by-step approach to implementing JWT and RLS for embedded analytics:

Phase 1: Foundation

  1. Design your JWT schema (what claims do you need?)
  2. Choose a signing algorithm (RS256 for most SaaS)
  3. Implement JWT generation in your backend
  4. Implement JWT validation in your analytics platform
  5. Test with a single tenant

Phase 2: Data Isolation

  1. Identify your tenant ID column (org_id, company_id, etc.)
  2. Design RLS policies for your core tables
  3. Implement RLS policies in your database
  4. Test that RLS actually blocks unauthorized access
  5. Verify performance impact

Phase 3: Fine-Grained Access Control

  1. Add role and permission claims to your JWT
  2. Implement permission checks in your analytics platform
  3. Hide dashboards and datasets based on permissions
  4. Test with different user roles

Phase 4: Production Hardening

  1. Implement token refresh mechanism
  2. Add monitoring and alerting
  3. Document your security architecture
  4. Conduct security review (internal or third-party)
  5. Set up incident response procedures

Phase 5: Scaling

  1. Optimize token generation
  2. Profile RLS policy performance
  3. Implement caching where appropriate
  4. Plan for multi-region or separate databases if needed

Conclusion

Secure embedded analytics in a multi-tenant SaaS requires coordinating three mechanisms: JWT for stateless authentication, RLS for database-level data isolation, and fine-grained access control at the application layer.

JWT provides the identity assertion. RLS enforces the boundary. Application-layer policies control visibility and permissions. Together, they create a security model that’s both robust and performant.

The key is treating security as architectural, not an afterthought. Design your JWT schema to carry the information your analytics platform needs. Design your RLS policies to be simple and testable. Design your application layer to verify every access decision.

When these three layers work together, you get a system where users can’t forge authentication, can’t access unauthorized data, and can’t see dashboards they shouldn’t see. That’s the foundation for trustworthy, scalable embedded analytics.

D23’s managed Apache Superset is built with this architecture in mind. It handles JWT validation, integrates with RLS policies, and provides the fine-grained access control your embedded analytics needs. Whether you’re building on D23 or another platform, the principles outlined here apply: push authentication as close to the user as possible, push data isolation as close to the database as possible, and monitor everything in between.