Documentssuperset
Flask-AppBuilder Authentication
Flask-AppBuilder Authentication
Type
Topic
Status
Published
Created
Jul 17, 2026
Updated
Jul 17, 2026

Flask-AppBuilder Authentication in Apache Superset#

Superset does not implement its own login/credential-verification logic. Instead, all core authentication — validating passwords, binding to LDAP, handling OAuth/SAML redirects — is delegated to Flask-AppBuilder (FAB), which ships its own SecurityManager, auth views, and login forms. Superset extends FAB through SupersetSecurityManager and a thin SupersetAuthView, leaving most auth behavior in FAB's code.

Architecture#

Browser
  │ POST /login/
SupersetAuthView (superset/views/auth.py)
  │ ↳ extends FAB's AuthView → renders React app template
  ▼ form submission handled by FAB's AuthDBView / AuthLDAPView / AuthOAuthView / ...
  │ calls sm.auth_user_db() / sm.auth_user_ldap() / sm.auth_user_oauth()
  │ on failure → flash(invalid_login_message, "warning")
SupersetSecurityManager (superset/security/manager.py)
  │ ↳ extends FAB's SecurityManager (flask_appbuilder.security.sqla.manager)
  │ inherits all credential-checking methods
Flask-Login session created; Superset RBAC checks applied on every request

Key Files#

FileRole
superset/security/manager.pySupersetSecurityManager — extends FAB's SecurityManager; owns RBAC, permissions, guest tokens
superset/views/auth.pySupersetAuthView (/login) — minimal shim that renders the React template; SupersetRegisterUserView for email-activation flow
superset/initialization/__init__.pyWires CUSTOM_SECURITY_MANAGER into FAB's appbuilder
flask_appbuilder/security/views.pyFAB's AuthView, AuthDBView, AuthLDAPView, etc. — actual login form handling
flask_appbuilder/security/manager.pyFAB's BaseSecurityManagerauth_user_db(), auth_user_ldap(), update_user_auth_stat()

Authentication Flow and Error Messages#

Login Flow#

SupersetAuthView handles GET /login/: if the user is already authenticated it redirects to the index; otherwise it renders the React app template. The actual form submission is handled by FAB's AuthDBView.login() or AuthLDAPView.login() (depending on AUTH_TYPE), which call sm.auth_user_db(username, password) or sm.auth_user_ldap(username, password) respectively (see FAB's views.py).

Where "Invalid login. Please try again." Comes From#

The error message displayed on failed login does not exist in Superset's codebase. It originates in FAB's AuthView base class:

# flask_appbuilder/security/views.py
class AuthView(BaseView):
    invalid_login_message = lazy_gettext("Invalid login. Please try again.")

When auth_user_db() returns None (wrong password, unknown user, or inactive user), AuthDBView and AuthLDAPView call flash(as_unicode(self.invalid_login_message), "warning") and redirect back to the login page . The server-side log message is LOGMSG_WAR_SEC_LOGIN_FAILED = "Login Failed for user: %s" written at INFO level, also from FAB's constants.

auth_user_db() Behavior (in FAB)#

FAB's BaseSecurityManager.auth_user_db() (see FAB's manager.py):

  • Returns None (triggers the flash error) when: user not found by username or email, or user.is_active == False.
  • Performs a fake check_password_hash even on missing users (constant-time defense against user enumeration).
  • On success: calls update_user_auth_stat(user, success=True) — increments login_count, resets fail_login_count.
  • On wrong password: calls update_user_auth_stat(user, success=False) — increments fail_login_count.

Misleading "Invalid Login" in Non-Login Contexts#

The same FAB-originated message can appear in unexpected contexts, e.g., in SQL Lab when Celery workers cannot authenticate to the Superset metadata database (not the target database). If the Superset web pod and worker pod use different SQLALCHEMY_DATABASE_URI or SECRET_KEY values, the worker's session decryption fails, FAB surfaces this as an authentication failure, and the same "Invalid login" flash message appears . Check environment consistency across pods before assuming a user credential problem.

SupersetSecurityManager: What It Owns vs. What FAB Owns#

SupersetSecurityManager extends flask_appbuilder.security.sqla.manager.SecurityManager. The split:

FAB owns (inherited, not overridden by Superset):

  • Credential verification: auth_user_db(), auth_user_ldap(), auth_user_oauth(), auth_user_saml()
  • Login form views: AuthDBView, AuthLDAPView, AuthOAuthView, AuthSAMLView
  • User model CRUD, password hashing (werkzeug.security.generate_password_hash)
  • LoginManager (Flask-Login) setup and user_loader
  • Auth error message string: "Invalid login. Please try again."
  • Rate limiting (AUTH_RATE_LIMITED, AUTH_RATE_LIMIT)

Superset owns (defined or overridden in SupersetSecurityManager):

  • create_login_manager() — adds a custom request_loader for embedded guest tokens
  • get_guest_user_from_request() / create_guest_access_token() / parse_jwt_guest_token() — guest (embedded) JWT auth
  • raise_for_access() — fine-grained RBAC checks on dashboards, datasources, charts, SQL tables
  • Permission lifecycle hooks: database_after_insert/delete/update, dataset_after_insert/delete/update (SQLAlchemy event listeners)
  • Role sync: sync_role_definitions() — creates Admin/Alpha/Gamma/sql_lab roles and syncs custom permissions
  • register_views() — overrides FAB to swap in SupersetAuthView and SupersetRegisterUserView, and trims FAB's security menu items

Configuration Reference#

All auth config keys are FAB conventions, set in superset/config.py:

KeyDefaultDescription
AUTH_TYPEAUTH_DBAuth backend: AUTH_DB, AUTH_LDAP, AUTH_OAUTH, AUTH_REMOTE_USER, AUTH_SAML
AUTH_ROLE_ADMIN"Admin"Role name for admins
AUTH_ROLE_PUBLIC"Public"Role for unauthenticated access
AUTH_USER_REGISTRATIONFalseEnable self-registration
AUTH_USER_REGISTRATION_ROLEpublic roleDefault role for self-registered users
AUTH_ROLES_MAPPING{}Map LDAP/OAuth group keys → FAB role names
AUTH_ROLES_SYNC_AT_LOGINFalseRe-sync roles from IdP on every login
AUTH_RATE_LIMITEDFalseEnable FAB's built-in rate limiting on login
AUTH_RATE_LIMIT"10 per 20 second"Rate limit expression when enabled
CUSTOM_SECURITY_MANAGERNoneOverride with a subclass of SupersetSecurityManager

CUSTOM_SECURITY_MANAGER is validated at startup: the custom class must extend SupersetSecurityManager (not raw FAB's manager), or app init raises an exception . This is the correct extension point for overriding auth behavior (e.g., adding custom auth_user_db logic, overriding FAB API views for permission filtering ).

Common Debugging Scenarios#

"Invalid login. Please try again." on correct credentials

  • Check ab_user.active column in the metadata DB — FAB rejects inactive users with the same message.
  • In Kubernetes deployments, verify that SQLALCHEMY_DATABASE_URI and SECRET_KEY are identical across web and Celery worker pods. Mismatches cause workers to fail session decryption, which FAB surfaces as an auth error .

Error doesn't appear in Superset source — where is it?

  • Search flask_appbuilder/security/views.py (FAB's invalid_login_message) and flask_appbuilder/security/manager.py (auth_user_db, auth_user_ldap). These files live in the flask-appbuilder pip package, not in the Superset repo .

JWT Bearer tokens returning empty results from APIs

  • FAB's before_request hook may reset g.user after JWT middleware sets it. Workaround: use a FLASK_APP_MUTATOR before_request hook to explicitly set g.user from the decoded token before FAB's hook runs .

SSO / OAuth session not re-evaluated after external logout

  • Superset has no built-in mechanism to detect external IdP logouts. Session persistence is managed entirely by Flask-Login (FAB's create_login_manager), so an active Superset cookie will remain valid until it expires or is explicitly invalidated .

Customizing auth behavior

  • Subclass SupersetSecurityManager, override the target method (e.g., auth_user_db, or a FAB API view class attribute like permission_view_menu_api), and set CUSTOM_SECURITY_MANAGER in your config .
Flask-AppBuilder Authentication | Dosu