# How to Implement Custom Security Managers Extending Flask-AppBuilder in Apache Superset

> Extend Apache Superset authentication and authorization by subclassing SupersetSecurityManager. Implement custom permissions with addPermissionViewMenu and set CUSTOM_SECURITY_MANAGER.

- Repository: [The Apache Software Foundation/superset](https://github.com/apache/superset)
- Tags: how-to-guide
- Published: 2026-03-03

---

**You can extend Apache Superset's authentication and authorization layer by subclassing `SupersetSecurityManager`, registering custom permissions via `add_permission_view_menu`, and pointing the `CUSTOM_SECURITY_MANAGER` configuration key to your implementation class.**

Apache Superset leverages **Flask-AppBuilder (FAB)** for its security foundation, handling everything from user authentication to granular role-based access control. When you need to implement custom security managers extending Flask-AppBuilder to integrate external identity providers, modify role creation logic, or add domain-specific permissions, you must inherit from Superset's base security manager and configure the application to load your custom class during startup.

## Understanding the Base Security Architecture

The core security logic resides in [`superset/security/manager.py`](https://github.com/apache/superset/blob/main/superset/security/manager.py), where `SupersetSecurityManager` extends FAB's base `SecurityManager`. This class defines the permission model that governs access to Superset's features:

- **Model view whitelists** (`READ_ONLY_MODEL_VIEWS`, `ADMIN_ONLY_VIEW_MENUS`) control which UI views each role can access
- **Permission sets** (`READ_ONLY_PERMISSION`, `ADMIN_ONLY_PERMISSIONS`, `SQLLAB_ONLY_PERMISSIONS`) map FAB actions (`can_read`, `can_write`, etc.) to Superset resources
- **Helper methods** for guest token handling, row-level security (RLS), and SQL Lab permissions

*Source:* [superset/security/manager.py – class definition](https://github.com/apache/superset/blob/master/superset/security/manager.py#L58-L90)

## Where Superset Loads the Custom Manager

During application initialization, Superset validates and loads your custom security manager in [`superset/initialization/__init__.py`](https://github.com/apache/superset/blob/main/superset/initialization/__init__.py) (lines 824-835):

```python

# superset/initialization/__init__.py

custom_sm = self.config["CUSTOM_SECURITY_MANAGER"] or SupersetSecurityManager
if not issubclass(custom_sm, SupersetSecurityManager):
    raise Exception("CUSTOM_SECURITY_MANAGER must inherit SupersetSecurityManager")
appbuilder.security_manager_class = custom_sm

```

This validation ensures that any class referenced by `CUSTOM_SECURITY_MANAGER` must inherit from `SupersetSecurityManager`. If your class fails this check, Superset raises an exception during startup.

## Step-by-Step Implementation Guide

### 1. Create a Subclass of SupersetSecurityManager

Create a new Python module (for example, [`my_security_manager.py`](https://github.com/apache/superset/blob/main/my_security_manager.py)) that imports and extends the base class:

```python
from superset.security.manager import SupersetSecurityManager

class CustomSecurityManager(SupersetSecurityManager):
    """Your custom security logic extends the base implementation."""
    pass

```

### 2. Override init_app to Register Custom Permissions

The `init_app` method runs once after Flask application creation, making it the ideal hook for registering new permissions and roles. Use `add_permission_view_menu` to create global permissions and `add_permission_role` to assign them to specific roles:

```python
def init_app(self, app):
    # Always call the parent implementation first

    super().init_app(app)
    
    # Register a new permission on a custom resource

    self.add_permission_view_menu("can_fly", "Airplane")
    
    # Grant the permission to the Alpha role

    alpha_role = self.find_role("Alpha")
    if alpha_role:
        self.add_permission_role(alpha_role, "can_fly", "Airplane")

```

### 3. Configure CUSTOM_SECURITY_MANAGER in superset_config.py

Expose your class to Superset by adding the module path to your configuration file:

```python

# superset_config.py

CUSTOM_SECURITY_MANAGER = "my_package.my_security_manager.CustomSecurityManager"

```

The string must be a fully qualified Python import path (module + class name) that Python can import at runtime.

## Complete Working Example

Here is a production-ready implementation that adds a custom permission and assigns it to the Alpha role:

```python

# my_package/my_security_manager.py

from superset.security.manager import SupersetSecurityManager

class CustomSecurityManager(SupersetSecurityManager):
    """
    Example custom security manager that adds a ``can_fly`` permission
    and grants it to the ``Alpha`` role.
    """

    def init_app(self, app):
        # Initialize base FAB security features

        super().init_app(app)

        # Register a new permission-view menu combination

        self.add_permission_view_menu("can_fly", "Airplane")

        # Assign the permission to an existing role

        alpha_role = self.find_role("Alpha")
        if alpha_role:
            self.add_permission_role(alpha_role, "can_fly", "Airplane")

```

**Key implementation details:**

- **Inheritance** from `SupersetSecurityManager` preserves all default authentication and authorization behavior
- **Super call** in `init_app` ensures critical security hooks (guest token handling, database initialization) remain active
- **Permission registration** via `add_permission_view_menu` makes the permission available throughout the application
- **Role assignment** through `add_permission_role` immediately grants capabilities to users with that role

## Advanced Customization Patterns

You can override specific methods in your custom security manager to handle specialized use cases:

- **External SSO integration** (SAML, OIDC, LDAP): Override `auth_user_oauth` or `auth_user_ldap` to map external attributes to Superset roles
- **Dynamic role assignment**: Override `get_user_roles` to compute roles based on request context, JWT claims, or IP addresses
- **Row-level security enhancements**: Extend `get_rls_filters` to inject custom filters per user or group
- **Audit logging**: Override `log_user_action` to push security events to external SIEM systems

All these hooks are defined in [`superset/security/manager.py`](https://github.com/apache/superset/blob/main/superset/security/manager.py) and can be customized while maintaining compatibility with FAB's security framework.

## Common Pitfalls to Avoid

When implementing custom security managers extending Flask-AppBuilder, watch for these common errors:

- **Missing inheritance**: If your class does not inherit `SupersetSecurityManager`, the initialization check in [`superset/initialization/__init__.py`](https://github.com/apache/superset/blob/main/superset/initialization/__init__.py) raises an exception
- **Skipping super().init_app(app)**: Omitting the parent call disables built-in security features including guest token handling and permission synchronization
- **Permission name collisions**: FAB treats permission strings case-sensitively; avoid shadowing existing permissions like `can_write` or `can_read`
- **Import path errors**: The `CUSTOM_SECURITY_MANAGER` string must be a valid Python import path; typos result in `ImportError` at startup
- **Database synchronization**: New permissions require the Superset metadata database to be initialized; ensure `superset db upgrade` has run before starting the application with new permissions

## Summary

- Create a Python class that **inherits from `SupersetSecurityManager`** in [`superset/security/manager.py`](https://github.com/apache/superset/blob/main/superset/security/manager.py) to maintain compatibility with Flask-AppBuilder
- **Override `init_app`** to register custom permissions using `add_permission_view_menu` and assign them to roles with `add_permission_role`
- Configure the **fully qualified class path** in `CUSTOM_SECURITY_MANAGER` inside [`superset_config.py`](https://github.com/apache/superset/blob/main/superset_config.py)
- Always **call `super().init_app(app)`** to preserve default security initialization logic
- **Validate inheritance** during startup in [`superset/initialization/__init__.py`](https://github.com/apache/superset/blob/main/superset/initialization/__init__.py) ensures your custom manager integrates safely with the security stack

## Frequently Asked Questions

### What happens if my custom security manager does not inherit from SupersetSecurityManager?

Superset validates the class hierarchy during initialization in [`superset/initialization/__init__.py`](https://github.com/apache/superset/blob/main/superset/initialization/__init__.py) (lines 824-835). If your class is not a subclass of `SupersetSecurityManager`, the application raises an exception immediately at startup with the message "CUSTOM_SECURITY_MANAGER must inherit SupersetSecurityManager".

### Can I use a custom security manager to integrate OAuth or SAML authentication?

Yes. Override methods like `auth_user_oauth` for OAuth providers or `auth_user_ldap` for LDAP integration. These methods receive the authentication response from Flask-AppBuilder and allow you to map external user attributes to Superset roles before returning a user object.

### Where should I place my custom security manager code?

You can place your custom security manager in any Python module that is importable by Superset. Common locations include a `security/` directory adjacent to your [`superset_config.py`](https://github.com/apache/superset/blob/main/superset_config.py) file, or within an installed Python package. Ensure the module path in `CUSTOM_SECURITY_MANAGER` matches the actual file location.

### How do I verify that my custom permissions were registered correctly?

After starting Superset with your custom manager, query the FAB security tables (`ab_permission_view_role`, `ab_permission_view`, `ab_permission`) in the metadata database to verify your permissions exist. Alternatively, write an integration test that loads a test application instance with `CUSTOM_SECURITY_MANAGER` set and asserts that `security_manager.find_permission_view_menu("can_fly", "Airplane")` returns a valid object.