SkyLink implements Role-Based Access Control (RBAC) following the Security by Design principle of Least Privilege. Each role has only the minimum permissions required for its function.
| Role | Description | Use Case |
|---|---|---|
aircraft_standard |
Default aircraft role | Basic operations (weather, telemetry write) |
aircraft_premium |
Premium aircraft | Extended access (+ contacts) |
ground_control |
Ground control station | Monitoring operations (read-only) |
maintenance |
Maintenance personnel | Diagnostic access |
admin |
System administrator | Full access |
| Permission | Description | Resources |
|---|---|---|
weather:read |
Access weather data | GET /weather/current |
contacts:read |
Access contacts data | GET /contacts/ |
telemetry:write |
Ingest telemetry | POST /telemetry/ingest |
telemetry:read |
Read telemetry | GET /telemetry/events/* |
config:read |
Read configuration | Future endpoint |
config:write |
Modify configuration | Future endpoint |
audit:read |
Read audit logs | Future endpoint |
| Role | weather:read | contacts:read | telemetry:write | telemetry:read | config:read | config:write | audit:read |
|---|---|---|---|---|---|---|---|
| aircraft_standard | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ |
| aircraft_premium | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ |
| ground_control | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ |
| maintenance | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ |
| admin | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
# Default role (aircraft_standard)
curl -X POST http://localhost:8000/auth/token \
-H "Content-Type: application/json" \
-d '{"aircraft_id": "550e8400-e29b-41d4-a716-446655440000"}'
# With specific role
curl -X POST http://localhost:8000/auth/token \
-H "Content-Type: application/json" \
-d '{
"aircraft_id": "550e8400-e29b-41d4-a716-446655440000",
"role": "aircraft_premium"
}'The JWT token includes the role in its claims:
{
"sub": "550e8400-e29b-41d4-a716-446655440000",
"aud": "skylink",
"iat": 1703174400,
"exp": 1703175300,
"role": "aircraft_premium"
}Missing or invalid JWT token.
{
"detail": "Missing Authorization header"
}Valid token but insufficient permissions.
{
"detail": "Permission denied: contacts:read required"
}from fastapi import APIRouter, Depends
from skylink.rbac import require_permission
from skylink.rbac_roles import Permission
router = APIRouter()
@router.get("/protected")
async def protected_endpoint(
token: dict = Depends(require_permission(Permission.WEATHER_READ))
):
# Token is verified and has required permission
return {"message": "Access granted"}@router.get("/multi-protected")
async def multi_protected(
token: dict = Depends(require_permission(
Permission.TELEMETRY_READ,
Permission.CONFIG_READ
))
):
# Requires BOTH permissions
return {"message": "Access granted"}from skylink.rbac import require_role
from skylink.rbac_roles import Role
@router.get("/admin-only")
async def admin_only(
token: dict = Depends(require_role(Role.ADMIN))
):
# Only admin role allowed
return {"message": "Admin access granted"}All authorization decisions are logged for security audit:
{
"event_type": "AUTHZ_SUCCESS",
"event_category": "authorization",
"severity": "info",
"actor": {"type": "aircraft", "id": "550e8400..."},
"details": {
"role": "aircraft_premium",
"permission": "contacts:read",
"endpoint": "/contacts/"
}
}{
"event_type": "AUTHZ_FAILURE",
"event_category": "authorization",
"severity": "warning",
"actor": {"type": "aircraft", "id": "550e8400..."},
"details": {
"role": "aircraft_standard",
"required_permission": "contacts:read",
"endpoint": "/contacts/"
}
}-
Default Role: Tokens without explicit role default to
aircraft_standard(least privilege). -
Invalid Roles: Invalid role values in tokens fall back to
aircraft_standard. -
Role in Token: Role is embedded in JWT, preventing runtime escalation.
-
No Role Enumeration: 403 responses don't reveal which roles would have access.
-
Authentication vs Authorization:
- 401 = Authentication failure (no/invalid token)
- 403 = Authorization failure (valid token, wrong permissions)
- Role hierarchy (inheritance)
- Dynamic role assignment from database
- Time-based permissions
- Scope-based access (e.g., specific aircraft only)