How to Integrate Custom Authentication with Apache Superset: A Complete Guide

You can integrate custom authentication with Apache Superset by extending the better-auth configuration in packages/auth/src/server.ts to add OAuth providers, custom session data, and JWT claims.

The superset-sh/superset repository ships with a production-ready authentication layer built on better-auth, providing a type-safe foundation for enterprise login flows. Whether you need to connect a corporate SSO, inject organization-specific metadata into user sessions, or secure API endpoints with custom JWT claims, the architecture exposes clear extension points without modifying core framework code.

Understanding the Authentication Architecture

The authentication system centers on a single configuration object in packages/auth/src/server.ts where the betterAuth() factory registers plugins for specific capabilities. This design keeps all auth logic centralized while remaining extensible through a plugin-based model.

Key files in the authentication stack include:

How to Add a Custom OAuth Provider

Superset-sh supports multiple OAuth 2.0 providers simultaneously through the socialProviders object in the better-auth configuration. You can add corporate identity providers like Microsoft Entra ID, Okta, or Auth0 by extending this configuration block.

To register a new provider, locate the socialProviders definition (approximately lines 90–98 in server.ts) and add your provider configuration:

// packages/auth/src/server.ts – inside the `betterAuth({ … })` call
socialProviders: {
  github: { 
    clientId: env.GH_CLIENT_ID, 
    clientSecret: env.GH_CLIENT_SECRET 
  },
  google: { 
    clientId: env.GOOGLE_CLIENT_ID, 
    clientSecret: env.GOOGLE_CLIENT_SECRET 
  },
  // Add Microsoft OAuth provider
  microsoft: {
    clientId: env.MS_CLIENT_ID,
    clientSecret: env.MS_CLIENT_SECRET,
    scopes: ["email", "profile", "openid"],
    // Optional: override authorization or token endpoints for tenant-specific flows
  },
},

Ensure corresponding environment variables are defined in packages/auth/src/env.ts and your deployment environment.

Enriching Sessions with Custom Data

For scenarios requiring organization-specific context—such as feature flags, tenant isolation, or user roles—you can inject custom fields into the session object using the customSession plugin. This callback executes on every request after user identification, allowing dynamic enrichment based on database lookups or external services.

The customSession implementation resides approximately at lines 539–586 in server.ts. Modify the callback to append your custom logic:

// packages/auth/src/server.ts – customSession hook
customSession(async ({ user, session: baseSession }) => {
  const session = baseSession as typeof sessions.$inferSelect;

  // Existing enrichment logic for active organization
  const activeOrganizationId = session.activeOrganizationId;
  
  // Custom: Add feature flag based on email domain
  const isEnterpriseUser = user.email.endsWith("@enterprise.com");
  
  // Custom: Fetch additional user metadata from your database
  const userPreferences = await db.query.userPreferences.findFirst({
    where: eq(userPreferences.userId, user.id),
  });

  return {
    user,
    session: {
      ...session,
      activeOrganizationId,
      isEnterpriseUser,      // Injected custom field
      preferredLocale: userPreferences?.locale ?? "en",
    },
  };
}),

These injected fields become available throughout your application via the session object.

Customizing JWT Claims for API Security

When securing API endpoints or integrating with external services, you may need to embed specific claims—such as organization IDs, roles, or locale preferences—directly into JWT access tokens. The customAccessTokenClaims option in server.ts (approximately lines 218–220) enables this customization.

Define additional claims by extending the configuration object:

// packages/auth/src/server.ts – customAccessTokenClaims
customAccessTokenClaims: ({ referenceId, user }) => ({
  organizationId: referenceId ?? undefined,
  role: user.role ?? "viewer",
  locale: user.locale ?? "en",   // Custom claim for localization
  tenantTier: user.tier ?? "free", // Custom claim for billing tier
}),

These claims are cryptographically signed and verifiable by downstream services, enabling stateless authorization decisions without database lookups.

Accessing Authentication State in Client Code

The client-side integration relies on the typed auth object exported from packages/auth/src/client.ts. This client provides methods to retrieve sessions, handle OAuth callbacks, and manage authentication state in React components or other UI code.

Import the client and access enriched session data:

// packages/auth/src/client.ts – typed client usage
import { auth } from "./client";

async function fetchDashboardData() {
  const { session } = await auth.getSession();
  
  if (!session) {
    throw new Error("Unauthorized");
  }
  
  // Access custom fields injected by customSession
  console.log("Enterprise access:", session.isEnterpriseUser);
  console.log("User locale:", session.preferredLocale);
  
  // Use organization ID from session for tenant-scoped queries
  return await api.dashboards.list(session.activeOrganizationId);
}

The type definitions automatically reflect any custom fields added to the session configuration, ensuring end-to-end type safety.

Summary

Integrating custom authentication with Apache Superset requires understanding the better-auth plugin architecture centralized in packages/auth/src/server.ts. The key extension points include:

  • OAuth Providers: Extend the socialProviders object to add corporate SSO options like Microsoft or Okta.
  • Session Enrichment: Use the customSession callback to inject organization-specific metadata and feature flags.
  • JWT Customization: Define additional claims via customAccessTokenClaims for stateless API authorization.
  • Client Integration: Consume the typed auth client from packages/auth/src/client.ts to access session data in UI components.

All modifications remain type-safe and persist across the tRPC API layer defined in packages/trpc/src/trpc.ts.

Frequently Asked Questions

Can I integrate multiple OAuth providers simultaneously?

Yes. The socialProviders configuration object in packages/auth/src/server.ts accepts multiple provider definitions concurrently. You can enable GitHub, Google, Microsoft, and custom OIDC providers simultaneously, and better-auth will handle the routing and callback logic for each. Users can then choose their preferred login method from the authentication UI.

How do I store additional user metadata in the session?

Use the customSession plugin callback in packages/auth/src/server.ts to fetch and attach custom fields. This async function receives the user and session objects, allowing you to query external databases or APIs to retrieve roles, preferences, or tenant information. Return these values in the session object, and they become available in both server-side tRPC contexts and client-side code via the typed auth client.

Is the authentication system compatible with existing Superset deployments?

The superset-sh/superset repository represents a modernized architecture built on better-auth, which differs from the legacy Flask-AppBuilder authentication in traditional Apache Superset deployments. While the concepts (OAuth, JWT, RBAC) remain similar, the implementation files and configuration methods described here are specific to the superset-sh codebase. Migration from legacy Superset would require adapting existing authentication logic to the better-auth plugin architecture described in packages/auth/src/server.ts.

Where should I define environment variables for authentication?

Environment variables are validated and typed in packages/auth/src/env.ts using a schema validation library (likely Zod or similar). Define all OAuth client secrets, JWT signing keys, and API key secrets in this file to ensure type safety across the application. The validated env object is then imported into packages/auth/src/server.ts and passed to the better-auth configuration, ensuring that sensitive credentials are never hardcoded and are properly validated at startup.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →