Authentication
Configuring Sentinel for workspace-scoped authorization with entity-level permissions.
DocuStore uses Sentinel for authorization. Sentinel operates in AuthZ mode -- the application authenticates users via an Identity Provider (IdP) directly, and Sentinel issues authorization JWTs that encode workspace membership, roles, and entity-level permissions.
Architecture
┌──────────┐
│ IdP │ (Google, Auth0, etc.)
└────┬─────┘
│ IdP token
▼
┌──────────┐ ┌──────────┐ ┌──────────────┐
│ Client │───▶│ Sentinel │───▶│ DocuStore │
│ (Portal) │ │ (AuthZ) │ │ API │
└──────────┘ └──────────┘ └──────────────┘
│ │
│ exchange │ AuthZ JWT
│ IdP token │ (workspace_id, user_id,
└──────────────┘ permissions, roles)Flow
- The frontend authenticates the user with the configured IdP (e.g., Google OAuth).
- The frontend sends the IdP token to Sentinel's token exchange endpoint.
- Sentinel validates the IdP token, resolves the user's workspace and permissions, and issues a DocuStore authorization JWT.
- All subsequent API requests include this JWT in the
Authorization: Bearer <token>header. - The DocuStore API validates the JWT using the
sentinel-auth-sdkand extracts theRequestAuthcontext.
Workspace Isolation
Every API request is scoped to the workspace encoded in the JWT. The RequestAuth object provides:
| Field | Type | Description |
|---|---|---|
workspace_id | UUID | Active workspace |
user_id | UUID | Authenticated user |
is_admin | bool | Workspace admin flag |
List endpoints automatically filter by workspace_id. Resource endpoints verify that the requested entity belongs to the user's workspace before returning data.
Entity-Level Permissions
Individual artifacts support fine-grained access control beyond workspace membership:
Visibility
| Level | Access |
|---|---|
workspace | All workspace members can view |
private | Only the owner can view |
shared | Owner + explicitly granted users/groups |
Sharing
Artifact owners and workspace admins can share artifacts with specific users or groups:
# Share an artifact with a user
curl -X POST http://localhost:8000/artifacts/{id}/shares \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"grantee_type": "user", "grantee_id": "user-uuid", "permission": "view"}'
# Update visibility
curl -X PATCH http://localhost:8000/artifacts/{id}/visibility \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"visibility": "private"}'
# View current ACL
curl http://localhost:8000/artifacts/{id}/permissions \
-H "Authorization: Bearer <token>"Permission Caching
Sentinel permission checks are cached for SENTINEL_CACHE_TTL seconds (default 120) to reduce latency on repeated access to the same resources.
Configuration
| Variable | Default | Description |
|---|---|---|
SENTINEL_URL | http://localhost:9003 | Sentinel service URL |
SENTINEL_SERVICE_KEY | (empty) | Service-to-service authentication key |
SENTINEL_SERVICE_NAME | docu-store | Service name registered in Sentinel |
SENTINEL_IDP_JWKS_URL | https://www.googleapis.com/oauth2/v3/certs | IdP JWKS endpoint for token validation |
SENTINEL_CACHE_TTL | 120 | Permission cache TTL in seconds (0 to disable) |
SDK Integration
The backend uses the sentinel-auth-sdk Python package:
from sentinel_auth import RequestAuth
# In FastAPI route handlers, RequestAuth is injected via dependency
@router.get("/artifacts")
async def list_artifacts(
auth: Annotated[RequestAuth, Depends(get_auth)],
):
# auth.workspace_id, auth.user_id, auth.is_admin are available
# auth.share(), auth.unshare(), auth.update_visibility() for ACL
# auth.get_enriched_resource_acl() for full ACL with user profiles
...The frontend uses the @sentinel-auth/nextjs package for server-side token validation and the @sentinel-auth/react package for client-side auth state management.
Development Setup
For local development, Sentinel runs as part of the Docker Compose stack. The default configuration uses Google as the IdP, but any OIDC-compliant provider can be configured by changing SENTINEL_IDP_JWKS_URL.
# Sentinel is included in docker-compose.yml
# Default URL: http://localhost:9003
SENTINEL_URL=http://localhost:9003
SENTINEL_SERVICE_KEY=dev-service-key