DocuStore.io
Integration

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

  1. The frontend authenticates the user with the configured IdP (e.g., Google OAuth).
  2. The frontend sends the IdP token to Sentinel's token exchange endpoint.
  3. Sentinel validates the IdP token, resolves the user's workspace and permissions, and issues a DocuStore authorization JWT.
  4. All subsequent API requests include this JWT in the Authorization: Bearer <token> header.
  5. The DocuStore API validates the JWT using the sentinel-auth-sdk and extracts the RequestAuth context.

Workspace Isolation

Every API request is scoped to the workspace encoded in the JWT. The RequestAuth object provides:

FieldTypeDescription
workspace_idUUIDActive workspace
user_idUUIDAuthenticated user
is_adminboolWorkspace 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

LevelAccess
workspaceAll workspace members can view
privateOnly the owner can view
sharedOwner + 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

VariableDefaultDescription
SENTINEL_URLhttp://localhost:9003Sentinel service URL
SENTINEL_SERVICE_KEY(empty)Service-to-service authentication key
SENTINEL_SERVICE_NAMEdocu-storeService name registered in Sentinel
SENTINEL_IDP_JWKS_URLhttps://www.googleapis.com/oauth2/v3/certsIdP JWKS endpoint for token validation
SENTINEL_CACHE_TTL120Permission 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