Extending Authentication Strategies
The framework allows adding custom authentication strategies through a registry-based approach. This follows the Open-Closed Principle, enabling you to add new auth methods without modifying the framework core.
1. Implement the Strategy
Your strategy must implement the AuthenticationProtocol from framework_m_core.interfaces.authentication.
from collections.abc import Mapping
from framework_m_core.interfaces.auth_context import UserContext
class MyCustomAuth:
def supports(self, headers: Mapping[str, str]) -> bool:
return "x-custom-token" in headers
async def authenticate(self, headers: Mapping[str, str]) -> UserContext | None:
token = headers.get("x-custom-token")
if token == "secret":
return UserContext(id="user-1", email="user@example.com")
return None
2. Create a Factory
Strategies are registered via a Factory function. This function receives the entire auth configuration block and any global dependencies (like jwt_secret).
from typing import Any
from framework_m_standard.adapters.auth.strategies import AuthStrategyRegistry
def custom_auth_factory(config: dict[str, Any], **deps: Any) -> MyCustomAuth:
return MyCustomAuth()
# Register the strategy
AuthStrategyRegistry().register("my-custom", custom_auth_factory)
3. Configure in config.toml
Once registered, you can enable your strategy and set its priority in the auth.strategies list. The order in the list determines the priority in the AuthChain ("first match wins").
[auth]
# Priority: Check custom token first, then fallback to Bearer JWT
strategies = ["my-custom", "bearer"]
4. Dynamic Loading (Alternative)
If you don't want to manually call register(), you can provide the fully qualified path to your strategy class or factory in the configuration:
[auth]
strategies = ["my_app.auth.MyCustomAuth", "bearer"]
The framework will automatically attempt to import and instantiate it.