bf-manage-core Auth and Authorization Model¶
Authentication¶
authenticate (src/auth/authentication.py) supports:
- Cognito bearer JWT path
- legacy VEMO token fallback path
- machine to machine token detection
On success it writes request.state.user with principal metadata.
flowchart TD
Header[Authorization input] --> Parse[Parse token source]
Parse --> Cognito{Cognito decode ok}
Cognito -- Yes --> Principal[Build principal]
Cognito -- No --> Legacy[Try legacy token decode]
Legacy --> LegacyOk{Legacy decode ok}
LegacyOk -- Yes --> Principal
LegacyOk -- No --> Reject[Return 401]
Authorization dependency model¶
Most routers are mounted with Depends(auth.authenticate) in main.py.
Endpoint-level access control is enforced via authorise(...) dependency (src/auth/permissions.py).
authorise performs:
- principal sanity checks
- system and m2m bypass checks
- workspace resolution from resource mapping or request headers
- user workspace permission lookup
- role and CRUD action checks
flowchart TD
Principal[request state principal] --> Active{Principal active}
Active -- No --> Deny[403 inactive]
Active -- Yes --> ResolveWorkspace[Resolve workspace id]
ResolveWorkspace --> PermCache[Check workspace permission cache]
PermCache --> RoleCache[Resolve role from role cache]
RoleCache --> RuleCheck[Apply action and condition rules]
RuleCheck --> Allow[Allow request]
RuleCheck --> Deny
Permission caches at app startup¶
main.py populates app state caches:
workspace_id_mappingrole_cacheworkspace_permission_cache
These accelerate authorization checks and are reloaded on cache misses.
flowchart LR
Startup[App startup] --> Map[workspace id mapping cache]
Startup --> Roles[role cache]
Startup --> Perms[user workspace permission cache]
RequestAuth[authorise check] --> Map
RequestAuth --> Roles
RequestAuth --> Perms
Workspace scoping signals¶
Workspace can be inferred from:
- resource identifier in path/query/body and mapping table
x-account-idheader for specific checks and context
This is how multi-tenant account boundaries are enforced per request.
Public vs protected API surfaces¶
main.py includes:
- public auth routes without global auth dependency
- public API routes with auth dependency
- internal API routes with auth dependency
Authorization is still endpoint-specific via explicit authorise(...) usage.