Securing Apache Superset OAuth login with PKCE

Proof Key for Code Exchange (PKCE) protects the OAuth authorization code in Superset logins. This page explains when to enable it, how to configure and test it with your identity provider, and what to confirm first.

On this page

Why Apache Superset OAuth PKCE matters for your login

PKCE binds the authorization code to the client that started the login, so a code intercepted in the redirect cannot be exchanged for tokens by anyone else. If you have or are planning an OAuth or OIDC login for Superset, you need to decide whether PKCE belongs in that configuration, and the answer should be settled before the identity provider registration is finalized rather than after go-live. Superset is built on Flask-AppBuilder and supports OAuth2 providers such as Google and Azure, plus custom OAuth2 servers that use the code flow. The exact PKCE parameters you can set depend on the Flask-AppBuilder version and the OAuth provider library installed in your image, so confirm both against the versions you actually run before writing any configuration.

Apache Superset is licensed under the Apache License 2.0 and has no paid edition, so there is no vendor feature gate to check. The work is configuration, testing and governance in your own environment: client registration in your identity provider, the Superset OAuth provider block, and proof that the authorization code flow behaves as expected for your clients. Ask your identity provider team which client types they register for web applications, whether they enforce PKCE, and what they do when a client sends a code challenge that is not expected. Those answers decide whether the Superset client is configured as confidential, public, or both, and they determine how much of the test plan in the rest of this page you need to run.

Treat PKCE as a control to verify, not a checkbox. Record the Flask-AppBuilder and provider library versions, the identity provider's client settings, and a test result showing that a login attempt with a mismatched verifier fails. A reader who can show that evidence can answer an auditor's question about how the login flow resists authorization code interception, and a reader who cannot will spend the review reconstructing it.

When public and confidential Superset clients need PKCE

In the usual Superset setup, the Flask application runs on your server and holds a client secret for the OAuth provider in its configuration. The browser is redirected to the identity provider, and the server exchanges the returned authorization code for tokens using that secret. Because the secret never leaves the server, this is a confidential client. Many identity providers accept a confidential client without PKCE, so PKCE is optional here in many cases, but it is still recommended as an added check that the code was issued to the same login attempt that started it.

  • Secret storage: Confirm the client secret is loaded from a secret store or environment variable, not written into a configuration file committed to source control.
  • Client type: In the provider console, confirm the client is registered as confidential or web application, with the secret enabled.
  • Redirect URI: Confirm the registered redirect URI matches the Superset callback path exactly, including scheme and port.
  • PKCE setting: Check whether the provider lets you require or enable PKCE for confidential clients, and whether it rejects requests that include a code challenge.
  • Rotation: Record who owns the secret and how it is rotated, since a leaked secret lets anyone exchange codes for this client.

Check the rules for confidential clients in your identity provider's documentation before changing the PKCE setting.

Provider settings that change how PKCE behaves

This table compares the provider-side decisions that change how PKCE works in a Superset OAuth login, including client type, challenge method, the client secret, redirect URIs and token handling. Read each row as a question to answer with your identity provider before you edit the Superset configuration, because several of these settings are enforced on the IdP side rather than in Superset.

DecisionWhen it fitsTrade-offConfirm before enabling
Client type: confidentialSuperset's backend can keep a client secret safely on the server and exchange the authorization code there, which is the usual Superset pattern.The secret must be stored, rotated and kept out of version control. PKCE still adds protection against code interception.Confirm in the Flask-AppBuilder OAuth provider documentation how the client secret and PKCE parameters are passed for your provider.
Client type: publicThe client cannot hold a secret, for example a browser-only or mobile-style client registered with the IdP.PKCE becomes the only proof that the code exchange comes from the original client, so the setting cannot be skipped.Confirm with the IdP that the application is registered as public and that it accepts token requests without a secret.
Challenge method: S256 requiredThe IdP enforces S256 and rejects plain challenges, which is the stronger option for any new registration.Clients that only send the plain method will fail at login, so older integrations may need a configuration update.Confirm with the IdP that S256 is enforced and confirm in Flask-AppBuilder that the code challenge method is set to S256.
Challenge method: S256 allowed onlyThe IdP accepts both methods, so a mixed set of clients can keep working during migration.A client can silently fall back to a weaker method if the setting is left permissive after rollout.Confirm in the IdP settings whether plain is still accepted for this application and disable it once Superset is tested.
Client secret kept in useA confidential client still needs its secret for the token request, and PKCE is added on top of it.Keeping the secret means managing rotation, but dropping it without an IdP setting change can break the exchange.Confirm with the IdP whether the secret is mandatory for token requests when PKCE is active, and where Superset reads it from.
Redirect URI registrationExact redirect URIs for each Superset environment are registered in the IdP, one per hostname and path.Wildcards or missing staging entries are a common source of login failures and open redirect risk.Confirm the callback path Superset uses in your Flask-AppBuilder version and register only exact matches for production and staging.
Authorization code lifetimeShort-lived codes limit the window in which an intercepted code could be exchanged.Very short lifetimes can cause failed logins on slow networks or when users pause on the consent screen.Confirm the code lifetime in the IdP policy and test a login from a slow or proxied network before go-live.
Access token lifetime and refreshShorter access tokens reduce exposure of a stolen token. Refresh tokens suit long sessions.Refresh handling adds a stored credential to manage, and longer sessions extend the period in which removed users keep access.Confirm in the IdP whether refresh tokens are issued for this client and in Flask-AppBuilder how session expiry and token refresh are handled.
Logout and session endSuperset sessions end at the application and may remain active at the IdP unless logout is wired through.Local logout alone leaves IdP sessions active, which can re-authenticate a user without a password prompt.Confirm the logout endpoint in the IdP documentation and test the full sign-out path in staging.

How to enable and test PKCE with your IdP

This sequence takes Superset's OAuth provider from an unverified configuration to a staging deployment where PKCE is confirmed on the wire, login succeeds, group-based roles map correctly and a broken verifier is rejected. The output is a documented, tested login path you can promote to production.

  1. Confirm versions and the Flask-AppBuilder release

    The platform engineer records the Superset version in staging and the Flask-AppBuilder release installed alongside it, since OAuth handling lives in Flask-AppBuilder and its behavior can change between releases. Check the version against the release notes on the project's releases page and confirm the Flask-AppBuilder pin in your requirements file. Done means both versions are written into the change record and match what staging actually runs.

  2. Confirm PKCE support and client type at the IdP

    The identity administrator checks in the IdP documentation whether the OAuth application supports PKCE, which code challenge methods it accepts and whether the registration is configured as a confidential or public client. Record whether a client secret is issued and whether PKCE is enforced or only offered. Done means you have a written note of the supported challenge method and client type, and you know whether the IdP will reject requests that omit a challenge.

  3. Register the redirect URI for staging

    The identity administrator adds the exact callback URL that Superset will use for the staging host to the OAuth application, matching scheme, host, port and path. Avoid wildcards unless the IdP requires them and your policy allows it. Done means the IdP lists the staging redirect URI and a test sign-in attempt reaches the IdP's consent or sign-in page without a redirect URI error.

  4. Set the provider block in the configuration

    The Superset administrator adds the OAuth provider block to the configuration file, following the structure in the configuring Superset documentation, and sets the client ID, the discovery or endpoint settings, the scopes and the PKCE-related options the chosen client type requires. Load the client secret from an environment variable or secrets store rather than writing it into the file. Done means the file parses, the provider appears in configuration review, and no secret is stored in plain text in version control.

  5. Restart and confirm the configuration loads

    The operator restarts the Superset web processes in staging and checks the startup logs for configuration errors and for the new provider name on the login page. If the application fails to start, correct the provider block before retrying. Done means Superset starts cleanly, the login page offers the configured provider and the logs show no OAuth configuration warnings.

  6. Verify the authorization request and token exchange

    The tester starts a login in a browser with developer tools or a proxy open and confirms the authorization request to the IdP includes a code challenge and the expected challenge method. After the IdP redirects back, confirm the token exchange at the callback succeeds and Superset creates a session for the user. Done means the request parameters are recorded in the test log and the user lands in Superset as an authenticated account.

  7. Test role mapping for each group

    Using one test user per directory group in staging, the tester signs in and checks the roles Superset assigns against the AUTH_ROLES_MAPPING entries, including the default role for users in no mapped group. Compare each result with the access matrix approved for the environment. Done means every test user holds exactly the roles expected for their group and any mismatch is corrected and retested before go-live.

  8. Confirm failed logins with wrong or missing verifiers

    The tester runs negative cases in staging: a token request with an altered code verifier and one with the verifier omitted, and confirms the IdP refuses both. Record the error responses and check that Superset shows a login failure without creating a session. Done means both negative cases fail as expected and the results are filed with the positive test evidence. Run the upgrade and staging practice described in the upgrade guide before promoting any change.

Why PKCE still helps when Superset holds a client secret

A client secret protects the token exchange only while it stays confidential, and the authorization code that precedes that exchange is a separate exposure. In the OAuth 2.0 authorization code flow, the identity provider redirects the browser back to Superset with a one-time code in the URL. Anyone who obtains that code before Superset redeems it, through a browser extension, a proxy or load balancer log, a referrer leak or a copied callback URL, can try to exchange it. The client secret held by the Superset process is what the identity provider checks at that exchange, so the secret does not by itself stop an attacker who holds only the code from being used in some configurations. PKCE, described in the OAuth 2.0 PKCE specification, closes that gap by binding the code to a verifier that only the Superset process knows.

The mechanism is simple to state. Superset generates a random verifier for each login attempt, sends a hash of it (the challenge) on the authorization request, and presents the original verifier when it redeems the code. An intercepted code without the verifier fails at the token endpoint. Because the verifier lives only in the Superset process for that login, the protection holds even when the secret is confidential and the code has leaked, which is why many providers and security guidance recommend PKCE alongside a confidential client rather than instead of one. Treat this as a design choice to confirm with your security team and with your identity provider's own guidance, since support and enforcement settings differ by provider. Check whether your provider can require PKCE for the client and whether it rejects requests that omit the challenge.

For your plan, record the decision and its owner before changing configuration: whether PKCE is required for this client, which provider setting enforces it, and how a failed exchange will appear in Superset and identity provider logs. Then test a negative case in staging, using a login attempt with the challenge removed or a mismatched verifier, to confirm the provider refuses it. A passing positive login alone does not show that the control is active.

Security risks PKCE addresses and the controls it leaves to you

PKCE closes one specific gap in the OAuth code flow, but the login path also depends on secrets, cookies, redirect rules, role mapping and logs that Superset and your identity provider do not manage for you. Each card below names a risk, what PKCE covers, and the control that stays with your team.

Authorization code interception

An authorization code returned to the browser can be captured by another process or a malicious app on the same device. PKCE binds the code to a verifier that only the Superset server holds, so a stolen code cannot be exchanged on its own. The control that remains yours is confirming that the OAuth client in Superset uses the code flow with PKCE enabled at the identity provider, and that the provider rejects token requests without a matching verifier. Check this during the test pass described in the flow section.

Redirect URI misconfiguration

PKCE does not stop an attacker from sending a user to a callback that the identity provider accepts. A loose redirect list lets codes flow to an address you did not intend. Keep the registered redirect URI list at the provider to the exact callback path for each Superset host, with no wildcards, and remove test or staging entries from production clients. Also confirm the public base URL in Superset matches the registered value, since a mismatch usually shows up as a login loop rather than an error.

Client secret exposure in configuration

Even with PKCE, a confidential Superset client should keep its client secret out of the repository, container images and shared configuration files. Superset reads its configuration from a Python file, so the secret should come from a mounted file or your secrets manager at startup. The secret is your responsibility to store, rotate and revoke. Ask your identity provider team who can read the client record and how a secret rotation is logged.

Session cookies and the SECRET_KEY

Superset signs its session cookies with SECRET_KEY, which must be set by you before the application starts. PKCE protects the login exchange but not the session that follows it. Use a long random key from your secrets store, serve Superset only over HTTPS, and set secure cookie flags at the proxy or in configuration. When you rotate the key, use PREVIOUS_SECRET_KEY so existing sessions do not fail without warning.

Token lifetime and session length

Access and refresh tokens from the identity provider determine how long a removed user can keep a Superset session. Superset does not replace your provider's lifetime policy. Set short access token lifetimes and session timeouts at the provider, decide whether refresh tokens are issued at all, and test that a disabled account loses access on its next request. Confirm these values with the identity team before go-live rather than assuming defaults.

Group claims that over-grant roles

AUTH_ROLES_MAPPING assigns Superset roles from group claims in the token. A broad or stale group, or a claim that lists every group a user belongs to, can grant more data access than intended. PKCE has no effect on what the claim contains. Limit the scope requested for groups, map only dedicated Superset groups, and review the mapping whenever groups change at the provider.

Logging of codes and tokens

Reverse proxies, load balancers and application logs can record query strings that contain authorization codes or tokens. PKCE makes a logged code less useful, but it does not remove the record. Configure access logs to omit the callback query string, restrict who can read log storage, and keep token values out of debug output. Ask your logging team to confirm retention for these logs against your policy.

What buyers ask before enabling PKCE for Superset

Is PKCE still needed if our OAuth client already has a client secret?

Yes, it is recommended. A client secret proves the client's identity to the identity provider, but it does not protect the authorization code while it travels through the browser and redirects. PKCE binds the code to a value only the Superset login process knows, so a stolen code cannot be exchanged on its own. Keep the secret and add PKCE on top of it, then confirm with your identity provider's documentation that the setting is enabled for the specific client. Whether a given provider enforces PKCE for confidential clients varies, so check the client configuration rather than assuming it.

What drives the effort of enabling PKCE on Superset?

The work is usually small in code and larger in verification. The main drivers are the identity provider type, since each product exposes PKCE settings in a different place, the number of environments that must match, and how much group mapping has to be re-tested after login changes. A single production client with one provider is a narrow job. Several environments, multiple providers or custom OAuth servers add configuration and test passes. Ask any partner to break the quote down by provider, environment and test cases, and to state which upgrade checks are included.

What does our team need to provide for the PKCE change?

Plan for four inputs before work starts. You need administrator access to the identity provider so the client can be changed and test users can be created. You need a staging Superset that matches production's authentication settings. You need test accounts covering each role and group that Superset maps at login. You also need a named owner who can approve changes to the client and the AUTH_ROLES_MAPPING configuration. Without these, verification stalls, and the change is often delayed rather than delivered.

Can our own team enable PKCE without outside help?

Often yes, if your team already operates the identity provider and Superset's configuration. The change is a client setting plus a provider configuration block in superset_config.py, and the Superset configuration documentation describes the OAuth provider setup. The harder part is testing: confirming login succeeds in every environment, roles map correctly, and a failed flow fails safely. Teams without a staging environment or without someone who has reviewed authentication logs before should weigh that gap in the decision. A written scope lets you compare doing it in-house with a partner.

How can Superset or Flask-AppBuilder upgrades affect the PKCE setting?

Upgrades can change how the OAuth configuration is read, so the PKCE setting should be part of every upgrade test. Superset is built on Flask-AppBuilder, and a version change in either can affect the login path. Follow the upgrade guide: back up the metadata database, run the upgrade steps, test in staging first, and check UPDATING.md for breaking changes between versions. Record the authentication test cases so they can be repeated after each upgrade and each identity provider change.

What should a written quote for PKCE include?

A useful quote lists the identity provider and Superset version in scope, each environment to be changed, the client settings to be updated, and the configuration changes to superset_config.py. It should name the test cases: successful login, denied login for users outside the allowed group, role mapping checks and a failed flow. It should state what you must provide, what is one-time work and what recurs, such as retesting after upgrades. Ask how rollback works and who approves the change. DeployOpen does not publish prices, so a quote follows from this written scope.

Does enabling PKCE change how users sign in?

Normally no, and users should see the same login screen and redirects. The change affects what happens in the background during the code exchange. However, it can break logins if the client is not configured to match Superset, or if a redirect URI differs between environments. For that reason, test with real test accounts in staging before production, and plan a short window to observe logins after the change. Keep a break-glass administrator path that does not depend on the new flow.

Limits and what to confirm in your environment

PKCE behavior depends on the Superset release, the Flask-AppBuilder and OAuth library versions, the identity provider's client settings, and how Superset is deployed. Each card below is a check to complete with the vendor or in your own test environment before the flow reaches users.

Confirm your Superset and Flask-AppBuilder versions

Superset is built on Flask-AppBuilder, so the OAuth code path you test depends on both versions. Apache Superset 6.1.0 was published on May 13, 2026, and 7.0.0rc2 is only a pre-release. Record the exact Superset version your image runs, along with the Flask-AppBuilder version it pins, and repeat the PKCE test after any upgrade. Do not assume behavior from the documentation of a different release.

Verify PKCE support for your client type

Confirm that the OAuth library and the identity provider both support PKCE for the client type you register. A public client, such as a single-page or native app, needs PKCE because it cannot keep a secret. A confidential server-side client may still use a secret plus PKCE. Check the library's documented code_challenge_method handling, and test that the IdP rejects an authorization request whose verifier does not match.

Check the provider block parameters

Confirm that the OAuth provider block in your superset_config.py accepts the parameters your flow needs, such as the code challenge settings and the scopes required for group claims. Do not rely on a configuration key from a blog post or an older release. Read the configuration documentation for your version, then verify the resulting authorization URL in a browser or with a request capture.

Test the Kubernetes deployment path

If you run Superset on Kubernetes, check how your install is managed before changing login settings. The current development docs mark the official Helm chart as deprecated and point new deployments to the Kubernetes Operator, which is in alpha with a v1alpha1 API that may change between releases. Confirm which tool owns your configuration, where secrets are injected, and whether a chart or operator upgrade would overwrite the OAuth settings.

Confirm the IdP enforces PKCE for all clients

Ask your identity provider whether PKCE is required for every client in the tenant or only where each application enables it. A permissive setting lets an application register without a challenge, which weakens protection for any client that is later added. Record the vendor's answer and the setting name, then test a deliberately incorrect verifier in staging to confirm the rejection behavior.

How DeployOpen scopes and delivers PKCE hardening for Superset

DeployOpen approaches OAuth hardening for Superset as a scoped engagement inside your own infrastructure, covering the identity provider configuration, the Superset OAuth provider block and the test evidence your team needs. Engagements are fixed-scope, with scope, deliverables and timelines agreed in writing before work starts.

How we scope

  • Inventory which Superset OAuth providers exist and whether each one is a public or confidential client.
  • Confirm the identity provider product, version and the OAuth flows currently enabled for Superset sign-in.
  • Write the scope in advance, listing the PKCE configuration, test cases, documentation and handover items agreed with you.

How we build

  • Configure the identity provider client so it requires PKCE with the S256 challenge method, and confirm this in its settings.
  • Update the Superset OAuth provider configuration in your deployment so the login flow matches the identity provider settings.
  • Keep client secrets, redirect URIs and callback paths under your change control, with each change tracked in version control.

How we hand over

  • Test the full login flow in a staging environment, including failed code exchanges, redirect mismatches and expired authorization attempts.
  • Document the identity provider settings, Superset configuration keys and the test results so your team can repeat the checks.
  • Walk your security and platform engineers through the configuration and the rollback steps before changes reach production.

How we support

  • Ongoing support, upgrades and continuous testing are available as retainers for Superset and its identity integrations.
  • Re-test the OAuth flow after Superset upgrades, since release notes and UPDATING.md may change authentication behavior.
  • Ask any provider for a quote based on your written scope, with recurring retainer work listed separately from the one-time build.

Sources and further reading

Talk to our team.

Tell us what you're working on, whether it's a deployment, an audit, a security test or a cyber range. You'll speak with an engineer who can help you scope it.

  • 30-minute call: free, with no obligation.
  • NDA on request: we can sign before you share details.
  • Clear next steps: a scope and plan after the call.