Stitchflow
Apache Superset logo

Apache Superset User Management API Guide

API workflow

How to automate user lifecycle operations through APIs with caveats that matter in production.

UpdatedFeb 26, 2026

Summary and recommendation

Apache Superset exposes a FAB-based REST API at /api/v1 authenticated via JWT Bearer tokens obtained from POST /api/v1/security/login (provider='db' only; OAuth/LDAP users cannot use this endpoint without a separate local admin account).

The user CRUD Security API (/api/v1/security/users/*) is disabled by default and requires FAB_ADD_SECURITY_API=True in superset_config.py - without this flag, all security CRUD endpoints return 404 and are absent from Swagger. The API is explicitly marked beta in FAB documentation, meaning breaking changes are expected across minor Superset versions.

There is no native SCIM 2.0 endpoint and no webhook system for user lifecycle events. For teams needing automated provisioning across a broad identity surface, Stitchflow's MCP server with ~100 deep IT/identity integrations provides a more stable abstraction layer than building directly against Superset's beta Security API.

API quick reference

Has user APIYes
Auth methodJWT Bearer token (FAB-issued). Obtain via POST /api/v1/security/login with username, password, and provider. Pass as Authorization: Bearer <token> header on all subsequent requests. CSRF token required for state-mutating calls when using session cookies.
Base URLOfficial docs
SCIM availableNo
SCIM plan requiredNot available in open-source Apache Superset. Preset (managed commercial offering) may provide easier IdP integration but does not advertise a native SCIM 2.0 endpoint.

Authentication

Auth method: JWT Bearer token (FAB-issued). Obtain via POST /api/v1/security/login with username, password, and provider. Pass as Authorization: Bearer header on all subsequent requests. CSRF token required for state-mutating calls when using session cookies.

Setup steps

  1. Ensure Superset is running and an admin account exists (created via superset fab create-admin or docker-init).
  2. POST to /api/v1/security/login with JSON body {"username":"admin","password":"","provider":"db","refresh":true} to receive access_token and refresh_token.
  3. Include Authorization: Bearer header on all API requests.
  4. For state-mutating endpoints (POST/PUT/DELETE) when using session-cookie auth, also fetch a CSRF token via GET /api/v1/security/csrf_token/ and include it as X-CSRFToken header.
  5. To enable the user CRUD Security API (beta), add FAB_ADD_SECURITY_API = True to superset_config.py and restart Superset. Security endpoints then appear in Swagger at /swagger/v1.
  6. If using OAuth2/LDAP for UI login, a separate local admin account with AUTH_TYPE=AUTH_DB can still authenticate against /api/v1/security/login using provider='db' for API access.

Required scopes

Scope Description Required for
Admin role (FAB) Superset uses role-based permissions managed by Flask-AppBuilder, not OAuth scopes. The calling user must hold the Admin role to perform user CRUD operations via the Security API. All /api/v1/security/users/* operations (create, read, update, delete)
can_list on UserDBModelView FAB permission auto-generated for listing users. Assigned to Admin role by default. GET /api/v1/security/users/
can_add on UserDBModelView FAB permission auto-generated for creating users. Assigned to Admin role by default. POST /api/v1/security/users/
can_edit on UserDBModelView FAB permission auto-generated for editing users. Assigned to Admin role by default. PUT /api/v1/security/users/{pk}
can_delete on UserDBModelView FAB permission auto-generated for deleting users. Assigned to Admin role by default. DELETE /api/v1/security/users/{pk}

User object / data model

Field Type Description On create On update Notes
id integer Auto-incremented primary key for the user record. auto-assigned immutable Used as {pk} in single-user endpoints.
username string Unique login identifier for the user. required optional Must be unique across the instance.
first_name string User's first name. required optional Mapped from given_name in OAuth flows.
last_name string User's last name. required optional Mapped from family_name in OAuth flows.
email string User's email address. Must be unique. required optional Used as identity in LDAP/OAuth auto-registration.
password string (write-only) Plaintext password on create/update; stored as hashed value (scrypt by default). required for AUTH_DB users optional Not returned in GET responses. Not applicable for LDAP/OAuth users.
active boolean Whether the user account is active and can log in. optional (defaults to true) optional Set to false to disable login without deleting the account.
roles array of role objects [{id, name}] List of FAB roles assigned to the user (e.g., Admin, Alpha, Gamma, Public, sql_lab). optional (defaults to AUTH_USER_REGISTRATION_ROLE if set) optional Do not alter built-in roles directly; create custom roles instead. Role IDs can be fetched from GET /api/v1/security/roles/.
login_count integer Number of successful logins. auto (0) system-managed Read-only; updated by FAB on each successful authentication.
last_login datetime (ISO 8601) Timestamp of the user's most recent login. null system-managed Read-only.
created_on datetime (ISO 8601) Timestamp when the user record was created. auto immutable Read-only.
changed_on datetime (ISO 8601) Timestamp of the last modification to the user record. auto auto Read-only; updated on any PUT.

Core endpoints

Obtain JWT access token

  • Method: POST
  • URL: /api/v1/security/login
  • Watch out for: provider must be 'db' for local accounts. OAuth-authenticated users cannot obtain a JWT via this endpoint without a local fallback admin account.

Request example

POST /api/v1/security/login
Content-Type: application/json

{"username":"admin","password":"admin",
 "provider":"db","refresh":true}

Response example

{
  "access_token": "eyJ...",
  "refresh_token": "eyJ..."
}

Get CSRF token (required for mutating calls with session auth)

  • Method: GET
  • URL: /api/v1/security/csrf_token/
  • Watch out for: Required as X-CSRFToken header on POST/PUT/DELETE when WTF_CSRF_ENABLED=True (default). Not needed when using pure Bearer token auth with WTF_CSRF_ENABLED=False.

Request example

GET /api/v1/security/csrf_token/
Authorization: Bearer <access_token>

Response example

{
  "result": "<csrf_token_string>"
}

List users (requires FAB_ADD_SECURITY_API=True)

  • Method: GET
  • URL: /api/v1/security/users/
  • Watch out for: Returns 403 if FAB_ADD_SECURITY_API is not set to True. Pagination params must be inside the Rison q parameter, not bare query params.

Request example

GET /api/v1/security/users/?q=(page:0,page_size:25)
Authorization: Bearer <access_token>

Response example

{
  "count": 42,
  "result": [
    {"id":1,"username":"admin",
     "first_name":"Admin","last_name":"User",
     "email":"admin@example.com","active":true,
     "roles":[{"id":1,"name":"Admin"}]}
  ]
}

Get single user by ID (requires FAB_ADD_SECURITY_API=True)

  • Method: GET
  • URL: /api/v1/security/users/{pk}
  • Watch out for: pk is the integer user ID, not username. Requires Admin role on the calling user.

Request example

GET /api/v1/security/users/5
Authorization: Bearer <access_token>

Response example

{
  "id": 5,
  "result": {
    "username": "jdoe",
    "first_name": "Jane",
    "last_name": "Doe",
    "email": "jdoe@example.com",
    "active": true,
    "roles": [{"id":2,"name":"Alpha"}]
  }
}

Create user (requires FAB_ADD_SECURITY_API=True)

  • Method: POST
  • URL: /api/v1/security/users/
  • Watch out for: Beta endpoint - breaking changes possible across Superset versions. Role IDs must be fetched first from GET /api/v1/security/roles/. Password field only applies to AUTH_DB users.

Request example

POST /api/v1/security/users/
Authorization: Bearer <access_token>
Content-Type: application/json

{"username":"jdoe","first_name":"Jane",
 "last_name":"Doe","email":"jdoe@example.com",
 "password":"SecurePass1!","active":true,
 "roles":[{"id":2}]}

Response example

{
  "id": 12,
  "result": {
    "username": "jdoe",
    "email": "jdoe@example.com",
    "active": true
  }
}

Update user (requires FAB_ADD_SECURITY_API=True)

  • Method: PUT
  • URL: /api/v1/security/users/{pk}
  • Watch out for: Full PUT replaces the resource; omitting roles will clear them. Use only fields you intend to change and include all required fields.

Request example

PUT /api/v1/security/users/12
Authorization: Bearer <access_token>
Content-Type: application/json

{"active":false,"roles":[{"id":3}]}

Response example

{
  "id": 12,
  "result": {
    "active": false,
    "roles": [{"id":3,"name":"Gamma"}]
  }
}

Delete user (requires FAB_ADD_SECURITY_API=True)

  • Method: DELETE
  • URL: /api/v1/security/users/{pk}
  • Watch out for: Permanently deletes the user record. No soft-delete. Consider setting active=false instead for reversible deactivation.

Request example

DELETE /api/v1/security/users/12
Authorization: Bearer <access_token>

Response example

{
  "message": "OK"
}

Get current authenticated user info (always available, no flag needed)

  • Method: GET
  • URL: /api/v1/me/
  • Watch out for: This endpoint is part of the public API (no FAB_ADD_SECURITY_API flag required). Returns info for the token owner only.

Request example

GET /api/v1/me/
Authorization: Bearer <access_token>

Response example

{
  "result": {
    "username": "admin",
    "first_name": "Admin",
    "last_name": "User",
    "email": "admin@example.com",
    "roles": [{"name":"Admin"}]
  }
}

Rate limits, pagination, and events

  • Rate limits: Apache Superset (self-hosted, open source) does not enforce built-in API rate limits by default. Rate limiting is the operator's responsibility and must be implemented at the infrastructure layer (e.g., nginx, API gateway). Flask-Limiter is a dependency of FAB but is not pre-configured with limits in Superset's default config.
  • Rate-limit headers: No
  • Retry-After header: No
  • Rate-limit notes: No official rate limit documentation exists for the open-source distribution. Preset (managed Superset) may impose its own limits but is a separate commercial product.
  • Pagination method: offset
  • Default page size: 20
  • Max page size: 100
  • Pagination pointer: Pagination params (page, page_size) must be embedded inside the Rison-encoded q query parameter, e.g. GET /api/v1/security/users/?q=(page:0,page_size:25). Passing page/page_size as bare query params does not work reliably. FAB_API_MAX_PAGE_SIZE config key controls the server-side ceiling.
Plan Limit Concurrent
Self-hosted (open source) No default limit; operator-configured 0
  • Webhooks available: No
  • Webhook notes: Apache Superset does not provide a native webhook system. There is no event-subscription mechanism for user lifecycle events (create, update, delete) in the open-source distribution.
  • Alternative event strategy: Use the LogRestApi endpoints (GET /api/v1/log/) to poll audit logs for user activity. For real-time event streaming, Superset offers AsyncEventsRestApi (GET /api/v1/async_event/) via Server-Sent Events (SSE), but this covers query/chart events, not user management events.

SCIM API status

  • SCIM available: No
  • SCIM version: Not documented
  • Plan required: Not available in open-source Apache Superset. Preset (managed commercial offering) may provide easier IdP integration but does not advertise a native SCIM 2.0 endpoint.
  • Endpoint: Not documented

Limitations:

  • No native SCIM 2.0 support in Apache Superset.
  • SSO/IdP provisioning requires a custom SecurityManager implementation.
  • User auto-registration on first SSO login is supported via AUTH_USER_REGISTRATION=True, but this is JIT provisioning, not SCIM push.
  • Role mapping from IdP groups to Superset roles is possible via AUTH_ROLES_MAPPING config but requires manual configuration.

Common scenarios

Three automation scenarios are supported by the API, each with meaningful caveats. First, programmatic user provisioning: POST /api/v1/security/users/ with role IDs fetched dynamically from GET /api/v1/security/roles/ - role integer IDs are not stable across reinstalls and must be resolved at runtime.

Second, soft deactivation: PUT /api/v1/security/users/{pk} with active:false - but PUT is a full replacement, so omitting any field (especially roles) will clear it; always send the complete desired user object.

Third, JIT SSO provisioning via AUTH_USER_REGISTRATION=True: users are created on first IdP login, but there is no SCIM push, no pre-provisioning, and no automatic deactivation when a user is removed from the IdP - Superset's database must be reconciled manually or via the Security API.

Pagination on list endpoints must be encoded inside the Rison q parameter (e. g.

, ? q=(page:0,page_size:25)); bare query params are silently ignored and always return the first 20 results.

Provision a new user and assign a role programmatically

  1. Ensure FAB_ADD_SECURITY_API=True is set in superset_config.py and Superset has been restarted.
  2. POST /api/v1/security/login with admin credentials (provider='db') to obtain access_token.
  3. GET /api/v1/security/roles/?q=(page:0,page_size:100) to retrieve available roles and their integer IDs.
  4. POST /api/v1/security/users/ with body {username, first_name, last_name, email, password, active:true, roles:[{id:}]}.
  5. Capture the returned user id for future reference.
  6. Optionally verify with GET /api/v1/security/users/{pk}.

Watch out for: Role IDs are integers and must be fetched dynamically - they are not stable across Superset reinstalls. The password field is only meaningful for AUTH_DB users; LDAP/OAuth users should be created without a password and will authenticate via their IdP.

Deactivate (soft-disable) a user without deleting them

  1. Obtain JWT access_token via POST /api/v1/security/login.
  2. Find the user's integer ID via GET /api/v1/security/users/?q=(filters:!((col:username,opr:eq,value:'jdoe'))).
  3. PUT /api/v1/security/users/{pk} with body {active:false} plus all other required fields (username, first_name, last_name, email, roles) to avoid clearing them.
  4. Confirm the user can no longer log in.

Watch out for: PUT is a full replacement in FAB's REST API. Omitting roles in the PUT body will clear all role assignments. Always include the full desired state of the user object, not just the changed fields.

Integrate IdP SSO with auto-provisioning (JIT, no SCIM)

  1. Install Authlib: pip install Authlib.
  2. In superset_config.py set AUTH_TYPE=AUTH_OAUTH, configure OAUTH_PROVIDERS with client_id, client_secret, api_base_url, access_token_url, authorize_url for your IdP (Okta, Entra, etc.).
  3. Set AUTH_USER_REGISTRATION=True and AUTH_USER_REGISTRATION_ROLE='Gamma' to auto-create users on first SSO login.
  4. Optionally configure AUTH_ROLES_MAPPING to map IdP group claims to Superset roles.
  5. Optionally set AUTH_ROLES_SYNC_AT_LOGIN=True to re-sync roles on every login.
  6. Run superset init to synchronize permissions.
  7. For API access by service accounts, maintain a separate local admin account (AUTH_DB) and use provider='db' on /api/v1/security/login.

Watch out for: This is JIT provisioning only - users are created on first login, not pushed from the IdP. There is no SCIM endpoint to pre-provision users or sync deletions. Deprovisioned IdP users will still exist in Superset's database and must be deactivated manually via the Security API or CLI.

Why building this yourself is a trap

The Security API's beta status is the primary risk for any production automation: FAB breaking changes across minor Superset versions can silently break provisioning pipelines with no deprecation notice. CSRF protection (WTF_CSRF_ENABLED=True by default) requires an additional token-fetch step on every mutating call when using session-cookie auth.

Superset does not natively validate externally-issued OIDC/JWT tokens (e.g., from Okta or Entra ID) for API calls - a custom SecurityManager subclass is required to accept external Bearer tokens, adding implementation surface. Running superset init at any point re-synchronizes all built-in role permissions to defaults, which can silently overwrite custom permission assignments.

There are no built-in rate limits (operator must configure at the infrastructure layer), no rate-limit response headers, and no retry-after signaling. Teams building lifecycle automation against this API should treat every endpoint under /api/v1/security/users/* as potentially unstable and version-pin their Superset deployments accordingly.

Automate Apache Superset workflows without one-off scripts

Stitchflow builds and maintains end-to-end IT automation across your SaaS stack, including apps without APIs. Built for exactly how your company works, with human approvals where they matter.

Every app coverage, including apps without APIs
60+ app integrations plus browser automation for apps without APIs
IT graph reconciliation across apps and your IdP
Less than a week to launch, maintained as APIs and admin consoles change
SOC 2 Type II. ~2 hours of your team's time

UpdatedFeb 26, 2026

* Details sourced from official product documentation and admin references.

Keep exploring

Related apps

Abnormal Security logo

Abnormal Security

API Only
AutomationAPI only
Last updatedMar 2026

Abnormal Security is an enterprise email security platform focused on detecting and investigating threats such as phishing, account takeover (ATO), and vendor email compromise. It does not support SCIM provisioning, which means every app in your stack

ActiveCampaign logo

ActiveCampaign

API Only
AutomationAPI only
Last updatedFeb 2026

ActiveCampaign uses a group-based permission model: every user belongs to exactly one group, and all feature-area access (Contacts, Campaigns, Automations, Deals, Reports, Templates) is configured at the group level, not per individual. The default Adm

ADP logo

ADP

API Only
AutomationAPI only
Last updatedFeb 2026

ADP Workforce Now is a mid-market to enterprise HCM platform that serves as the HR source of record for employee data — payroll, benefits, time, and talent. User access is governed by a hybrid permission model: predefined security roles (Security Maste