Skip to main content

superset-auth-kit

PyPI version

CI Python Superset License: MIT

superset-auth-kit (SAK) is a Flask extension for Apache Superset that provides transparent JWT-based SSO and multi-tenant embedding for SaaS applications.

It integrates directly into Superset's Flask-AppBuilder security layer — no proxy, no sidecar, no fork required.


Features

  • JWT SSO — Validate HS256, RS256, or ES256 tokens from your identity provider and create a Superset session in one POST request.
  • Anti-replay protection — JTI blocklist with pluggable backends: in-memory (single process) or Redis (distributed).
  • Multi-tenant context — Thread-safe and greenlet-safe tenant propagation via contextvars.ContextVar (PEP 567). Fail Closed: raises an error rather than leaking data across tenants.
  • Row Level Security (RLS) — current_tenant() Jinja macro for SQL templates. Works with cache_key_wrapper to guarantee per-tenant cache isolation.
  • Declarative role management — CapabilityBundle definitions provisioned idempotently into Superset's FAB database. Two production-ready bundles included: DashboardConsumer (white-label embed) and ChartAuthor (authoring workspace).
  • CLI — superset authkit provision-roles and superset authkit check-compat for pipeline and Kubernetes initContainer integration.
  • Secure by default — Admin role injection blocked, session fixation protection, open-redirect prevention, HMAC-signed server sessions.

Compatibility

SAK Version Superset Flask-AppBuilder Python
0.1.x 6.1.x 5.0.x 3.10+

Installation

pip install superset-auth-kit[api]

Optional extras:

Extra Installs Use case
api flask, flask-login, marshmallow SSO endpoint
redis redis Distributed JTI blocklist
cli flask, click, sqlalchemy provision-roles CLI
dev All of the above + pytest, mypy Development

Quick Start

1. Configure Superset

In your superset_config.py:

from superset.security import SupersetSecurityManager

from superset_auth_kit.api.blueprint import create_sso_blueprint, init_app
from superset_auth_kit.providers.jwt import JwtProvider
from superset_auth_kit.replay.blocklist import InMemoryJtiStore
from superset_auth_kit.security.manager import build_manager
from superset_auth_kit.sync.role_mapper import RoleMapper
from superset_auth_kit.tenant.context import TenantContext

# Identity provider
_provider = JwtProvider(
    secret_or_key="your-jwt-shared-secret",  # or an RSA/EC public key
    algorithms=["HS256"],
    jti_store=InMemoryJtiStore(),  # use RedisJtiStore in production
)

# IdP role -> Superset role mapping
_mapper = RoleMapper(
    mapping={"viewer": "sak__dashboard_consumer", "analyst": "sak__chart_author"},
    allowed_roles=frozenset({"sak__dashboard_consumer", "sak__chart_author"}),
    default_roles=("sak__dashboard_consumer",),
)

# Inject SAK into Superset's security layer
CUSTOM_SECURITY_MANAGER = build_manager(
    SupersetSecurityManager,
    identity_provider=_provider,
    role_mapper=_mapper,
)

# Register the SSO endpoint blueprint
BLUEPRINTS = [create_sso_blueprint()]
FLASK_APP_MUTATOR = init_app

# Expose current_tenant() in Jinja SQL templates
JINJA_CONTEXT_ADDONS = {
    "current_tenant": TenantContext.get_tenant,
}

2. Provision roles

superset authkit provision-roles

This creates sak__dashboard_consumer and sak__chart_author in the FAB database. The command is idempotent — safe to run on every deployment.

3. Authenticate via SSO

Your frontend sends a signed JWT to:

POST /api/v1/auth/sso
Content-Type: application/json

{
  "token": "<signed-jwt>",
  "redirect_to": "/superset/dashboard/1/"
}

On success: 302 redirect to redirect_to with a Flask session cookie set.


JWT Claims

The JWT must contain the following claims:

Claim Required Description
sub ✅ Unique user identifier
email ✅ User email address
given_name ✅ First name
family_name ✅ Last name
roles ✅ List of IdP role names (strings)
tenant_id ✅ Tenant identifier — ^[a-zA-Z0-9_-]{1,128}$
exp ✅ Expiration timestamp (standard JWT claim)
iat recommended Issued-at timestamp
jti recommended Unique token ID (enables anti-replay)

Claim names are configurable via ClaimMapping in JwtProvider.


Row Level Security

In your Superset SQL template (dataset or RLS filter):

-- Correct: tenant_id is included in BOTH the SQL filter AND the cache key
WHERE tenant_id = '{{ cache_key_wrapper(current_tenant()) }}'

The cache_key_wrapper call ensures that the tenant value is included in the SHA-256 cache key hash, preventing cross-tenant cache collisions.


Role Management

Built-in capability bundles

Bundle key FAB role name Profile
dashboard_consumer sak__dashboard_consumer Embed-only viewer. Zero menu_access. Read-only.
chart_author sak__chart_author Chart and dashboard authoring. No SQL Lab or admin access.

CLI

# Provision all bundles
superset authkit provision-roles

# Provision specific bundles
superset authkit provision-roles --bundle dashboard_consumer

# Dry-run: show what would change without applying
superset authkit provision-roles --dry-run

# Force re-provision even if version matches
superset authkit provision-roles --force

# Check compatibility with the installed Superset version
superset authkit check-compat

Versioning

Each bundle has a version: int. When you modify a bundle's permission graph, increment the version. On the next provision-roles run, SAK detects the version change and applies the diff automatically.

Downgrades (deploying an older bundle version over a newer database version) are blocked with an explicit error — they must be an intentional explicit action, not a silent side effect of a rollback.


Configuration Reference

Config variable Type Description
CUSTOM_SECURITY_MANAGER type Required — output of build_manager()
BLUEPRINTS list Required — [create_sso_blueprint()]
FLASK_APP_MUTATOR callable Required — init_app
JINJA_CONTEXT_ADDONS dict Required for RLS — {"current_tenant": TenantContext.get_tenant}
SESSION_COOKIE_SECURE bool Recommended True in production
SESSION_COOKIE_HTTPONLY bool Recommended True
SESSION_COOKIE_SAMESITE str Recommended "Lax" or "Strict"

JwtProvider options

JwtProvider(
    secret_or_key=...,          # str (HMAC) or RSA/EC public key PEM
    algorithms=["HS256"],       # non-empty list — required by PyJWT 2.x
    jti_store=InMemoryJtiStore(),
    claim_mapping=ClaimMapping( # optional, all fields have defaults
        sub="sub",
        email="email",
        given_name="given_name",
        family_name="family_name",
        roles="roles",
        tenant_id="tenant_id",
    ),
    leeway=0,                   # clock skew tolerance in seconds
)

Redis JTI store

from superset_auth_kit.replay.blocklist import RedisJtiStore
import redis

jti_store = RedisJtiStore(
    client=redis.Redis.from_url("redis://localhost:6379/0"),
    ttl=3600,  # seconds — should match your JWT max expiry
)

Docker Compose Integration

superset:
  image: apache/superset:latest
  environment:
    SUPERSET_CONFIG_PATH: /app/pythonpath/superset_config.py
  command: >
    bash -c "
    pip install superset-auth-kit[api,cli] &&
    superset db upgrade &&
    superset init &&
    superset authkit provision-roles &&
    superset run -p 8088 --host 0.0.0.0 --with-threads
    "

Kubernetes / Helm

initContainers:
  - name: provision-sak-roles
    image: "apache/superset:latest"
    command: ["superset", "authkit", "provision-roles"]
    env:
      - name: SUPERSET_CONFIG_PATH
        value: /app/pythonpath/superset_config.py

This guarantees provisioning completes before application pods start — the recommended K8s pattern for data initialization.


Development

git clone https://github.com/plinxore/superset-auth-kit.git
cd superset-auth-kit
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"

# Run unit tests (no Docker required)
pytest tests/unit/ -v --tb=short -m "not integration"

# Run integration tests (requires Docker)
pytest tests/integration/ -v -m integration --timeout=300

# Type checking
mypy superset_auth_kit/ --ignore-missing-imports \
    --exclude 'superset_auth_kit/cli/commands\.py'

See CONTRIBUTING.md for the full contribution guide.


Security

  • JWT algorithm confusion: algorithms must be a non-empty list; "none" is never accepted.
  • Admin role injection: blocked at RoleMapper construction and UserSyncer runtime.
  • Tenant ID: validated by regex ^[a-zA-Z0-9_-]{1,128}$ at every ContextVar write. TenantResolutionError is raised (never None returned) when the context is missing.
  • Session fixation: session.clear() is called before every login_user().
  • Open redirect: redirect_to only accepts relative paths starting with /.

License

MIT — Copyright (c) 2026 Plinxore

Metadata

Release files for superset-auth-kit 0.1.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for superset-auth-kit 0.1.2
File Size Uploaded Provenance
superset_auth_kit-0.1.2.tar.gz 45.8 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for superset-auth-kit 0.1.2
File Interpreter ABI Platform
superset_auth_kit-0.1.2-py3-none-any.whl Python 3 none any Details

Total release size: 98.6 kB

Release files / superset_auth_kit-0.1.2.tar.gz

Download URL superset_auth_kit-0.1.2.tar.gz
Size 45.8 kB
Tags Source
SHA-256 checksum
How to use checksums
e5430bf7f9e2da900fafbebd22dbc179080bdc094e2fb4ac7764e0c743c020ea
BLAKE2b-256 checksum
How to use checksums
5a4e9cb076ed01762788a194427b1766a6078abf5d6e267b2427299c05638496
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.32 {"installer":{"name":"uv","version":"0.11.32","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / superset_auth_kit-0.1.2-py3-none-any.whl

Download URL superset_auth_kit-0.1.2-py3-none-any.whl
Size 52.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
adae39648880737021ecaff26c7f2d3fa76a2b4e8fa7a84498da61a721fbc0a5
BLAKE2b-256 checksum
How to use checksums
c9e658ae5cb2e71275522573300ebbda2dceb43d642de7d9a971351c64b8a3cc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.32 {"installer":{"name":"uv","version":"0.11.32","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Security for superset-auth-kit 0.1.2

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page