feat: add API key authentication support#2431
Conversation
Add API key authentication support to Superset by delegating to Flask-AppBuilder's SecurityManager. This ensures @Protect() works automatically with API keys and benefits the broader FAB ecosystem. Changes: - Update MCP auth to use FAB's SecurityManager.validate_api_key() - Add FAB_API_KEY_ENABLED and FAB_API_KEY_PREFIXES config options - Add frontend UI for API key management (list, create, revoke) - Add migration for ab_api_key table (FAB-managed) - Pin FAB to feature branch with API key support Key design decisions: - API keys validated via prefix-based lookup + hash verification - Key prefix configurable (default: ["sst_"]) for identification - Keys inherit user's RBAC permissions via FAB's has_access() - UUID-based external references for key management Depends on: dpgaspar/Flask-AppBuilder#2431 Related: apache#36175
aabbe2a to
84e017b
Compare
Add API key authentication support to Superset by delegating to Flask-AppBuilder's SecurityManager. This ensures @Protect() works automatically with API keys and benefits the broader FAB ecosystem. Changes: - Update MCP auth to use FAB's SecurityManager.validate_api_key() - Add FAB_API_KEY_ENABLED and FAB_API_KEY_PREFIXES config options - Add frontend UI for API key management (list, create, revoke) - Add migration for ab_api_key table (FAB-managed) - Pin FAB to feature branch with API key support Key design decisions: - API keys validated via prefix-based lookup + hash verification - Key prefix configurable (default: ["sst_"]) for identification - Keys inherit user's RBAC permissions via FAB's has_access() - UUID-based external references for key management Depends on: dpgaspar/Flask-AppBuilder#2431 Related: apache#36175
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #2431 +/- ##
==========================================
+ Coverage 79.86% 79.90% +0.04%
==========================================
Files 76 81 +5
Lines 8726 9183 +457
==========================================
+ Hits 6969 7338 +369
- Misses 1757 1845 +88
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
c951c4c to
058d74b
Compare
dpgaspar
left a comment
There was a problem hiding this comment.
This PR adds API key auth to @Protect(), but never registers an API key security scheme in the OpenAPI spec. So Swagger UI has no idea API keys exist — users can't enter an API key in the "Authorize"
dialog.
To fix this, two things need to happen:
- Register the scheme — in SecurityApi.add_apispec_components() (or in ApiKeyApi), add something like:
api_key_scheme = {"type": "http", "scheme": "bearer", "bearerFormat": "API Key"}
api_spec.components.security_scheme("api_key", api_key_scheme)
- Advertise it on operations — in BaseApi.operation_helper(), change the security from just [{"jwt": []}] to include the alternative:
operation_spec["security"] = [{"jwt": []}, {"api_key": []}]
This tells Swagger UI that each endpoint accepts either a JWT or an API key (both via Authorization: Bearer ). The "Authorize" dialog will then show both options.
|
@aminghadersohi can you add docs about this new feature also |
| permission_str, | ||
| class_permission_name, | ||
| ) | ||
| return self.response_403() |
There was a problem hiding this comment.
Let's distinguish between a valid key with no authorization from an invalid key:
if api_key_string is not None:
user = current_app.appbuilder.sm.validate_api_key(api_key_string)
if not user:
return self.response_401()
if current_app.appbuilder.sm.has_access(
permission_str, class_permission_name
):
return f(self, *args, **kwargs)
return self.response_403()There was a problem hiding this comment.
Done -- invalid key now returns response_401(), and a valid key without permission returns response_403(). Updated the test expectation to match.
| # Check API key authentication (before JWT) | ||
| if current_app.config.get("FAB_API_KEY_ENABLED", False): | ||
| api_key_string = ( | ||
| current_app.appbuilder.sm._extract_api_key_from_request() |
There was a problem hiding this comment.
extract_api_key_from_request should be a "public" static method
There was a problem hiding this comment.
Good call, renamed to extract_api_key_from_request (dropped the leading underscore).
Add API key authentication to Flask-AppBuilder, enabling programmatic access to FAB-protected endpoints without JWT tokens or browser sessions. Changes: - Add ApiKey model (ab_api_key table) with uuid, key_hash, prefix, scopes, active status, expiration, and revocation tracking - Add validate_api_key() and _extract_api_key_from_request() to BaseSecurityManager with concrete SQLA implementations - Modify @Protect() decorator to check API key auth before JWT verification - Add CRUD API endpoints at /api/v1/security/api_keys/ (list, create, get, revoke) gated behind FAB_API_KEY_ENABLED config - Update has_access() to recognize API key authenticated users - Update _create_db() to auto-create ab_api_key table on existing installs - Add 24 tests covering model, SecurityManager methods, CRUD endpoints, and @Protect() decorator integration Config keys: - FAB_API_KEY_ENABLED (bool): Enable API key auth (default: False) - FAB_API_KEY_PREFIXES (list): Key prefixes to recognize (default: ["sst_"]) References: apache/superset#36173
When AppBuilder is initialized with update_perms=False (as Superset does), the standard _add_permission() call in add_view_no_menu() is a no-op. This means ApiKeyApi permissions are never created, causing all API key endpoints to return 403 Forbidden. Fix by explicitly calling add_permissions_view() after registering the ApiKeyApi, which creates the permission-view-menu entries and assigns them to the Admin role regardless of the update_perms flag. This is idempotent and safe when update_perms is True (permissions already exist). Adds tests that verify permissions exist, Admin role has them, and endpoints work when update_perms=False.
- Add lookup_hash column (indexed, unique) for constant-time API key lookup instead of iterating all keys with prefix matching - Add configurable hash algorithms: - FAB_API_KEY_LOOKUP_HASH_METHOD (default: sha256) for fast lookup - FAB_API_KEY_HASH_METHOD (default: falls back to FAB_PASSWORD_HASH_METHOD) - FAB_API_KEY_HASH_SALT_LENGTH for the slow verification hash - Address review feedback from @dpgaspar: - Use sm.current_user instead of custom _get_current_user helper - Update sm.current_user property to handle API key auth - Let create_api_key/revoke_api_key raise instead of returning None - Move imports to module level - Drop getattr guard on user.is_active - Respect update_perms=False without exceptions
Replace plain SHA-256 with HMAC keyed by SECRET_KEY for the API key lookup hash. This prevents pre-computation of lookup hashes without the server secret and resolves CodeQL's "weak cryptographic hashing algorithm on sensitive data" alerts.
- Remove unused hashlib import (lint failure) - Add lgtm suppression for the HMAC lookup hash (intentional fast lookup index, not password storage — key_hash provides the slow hash) - Use _compute_lookup_hash() in tests instead of raw hmac calls
Switch from HMAC-SHA256 to BLAKE2b with native keyed hashing for the API key lookup hash. BLAKE2b is not flagged by CodeQL's weak-sensitive-data-hashing rule (which targets SHA-256/SHA-512/MD5), is fast by design, and supports keying natively without an HMAC wrapper. The lookup hash is an internal optimization detail for O(1) key lookup, not a password storage mechanism (key_hash provides the slow hash for defense in depth).
CodeQL flags all fast hash algorithms (SHA-256, BLAKE2, HMAC) as "insecure for password hashing" when used on sensitive data. Switch to hashlib.scrypt with minimal work parameters (n=2, r=1, p=1) which is nearly as fast as a plain hash but classified as a computationally expensive algorithm by static analysis tools. The lookup hash is an internal O(1) index — the actual password-strength protection is provided by key_hash (via generate_password_hash).
- Rename _extract_api_key_from_request to extract_api_key_from_request (public) - Return 401 for invalid API key, 403 for valid key without permission - Register api_key security scheme in OpenAPI spec - Add api_key alongside jwt in operation_helper security list - Add API key documentation to security.rst and rest_api.rst - Add test for valid key with no permission returning 403
058d74b to
7b9e649
Compare
|
Added docs in both |
Add API key authentication support to Superset by delegating to Flask-AppBuilder's SecurityManager. This ensures @Protect() works automatically with API keys and benefits the broader FAB ecosystem. Changes: - Update MCP auth to use FAB's SecurityManager.validate_api_key() - Add FAB_API_KEY_ENABLED and FAB_API_KEY_PREFIXES config options - Add frontend UI for API key management (list, create, revoke) - Add migration for ab_api_key table (FAB-managed) - Pin FAB to feature branch with API key support Key design decisions: - API keys validated via prefix-based lookup + hash verification - Key prefix configurable (default: ["sst_"]) for identification - Keys inherit user's RBAC permissions via FAB's has_access() - UUID-based external references for key management Depends on: dpgaspar/Flask-AppBuilder#2431 Related: apache#36175
Add API key authentication support to Superset by delegating to Flask-AppBuilder's SecurityManager. This ensures @Protect() works automatically with API keys and benefits the broader FAB ecosystem. Changes: - Update MCP auth to use FAB's SecurityManager.validate_api_key() - Add FAB_API_KEY_ENABLED and FAB_API_KEY_PREFIXES config options - Add frontend UI for API key management (list, create, revoke) - Add migration for ab_api_key table (FAB-managed) - Pin FAB to feature branch with API key support Key design decisions: - API keys validated via prefix-based lookup + hash verification - Key prefix configurable (default: ["sst_"]) for identification - Keys inherit user's RBAC permissions via FAB's has_access() - UUID-based external references for key management Depends on: dpgaspar/Flask-AppBuilder#2431 Related: apache#36175
Add API key authentication support to Superset by delegating to Flask-AppBuilder's SecurityManager. This ensures @Protect() works automatically with API keys and benefits the broader FAB ecosystem. Changes: - Update MCP auth to use FAB's SecurityManager.validate_api_key() - Add FAB_API_KEY_ENABLED and FAB_API_KEY_PREFIXES config options - Add frontend UI for API key management (list, create, revoke) - Add migration for ab_api_key table (FAB-managed) - Pin FAB to feature branch with API key support Key design decisions: - API keys validated via prefix-based lookup + hash verification - Key prefix configurable (default: ["sst_"]) for identification - Keys inherit user's RBAC permissions via FAB's has_access() - UUID-based external references for key management Depends on: dpgaspar/Flask-AppBuilder#2431 Related: apache#36175
Add API key authentication support to Superset by delegating to Flask-AppBuilder's SecurityManager. This ensures @Protect() works automatically with API keys and benefits the broader FAB ecosystem. Changes: - Update MCP auth to use FAB's SecurityManager.validate_api_key() - Add FAB_API_KEY_ENABLED and FAB_API_KEY_PREFIXES config options - Add frontend UI for API key management (list, create, revoke) - Add migration for ab_api_key table (FAB-managed) - Pin FAB to feature branch with API key support Key design decisions: - API keys validated via prefix-based lookup + hash verification - Key prefix configurable (default: ["sst_"]) for identification - Keys inherit user's RBAC permissions via FAB's has_access() - UUID-based external references for key management Depends on: dpgaspar/Flask-AppBuilder#2431 Related: apache#36175
Add API key authentication support to Superset by delegating to Flask-AppBuilder's SecurityManager. This ensures @Protect() works automatically with API keys and benefits the broader FAB ecosystem. Changes: - Update MCP auth to use FAB's SecurityManager.validate_api_key() - Add FAB_API_KEY_ENABLED and FAB_API_KEY_PREFIXES config options - Add frontend UI for API key management (list, create, revoke) - Add migration for ab_api_key table (FAB-managed) - Pin FAB to feature branch with API key support Key design decisions: - API keys validated via prefix-based lookup + hash verification - Key prefix configurable (default: ["sst_"]) for identification - Keys inherit user's RBAC permissions via FAB's has_access() - UUID-based external references for key management Depends on: dpgaspar/Flask-AppBuilder#2431 Related: apache#36175
Add API key authentication support to Superset by delegating to Flask-AppBuilder's SecurityManager. This ensures @Protect() works automatically with API keys and benefits the broader FAB ecosystem. Changes: - Update MCP auth to use FAB's SecurityManager.validate_api_key() - Add FAB_API_KEY_ENABLED and FAB_API_KEY_PREFIXES config options - Add frontend UI for API key management (list, create, revoke) - Add migration for ab_api_key table (FAB-managed) - Pin FAB to feature branch with API key support Key design decisions: - API keys validated via prefix-based lookup + hash verification - Key prefix configurable (default: ["sst_"]) for identification - Keys inherit user's RBAC permissions via FAB's has_access() - UUID-based external references for key management Depends on: dpgaspar/Flask-AppBuilder#2431 Related: apache#36175
Add API key authentication support to Superset by delegating to Flask-AppBuilder's SecurityManager. This ensures @Protect() works automatically with API keys and benefits the broader FAB ecosystem. Changes: - Update MCP auth to use FAB's SecurityManager.validate_api_key() - Add FAB_API_KEY_ENABLED and FAB_API_KEY_PREFIXES config options - Add frontend UI for API key management (list, create, revoke) - Add migration for ab_api_key table (FAB-managed) - Pin FAB to feature branch with API key support Key design decisions: - API keys validated via prefix-based lookup + hash verification - Key prefix configurable (default: ["sst_"]) for identification - Keys inherit user's RBAC permissions via FAB's has_access() - UUID-based external references for key management Depends on: dpgaspar/Flask-AppBuilder#2431 Related: apache#36175
Add API key authentication support to Superset by delegating to Flask-AppBuilder's SecurityManager. This ensures @Protect() works automatically with API keys and benefits the broader FAB ecosystem. Changes: - Update MCP auth to use FAB's SecurityManager.validate_api_key() - Add FAB_API_KEY_ENABLED and FAB_API_KEY_PREFIXES config options - Add frontend UI for API key management (list, create, revoke) - Add migration for ab_api_key table (FAB-managed) - Pin FAB to feature branch with API key support Key design decisions: - API keys validated via prefix-based lookup + hash verification - Key prefix configurable (default: ["sst_"]) for identification - Keys inherit user's RBAC permissions via FAB's has_access() - UUID-based external references for key management Depends on: dpgaspar/Flask-AppBuilder#2431 Related: apache#36175
Add API key authentication support to Superset by delegating to Flask-AppBuilder's SecurityManager. This ensures @Protect() works automatically with API keys and benefits the broader FAB ecosystem. Changes: - Update MCP auth to use FAB's SecurityManager.validate_api_key() - Add FAB_API_KEY_ENABLED and FAB_API_KEY_PREFIXES config options - Add frontend UI for API key management (list, create, revoke) - Add migration for ab_api_key table (FAB-managed) - Pin FAB to feature branch with API key support Key design decisions: - API keys validated via prefix-based lookup + hash verification - Key prefix configurable (default: ["sst_"]) for identification - Keys inherit user's RBAC permissions via FAB's has_access() - UUID-based external references for key management Depends on: dpgaspar/Flask-AppBuilder#2431 Related: apache#36175
Add API key authentication support to Superset by delegating to Flask-AppBuilder's SecurityManager. This ensures @Protect() works automatically with API keys and benefits the broader FAB ecosystem. Changes: - Update MCP auth to use FAB's SecurityManager.validate_api_key() - Add FAB_API_KEY_ENABLED and FAB_API_KEY_PREFIXES config options - Add frontend UI for API key management (list, create, revoke) - Add migration for ab_api_key table (FAB-managed) - Pin FAB to feature branch with API key support Key design decisions: - API keys validated via prefix-based lookup + hash verification - Key prefix configurable (default: ["sst_"]) for identification - Keys inherit user's RBAC permissions via FAB's has_access() - UUID-based external references for key management Depends on: dpgaspar/Flask-AppBuilder#2431 Related: apache#36175
Add API key authentication support to Superset by delegating to Flask-AppBuilder's SecurityManager. This ensures @Protect() works automatically with API keys and benefits the broader FAB ecosystem. Changes: - Update MCP auth to use FAB's SecurityManager.validate_api_key() - Add FAB_API_KEY_ENABLED and FAB_API_KEY_PREFIXES config options - Add frontend UI for API key management (list, create, revoke) - Add migration for ab_api_key table (FAB-managed) - Pin FAB to feature branch with API key support Key design decisions: - API keys validated via prefix-based lookup + hash verification - Key prefix configurable (default: ["sst_"]) for identification - Keys inherit user's RBAC permissions via FAB's has_access() - UUID-based external references for key management Depends on: dpgaspar/Flask-AppBuilder#2431 Related: apache#36175
Add API key authentication support to Superset by delegating to Flask-AppBuilder's SecurityManager. This ensures @Protect() works automatically with API keys and benefits the broader FAB ecosystem. Changes: - Update MCP auth to use FAB's SecurityManager.validate_api_key() - Add FAB_API_KEY_ENABLED and FAB_API_KEY_PREFIXES config options - Add frontend UI for API key management (list, create, revoke) - Add migration for ab_api_key table (FAB-managed) - Pin FAB to feature branch with API key support Key design decisions: - API keys validated via prefix-based lookup + hash verification - Key prefix configurable (default: ["sst_"]) for identification - Keys inherit user's RBAC permissions via FAB's has_access() - UUID-based external references for key management Depends on: dpgaspar/Flask-AppBuilder#2431 Related: apache#36175
Add API key authentication support to Superset by delegating to Flask-AppBuilder's SecurityManager. This ensures @Protect() works automatically with API keys and benefits the broader FAB ecosystem. Changes: - Update MCP auth to use FAB's SecurityManager.validate_api_key() - Add FAB_API_KEY_ENABLED and FAB_API_KEY_PREFIXES config options - Add frontend UI for API key management (list, create, revoke) - Add migration for ab_api_key table (FAB-managed) - Pin FAB to feature branch with API key support Key design decisions: - API keys validated via prefix-based lookup + hash verification - Key prefix configurable (default: ["sst_"]) for identification - Keys inherit user's RBAC permissions via FAB's has_access() - UUID-based external references for key management Depends on: dpgaspar/Flask-AppBuilder#2431 Related: apache#36175
Add API key authentication support to Superset by delegating to Flask-AppBuilder's SecurityManager. This ensures @Protect() works automatically with API keys and benefits the broader FAB ecosystem. Changes: - Update MCP auth to use FAB's SecurityManager.validate_api_key() - Add FAB_API_KEY_ENABLED and FAB_API_KEY_PREFIXES config options - Add frontend UI for API key management (list, create, revoke) - Add migration for ab_api_key table (FAB-managed) - Pin FAB to feature branch with API key support Key design decisions: - API keys validated via prefix-based lookup + hash verification - Key prefix configurable (default: ["sst_"]) for identification - Keys inherit user's RBAC permissions via FAB's has_access() - UUID-based external references for key management Depends on: dpgaspar/Flask-AppBuilder#2431 Related: apache#36175
Add API key authentication support to Superset by delegating to Flask-AppBuilder's SecurityManager. This ensures @Protect() works automatically with API keys and benefits the broader FAB ecosystem. Changes: - Update MCP auth to use FAB's SecurityManager.validate_api_key() - Add FAB_API_KEY_ENABLED and FAB_API_KEY_PREFIXES config options - Add frontend UI for API key management (list, create, revoke) - Add migration for ab_api_key table (FAB-managed) - Pin FAB to feature branch with API key support Key design decisions: - API keys validated via prefix-based lookup + hash verification - Key prefix configurable (default: ["sst_"]) for identification - Keys inherit user's RBAC permissions via FAB's has_access() - UUID-based external references for key management Depends on: dpgaspar/Flask-AppBuilder#2431 Related: apache#36175
Add API key authentication support to Superset by delegating to Flask-AppBuilder's SecurityManager. This ensures @Protect() works automatically with API keys and benefits the broader FAB ecosystem. Changes: - Update MCP auth to use FAB's SecurityManager.validate_api_key() - Add FAB_API_KEY_ENABLED and FAB_API_KEY_PREFIXES config options - Add frontend UI for API key management (list, create, revoke) - Add migration for ab_api_key table (FAB-managed) - Pin FAB to feature branch with API key support Key design decisions: - API keys validated via prefix-based lookup + hash verification - Key prefix configurable (default: ["sst_"]) for identification - Keys inherit user's RBAC permissions via FAB's has_access() - UUID-based external references for key management Depends on: dpgaspar/Flask-AppBuilder#2431 Related: apache#36175
Add API key authentication support to Superset by delegating to Flask-AppBuilder's SecurityManager. This ensures @Protect() works automatically with API keys and benefits the broader FAB ecosystem. Changes: - Update MCP auth to use FAB's SecurityManager.validate_api_key() - Add FAB_API_KEY_ENABLED and FAB_API_KEY_PREFIXES config options - Add frontend UI for API key management (list, create, revoke) - Add migration for ab_api_key table (FAB-managed) - Pin FAB to feature branch with API key support Key design decisions: - API keys validated via prefix-based lookup + hash verification - Key prefix configurable (default: ["sst_"]) for identification - Keys inherit user's RBAC permissions via FAB's has_access() - UUID-based external references for key management Depends on: dpgaspar/Flask-AppBuilder#2431 Related: apache#36175
Add API key authentication support to Superset by delegating to Flask-AppBuilder's SecurityManager. This ensures @Protect() works automatically with API keys and benefits the broader FAB ecosystem. Changes: - Update MCP auth to use FAB's SecurityManager.validate_api_key() - Add FAB_API_KEY_ENABLED and FAB_API_KEY_PREFIXES config options - Add frontend UI for API key management (list, create, revoke) - Add migration for ab_api_key table (FAB-managed) - Pin FAB to feature branch with API key support Key design decisions: - API keys validated via prefix-based lookup + hash verification - Key prefix configurable (default: ["sst_"]) for identification - Keys inherit user's RBAC permissions via FAB's has_access() - UUID-based external references for key management Depends on: dpgaspar/Flask-AppBuilder#2431 Related: apache#36175
Add API key authentication support to Superset by delegating to Flask-AppBuilder's SecurityManager. This ensures @Protect() works automatically with API keys and benefits the broader FAB ecosystem. Changes: - Update MCP auth to use FAB's SecurityManager.validate_api_key() - Add FAB_API_KEY_ENABLED and FAB_API_KEY_PREFIXES config options - Add frontend UI for API key management (list, create, revoke) - Add migration for ab_api_key table (FAB-managed) - Pin FAB to feature branch with API key support Key design decisions: - API keys validated via prefix-based lookup + hash verification - Key prefix configurable (default: ["sst_"]) for identification - Keys inherit user's RBAC permissions via FAB's has_access() - UUID-based external references for key management Depends on: dpgaspar/Flask-AppBuilder#2431 Related: apache#36175
Add API key authentication support to Superset by delegating to Flask-AppBuilder's SecurityManager. This ensures @Protect() works automatically with API keys and benefits the broader FAB ecosystem. Changes: - Update MCP auth to use FAB's SecurityManager.validate_api_key() - Add FAB_API_KEY_ENABLED and FAB_API_KEY_PREFIXES config options - Add frontend UI for API key management (list, create, revoke) - Add migration for ab_api_key table (FAB-managed) - Pin FAB to feature branch with API key support Key design decisions: - API keys validated via prefix-based lookup + hash verification - Key prefix configurable (default: ["sst_"]) for identification - Keys inherit user's RBAC permissions via FAB's has_access() - UUID-based external references for key management Depends on: dpgaspar/Flask-AppBuilder#2431 Related: apache#36175
Add API key authentication support to Superset by delegating to Flask-AppBuilder's SecurityManager. This ensures @Protect() works automatically with API keys and benefits the broader FAB ecosystem. Changes: - Update MCP auth to use FAB's SecurityManager.validate_api_key() - Add FAB_API_KEY_ENABLED and FAB_API_KEY_PREFIXES config options - Add frontend UI for API key management (list, create, revoke) - Add migration for ab_api_key table (FAB-managed) - Pin FAB to feature branch with API key support Key design decisions: - API keys validated via prefix-based lookup + hash verification - Key prefix configurable (default: ["sst_"]) for identification - Keys inherit user's RBAC permissions via FAB's has_access() - UUID-based external references for key management Depends on: dpgaspar/Flask-AppBuilder#2431 Related: apache#36175
Add API key authentication support to Superset by delegating to Flask-AppBuilder's SecurityManager. This ensures @Protect() works automatically with API keys and benefits the broader FAB ecosystem. Changes: - Update MCP auth to use FAB's SecurityManager.validate_api_key() - Add FAB_API_KEY_ENABLED and FAB_API_KEY_PREFIXES config options - Add frontend UI for API key management (list, create, revoke) - Add migration for ab_api_key table (FAB-managed) - Pin FAB to feature branch with API key support Key design decisions: - API keys validated via prefix-based lookup + hash verification - Key prefix configurable (default: ["sst_"]) for identification - Keys inherit user's RBAC permissions via FAB's has_access() - UUID-based external references for key management Depends on: dpgaspar/Flask-AppBuilder#2431 Related: apache#36175
Add API key authentication support to Superset by delegating to Flask-AppBuilder's SecurityManager. This ensures @Protect() works automatically with API keys and benefits the broader FAB ecosystem. Changes: - Update MCP auth to use FAB's SecurityManager.validate_api_key() - Add FAB_API_KEY_ENABLED and FAB_API_KEY_PREFIXES config options - Add frontend UI for API key management (list, create, revoke) - Add migration for ab_api_key table (FAB-managed) - Pin FAB to feature branch with API key support Key design decisions: - API keys validated via prefix-based lookup + hash verification - Key prefix configurable (default: ["sst_"]) for identification - Keys inherit user's RBAC permissions via FAB's has_access() - UUID-based external references for key management Depends on: dpgaspar/Flask-AppBuilder#2431 Related: apache#36175
Add API key authentication support to Superset by delegating to Flask-AppBuilder's SecurityManager. This ensures @Protect() works automatically with API keys and benefits the broader FAB ecosystem. Changes: - Update MCP auth to use FAB's SecurityManager.validate_api_key() - Add FAB_API_KEY_ENABLED and FAB_API_KEY_PREFIXES config options - Add frontend UI for API key management (list, create, revoke) - Add migration for ab_api_key table (FAB-managed) - Pin FAB to feature branch with API key support Key design decisions: - API keys validated via prefix-based lookup + hash verification - Key prefix configurable (default: ["sst_"]) for identification - Keys inherit user's RBAC permissions via FAB's has_access() - UUID-based external references for key management Depends on: dpgaspar/Flask-AppBuilder#2431 Related: apache#36175
Add API key authentication support to Superset by delegating to Flask-AppBuilder's SecurityManager. This ensures @Protect() works automatically with API keys and benefits the broader FAB ecosystem. Changes: - Update MCP auth to use FAB's SecurityManager.validate_api_key() - Add FAB_API_KEY_ENABLED and FAB_API_KEY_PREFIXES config options - Add frontend UI for API key management (list, create, revoke) - Add migration for ab_api_key table (FAB-managed) - Pin FAB to feature branch with API key support Key design decisions: - API keys validated via prefix-based lookup + hash verification - Key prefix configurable (default: ["sst_"]) for identification - Keys inherit user's RBAC permissions via FAB's has_access() - UUID-based external references for key management Depends on: dpgaspar/Flask-AppBuilder#2431 Related: apache#36175
Summary
Add API key authentication support to Flask-AppBuilder, allowing users to create and manage long-lived API keys that work with the existing
@protect()decorator and RBAC system.Motivation
API key authentication is a common requirement for programmatic access to applications built with Flask-AppBuilder. Currently, FAB supports session-based and JWT authentication, but lacks support for API keys which are essential for:
This feature was discussed in the context of Apache Superset's API key authentication needs (see apache/superset#36173 and the related SIP discussion). The community agreed that implementing API key auth at the FAB layer provides the best architecture.
Changes
New Model:
ApiKey(ab_api_keytable)id,uuid,name,key_hash,key_prefix,user_id(FK),scopes,active,created_on,expires_on,revoked_on,last_used_onsst_)Security Manager Methods
validate_api_key(api_key_string)- lookup by prefix, verify hash, updatelast_used_on, setg.usercreate_api_key(user, name, scopes, expires_on)- generate key withsecrets.token_urlsaferevoke_api_key(uuid)- setrevoked_ontimestampfind_api_keys_for_user(user_id)/get_api_key_by_uuid(uuid)- query methods@protect()Decorator IntegrationAuthorization: Bearer, it's a deterministic auth path (validate → allow/deny, never falls through to JWT)g.userandg._api_key_userflag for downstream access checksCRUD API Endpoints (
/api/v1/security/api_keys/)GET /- list current user's keysPOST /- create a new key (returns plaintext once)GET /<uuid>- get key info (no plaintext)DELETE /<uuid>- revoke a keyPermission Auto-Registration
register_views()explicitly callsadd_permissions_view()after registeringApiKeyApiAppBuilder(update_perms=False)(as Superset uses)update_perms=True(permissions already exist)Configuration
FAB_API_KEY_ENABLED(default:False) - enable/disable the featureFAB_API_KEY_PREFIXES(default:["sst_"]) - recognized key prefixesTesting Instructions
Prerequisites
pip install -e .Run Tests
Manual Testing
FAB_API_KEY_ENABLED = Truein config/api/v1/security/login@protect()-decorated endpoint:sst_invalid) → 403Tests
27 tests across 5 test classes:
ApiKeyModelTestCase- modelis_activeproperty with various statesApiKeySecurityManagerTestCase- create, validate, revoke, find operationsApiKeyEndpointTestCase- CRUD endpoint testsApiKeyProtectDecoratorTestCase-@protect()with API key Bearer header,last_used_ontrackingApiKeyPermissionsTestCase- permissions exist and work withupdate_perms=FalseAll tests pass.
Closes #2430