FastAPI permissions system
Project description
fastapi-has-permissions
Introduction
fastapi-has-permissions is a Python library that provides a declarative permissions system for FastAPI applications.
It allows you to define permission checks as classes or functions and compose them using boolean operators
(&, |, ~) into complex permission expressions. These composed permissions integrate directly
with FastAPI's dependency injection system.
Features:
- Class-based permissions -- subclass
Permissionand overridecheck_permissions() - Function-based permissions -- use the
@permissiondecorator to wrap async functions - Boolean composition -- combine permissions with
&(AND),|(OR),~(NOT) - Lazy evaluation -- defer dependency resolution to request time with
lazy() - Skip mechanism -- conditionally bypass permission checks using
SkipPermissionCheck - Customizable error responses -- override default 403 status code and error messages
- Full FastAPI DI integration -- permission check functions support all FastAPI dependency injection features
- Compatible with Python 3.10 and higher
Installation
pip install fastapi-has-permissions
Quickstart
Define a permission by subclassing Permission and use it as a FastAPI dependency:
from dataclasses import dataclass
from fastapi import Depends, FastAPI, Request
from fastapi_has_permissions import Permission
class HasAuthorizationHeader(Permission):
async def check_permissions(self, request: Request) -> bool:
return "Authorization" in request.headers
app = FastAPI()
@app.get(
"/protected",
dependencies=[Depends(HasAuthorizationHeader())],
)
async def protected():
return {"message": "You have access!"}
Boolean Composition
Permissions can be combined using & (AND), | (OR), and ~ (NOT) operators:
from dataclasses import dataclass
from fastapi import Depends, Request
from fastapi_has_permissions import Permission
class HasAuthorizationHeader(Permission):
async def check_permissions(self, request: Request) -> bool:
return "Authorization" in request.headers
@dataclass
class HasRole(Permission):
role: str
async def check_permissions(self, request: Request) -> bool:
return request.headers.get("role") == self.role
# All permissions must pass
@app.get(
"/admin",
dependencies=[Depends(HasAuthorizationHeader() & HasRole("admin"))],
)
async def admin_only():
return {"message": "Admin access granted"}
# Any permission must pass
@app.get(
"/flexible",
dependencies=[Depends(HasAuthorizationHeader() | HasRole("admin"))],
)
async def flexible_access():
return {"message": "Access granted"}
# Negated permission
@app.get(
"/no-auth",
dependencies=[Depends(~HasAuthorizationHeader())],
)
async def no_auth_required():
return {"message": "No auth header present"}
Function-Based Permissions
Use the @permission decorator to create permissions from async functions:
from typing import Annotated
from fastapi import Depends, Header
from fastapi_has_permissions import permission
@permission
async def has_admin_role(role: Annotated[str, Header()]) -> bool:
return role == "admin"
@app.get(
"/admin",
dependencies=[Depends(has_admin_role)],
)
async def admin_endpoint():
return {"message": "Admin access granted"}
Function-based permissions also support boolean composition:
@permission
async def has_authorization(request: Request) -> bool:
return "Authorization" in request.headers
# Combine function-based permissions
@app.get(
"/combined",
dependencies=[Depends(has_authorization & has_admin_role)],
)
async def combined():
return {"message": "Access granted"}
Lazy Permissions
Use lazy() to defer dependency resolution to request time. This is useful when a permission's
dependencies may not always be available:
from dataclasses import dataclass
from typing import Annotated
from fastapi import Depends, Header
from fastapi.exceptions import RequestValidationError
from fastapi_has_permissions import Permission, lazy
@dataclass
class AgeIsMoreThan(Permission):
age: int
async def check_permissions(self, age: Annotated[int, Header()]) -> bool:
return age > self.age
# If the "age" header is missing/invalid, skip the check instead of failing
@app.get(
"/age-restricted",
dependencies=[
Depends(lazy(AgeIsMoreThan(age=18), skip_on_exc=(RequestValidationError,))),
],
)
async def age_restricted():
return {"message": "Access granted"}
Custom Error Responses
Override the default 403 response by setting class variables or overriding methods:
class CustomPermission(Permission):
default_exc_message = "Custom error message"
default_exc_status_code = 401
async def check_permissions(self, request: Request) -> bool:
return "Authorization" in request.headers
For dynamic error messages, override get_exc_message() or get_exc_status_code():
@dataclass
class HasRole(Permission):
role: str
async def check_permissions(self, request: Request) -> bool:
return request.headers.get("role") == self.role
def get_exc_message(self) -> str:
return f"Role '{self.role}' is required"
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fastapi_has_permissions-0.1.1.tar.gz.
File metadata
- Download URL: fastapi_has_permissions-0.1.1.tar.gz
- Upload date:
- Size: 56.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.0 {"installer":{"name":"uv","version":"0.10.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
399e5c8d9133e8b11c5e0c209fe6a24f3854520b23341cd23c26664b79eba673
|
|
| MD5 |
324b567e07b57094c386c3192a8c674e
|
|
| BLAKE2b-256 |
c37fb199a23647ca22ac0c4c4f4f8cb03249b5fd160a9bd76590a7c7d064f0ba
|
File details
Details for the file fastapi_has_permissions-0.1.1-py3-none-any.whl.
File metadata
- Download URL: fastapi_has_permissions-0.1.1-py3-none-any.whl
- Upload date:
- Size: 13.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.0 {"installer":{"name":"uv","version":"0.10.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8b63b5ee2562de64ca5e99660cfe25bd37c578b7b327493af252c52ff304af24
|
|
| MD5 |
100b1545f482c6506ac03990860b70c6
|
|
| BLAKE2b-256 |
61279730be1399c18d9c909234adfaad6387d12d7877d43d5d33839b3346206a
|