-
Notifications
You must be signed in to change notification settings - Fork 16.7k
Description
Motivation
Apache Superset currently lacks essential, modern password management capabilities when AUTH_TYPE = AUTH_DB is configured. The existing user experience is fragmented, insecure in certain areas, and heavily reliant on server-side CLI access for basic account recovery operations. This creates a significant operational burden for administrators and a frustrating experience for end users.
Current state of affairs:
-
Authenticated password change — A logged-in user can change their own password via Profile → Change Password, but the form does not require the current password, making it vulnerable to session hijacking attacks. This was reported in [Issue #37700](Reset My Password and Reset Password views are still accessible in Superset 6.0.0 after the major frontend porting. #37700) and partially addressed by [PR #37773](fix(auth): gate legacy FAB password reset routes behind config flag #37773) which gates legacy FAB routes behind a config flag, but the underlying UX and security gaps remain.
-
Forgotten password (self-service reset) — There is no "Forgot Password" flow out of the box. When a user loses access to their account, the only remediation paths are:
- An administrator runs
superset fab reset-password --username <user> --password <new_password>on the server (requires shell access). - The administrator deactivates the user and recreates the account, losing ownership references and audit history.
- Direct SQL manipulation of the
ab_usertable (highly discouraged).
This gap has been a recurring community request since at least 2017 ([Issue #2731](Give users the rights to change their password #2731)), with dedicated discussions ([#18427](Forgot Password feature #18427), [#34241](🔐 Forgot Password Feature – Superset #34241)) and feature requests ([#19498](Need a way to change a forgotten password #19498), [#36223](Admin UI: allow administrators to change/reset another user's password #36223)).
- An administrator runs
-
Admin-initiated password reset via UI — Administrators cannot reset another user's password from the web interface. [PR #36764](feat(dashboard): add password change functionality in user management #36764) adds password change functionality to the user management modal, but a holistic approach covering security policies, audit logging, and session invalidation is still missing.
-
Email change — There is no CLI or UI mechanism to update a user's email address. If a user loses access to their email, the administrator has no supported path to update it without direct database edits.
-
Critical operational scenarios — In on-premise and self-hosted deployments, three scenarios cause the most pain:
- Total admin lockout — If the sole admin forgets their password and has no shell access, recovery is extremely difficult.
- Missing automated deprovisioning — No built-in mechanism to disable or expire stale accounts.
- Ungoverned server access — CLI password resets require direct server access, which may not be available to the logical "Superset admin" in many organizations.
This SIP proposes a unified, security-conscious overhaul of password and credential management in Superset, scoped exclusively to AUTH_TYPE = AUTH_DB deployments.
Proposed Change
The proposal is organized into four pillars, each addressing a distinct area of the password lifecycle.
Pillar 1 — Secure Authenticated Password Change
When a logged-in user changes their own password:
- Require current password — The change password form must prompt for the existing password before accepting a new one. This prevents unauthorized password changes in case of session hijacking.
- Password policy enforcement — Introduce configurable validation rules via
superset_config.py:PASSWORD_MIN_LENGTH(default: 12)PASSWORD_REQUIRE_UPPERCASE(default:True)PASSWORD_REQUIRE_LOWERCASE(default:True)PASSWORD_REQUIRE_DIGIT(default:True)PASSWORD_REQUIRE_SPECIAL(default:True)PASSWORD_COMMON_LIST_CHECK(default:True) — reject passwords from a known common-passwords list
- Session invalidation — After a successful password change, all existing sessions for the user must be invalidated. The session cookie is regenerated, and any persistent tokens are revoked. This mitigates session hijacking.
- Hashing — Passwords are hashed using
bcrypt(orargon2as a configurable alternative). Passwords must never be stored in plaintext or logged. - Audit logging — Every password change event is recorded with timestamp, user ID, source IP, and whether it was self-initiated or admin-initiated.
Frontend changes: Migrate the password change form from the legacy FAB SSR view to a React SPA component consistent with the post-6.0.0 architecture. The new form includes fields for current password, new password, and password confirmation with real-time client-side validation feedback.
Pillar 2 — Self-Service Forgotten Password Reset (Email-Based)
A new "Forgot Password" flow accessible from the login page:
User clicks "Forgot Password" on login page
↓
User enters their email address
↓
System generates a cryptographically secure, single-use token
↓
Email sent via configured SMTP with an HTTPS reset link
↓
Token has a configurable expiry (default: 30 minutes, range: 15–60 min)
↓
User clicks link → lands on password reset page
↓
User enters new password (subject to password policy)
↓
Token is invalidated immediately after use
↓
All existing sessions invalidated
↓
User is redirected to login page
Security requirements:
- Tokens must be cryptographically random (at least 256 bits of entropy, e.g.
secrets.token_urlsafe(48)). - Tokens are single-use and invalidated on consumption or expiry.
- The system must not reveal whether an email address exists in the database. Regardless of whether the email is found, the user sees the same confirmation message: "If an account with that email exists, a reset link has been sent."
- Rate limiting on the reset endpoint: configurable via
PASSWORD_RESET_RATE_LIMIT(default: 5 requests per 15 minutes per IP). - The reset link must use HTTPS in production environments. The URL scheme is derived from the incoming request (honoring X-Forwarded-Proto) or from an explicit configuration override (e.g., PASSWORD_RESET_BASE_URL). In local development over plaintext HTTP, the link will use http:// accordingly. A startup warning is logged when PASSWORD_RESET_ENABLED = True and the detected scheme is not HTTPS.
- Token storage in the database uses hashed values (never store the raw token).
Configuration:
# superset_config.py
PASSWORD_RESET_ENABLED = True # default: False (opt-in)
PASSWORD_RESET_TOKEN_EXPIRY_MINUTES = 30
PASSWORD_RESET_RATE_LIMIT = "5 per 15 minutes"Prerequisite: A working SMTP configuration (EMAIL_NOTIFICATIONS = True with valid SMTP_* settings). When SMTP is not configured and PASSWORD_RESET_ENABLED = True, Superset should log a warning at startup.
Pillar 3 — Admin-Initiated Password Reset and Email Change (UI + CLI)
Web UI — Admin password reset:
In Security → List Users, administrators (users with the Admin role) can trigger a password reset for any user. Two modes are supported:
- Set password directly — Admin enters a new password for the user via a modal dialog. The user's existing sessions are invalidated. Whether this mode should be supported is open for discussion: while it offers a quick recovery path (especially when SMTP is unavailable), it means the admin has momentary knowledge of the user's password, which conflicts with zero-knowledge security principles. Community input on whether to include, exclude, or gate this behind a separate config flag (e.g.,
ADMIN_DIRECT_PASSWORD_SET = False) is welcome. - Send reset link — Admin triggers a reset email to the user's registered email (requires SMTP). This is the preferred approach as the admin never sees the new password.
Both actions are gated behind the existing can_write permission on the User resource and are recorded in the audit log.
CLI — Password reset (existing):
The existing superset fab reset-password command is preserved and documented:
superset fab reset-password --username <username> --password <new_password>CLI — Email change (new):
A new CLI command to update a user's email address:
superset change-email --username <username> --new-email <new_email>This command:
- Validates email format.
- Checks for uniqueness against existing users.
- Updates the
ab_user.emailfield. - Logs the change in the audit log.
- Is only available when
AUTH_TYPE = AUTH_DB.
This addresses the scenario where a user loses access to their email and cannot use the self-service reset flow.
CLI — Account deactivation (new):
superset deactivate-user --username <username>Deactivates the user (active = False), invalidates all sessions, and logs the event.
Pillar 4 — Security Hardening and Operational Safety
Login rate limiting and account lockout:
LOGIN_RATE_LIMIT— Configurable rate limit on the login endpoint (default: 10 attempts per 5 minutes per IP).LOGIN_MAX_FAILURES— After N consecutive failed login attempts for a given username, the account is temporarily locked (default: 5 failures → 15 minute lockout).- Lockout events are logged and optionally trigger an email notification to the user.
Audit logging:
All authentication-related events are logged to a new auth_audit_log table:
- Successful and failed logins (with IP and user-agent)
- Password changes (self and admin-initiated)
- Password resets (request and completion)
- Email changes
- Account lockouts and unlocks
- Account activations and deactivations
Session management hardening:
After any password or credential change:
- Invalidate all existing
sessionrecords for the user. - Regenerate the session ID for the current session.
- Revoke any persistent or remember-me tokens.
Future Considerations (Out of Scope for This SIP)
The following topics are acknowledged as important but are intentionally excluded from this SIP to keep scope manageable. They may be addressed in subsequent SIPs:
- Multi-Factor Authentication (MFA) — Strongly recommended for production deployments. Could be introduced via TOTP (e.g.
pyotp) as a follow-up. - Password expiration policies — Configurable password rotation (e.g. every 90 days). Depends on organizational policy and is controversial in modern security guidance (NIST SP 800-63B discourages mandatory rotation).
- OIDC / SAML integration improvements — When
AUTH_TYPEis set toAUTH_OID,AUTH_OAUTH, orAUTH_REMOTE_USER, password management is delegated to the identity provider. This SIP does not modify those flows. However, a future SIP could improve the OIDC onboarding experience and documentation. - WebAuthn / Passkeys — Modern passwordless authentication. Requires significant frontend and backend work.
New or Changed Public Interfaces
REST API — New endpoints:
| Method | Endpoint | Description |
|---|---|---|
PUT |
/api/v1/me/password |
Authenticated user changes own password (requires current password) |
POST |
/api/v1/auth/forgot-password |
Request a password reset email (unauthenticated) |
POST |
/api/v1/auth/reset-password |
Complete password reset with token (unauthenticated) |
PUT |
/api/v1/user/{id}/password |
Admin resets a user's password (Admin role required) |
POST |
/api/v1/user/{id}/send-reset-link |
Admin triggers a reset email for a user (Admin role required) |
REST API — Modified endpoints:
| Method | Endpoint | Change |
|---|---|---|
PUT |
/api/v1/user/{id} |
Email field becomes updatable by Admin role |
CLI — New commands:
| Command | Description |
|---|---|
superset change-email --username <user> --new-email <email> |
Update a user's email address |
superset deactivate-user --username <user> |
Deactivate a user account |
CLI — Existing commands (unchanged):
| Command | Description |
|---|---|
superset fab reset-password --username <user> --password <pw> |
Reset password from CLI (already exists) |
superset fab create-admin |
Create admin user (already exists) |
Frontend — React components:
- New
ChangePasswordModalcomponent (replaces legacy FAB SSR view) - New
ForgotPasswordPagecomponent (login page addition) - New
ResetPasswordPagecomponent (token-based reset) - Modified
UserListModalto include admin password reset action - Password strength indicator component with real-time policy feedback
Configuration — New superset_config.py keys:
# Password policy
PASSWORD_MIN_LENGTH = 12
PASSWORD_REQUIRE_UPPERCASE = True
PASSWORD_REQUIRE_LOWERCASE = True
PASSWORD_REQUIRE_DIGIT = True
PASSWORD_REQUIRE_SPECIAL = True
PASSWORD_COMMON_LIST_CHECK = True
# Self-service reset
PASSWORD_RESET_ENABLED = False
PASSWORD_RESET_TOKEN_EXPIRY_MINUTES = 30
PASSWORD_RESET_RATE_LIMIT = "5 per 15 minutes"
# Login security
LOGIN_RATE_LIMIT = "10 per 5 minutes"
LOGIN_MAX_FAILURES = 5
LOGIN_LOCKOUT_DURATION_MINUTES = 15Important: All features in this SIP apply exclusively when AUTH_TYPE = AUTH_DB. When external authentication providers are configured (OAuth, LDAP, REMOTE_USER), the password-related endpoints and UI elements are hidden.
New Dependencies
| Package | Purpose | License | Maintained |
|---|---|---|---|
flask-limiter |
Rate limiting for login and reset endpoints | MIT | Yes (active) |
argon2-cffi (optional) |
Alternative password hashing to bcrypt | MIT | Yes (active) |
No new npm dependencies are anticipated. The frontend components will use existing Ant Design form components and Superset's design system.
Note: bcrypt is already a transitive dependency via Flask-AppBuilder. flask-limiter may already be available depending on the deployment; if not, it is lightweight and actively maintained.
Migration Plan and Compatibility
Database migrations:
-
New table
password_reset_token:id(PK)user_id(FK →ab_user.id)token_hash(VARCHAR, indexed)created_at(TIMESTAMP)expires_at(TIMESTAMP)used_at(TIMESTAMP, nullable)
-
New table
auth_audit_log:id(PK)user_id(FK →ab_user.id, nullable for failed logins with unknown user)event_type(VARCHAR — e.g.login_success,login_failure,password_change,password_reset_request,password_reset_complete,email_change,account_lockout,account_deactivated)ip_address(VARCHAR)user_agent(TEXT)metadata(JSON, nullable — additional context)created_at(TIMESTAMP)
-
New table
account_lockout:id(PK)user_id(FK →ab_user.id)failed_attempts(INTEGER)locked_until(TIMESTAMP, nullable)last_failed_at(TIMESTAMP)
Note: on FAB schema ownership: The ab_* tables (e.g., ab_user, ab_role, ab_permission_view) are owned and managed by Flask-AppBuilder's own migration chain. Adding custom columns to these tables introduces a maintenance risk: FAB upstream may alter the same tables in future releases, causing Alembic migration conflicts, failed upgrades, or silent schema drift. To preserve clean upgrade paths and avoid coupling Superset's auth enhancements to FAB's release cycle, this SIP introduces new, Superset-managed tables (password_reset_token, auth_audit_log, account_lockout) that reference ab_user.id via foreign key without modifying the upstream schema. This approach also simplifies a potential future migration away from FAB's built-in user model.
Backward compatibility:
- All new features are opt-in via configuration flags. Existing deployments are unaffected by default.
- The existing
superset fab reset-passwordCLI command remains unchanged. - The legacy FAB password change view is deprecated in favor of the new SPA-based component. During a transition period, the legacy route can be re-enabled via the config flag introduced in [PR #37773](fix(auth): gate legacy FAB password reset routes behind config flag #37773).
- No breaking changes to existing stored URLs or bookmarks.
Rollout strategy:
- Phase 1: Secure authenticated password change (Pillar 1) + audit logging foundation
- Phase 2: Self-service forgot password flow (Pillar 2) + CLI email change
- Phase 3: Admin UI password reset (Pillar 3)
- Phase 4: Rate limiting and lockout (Pillar 4)
Rejected Alternatives
-
Relying entirely on Flask-AppBuilder upstream — A PR ([dpgaspar/Flask-AppBuilder#1566](feat: Reset password email and 'Forgot password' solution dpgaspar/Flask-AppBuilder#1566)) was opened to add forgot-password to FAB itself, but has been stalled for years with no progress. Waiting for upstream is not viable given the community demand and the Superset project's migration to SPA architecture.
-
Requiring all deployments to use OIDC/SAML — While external identity providers solve password management entirely, many small-to-medium deployments and development environments rely on
AUTH_DB. Forcing migration to an external IdP would be a significant barrier to adoption. -
Direct database SQL for password resets — Some community workarounds suggest running
UPDATE ab_user SET password = '...'directly. This is fragile, error-prone, bypasses all security controls, and should never be recommended as a supported workflow. -
Admin-only password resets (no self-service) — While simpler to implement, this still requires admin intervention for every forgotten password and does not scale for larger deployments. The self-service flow (Pillar 2) is essential for operational efficiency.
-
Implementing a full identity management system — Building user lifecycle management, SSO, and identity federation within Superset itself would be overengineering. This SIP scopes the work to the minimum necessary for secure password management when using database authentication, while acknowledging that organizations with advanced requirements should use external identity providers.