ec4769a33f
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
33 lines
939 B
Python
33 lines
939 B
Python
"""API key authentication backend (Stage 1 PR2).
|
|
|
|
Resolves an ``Authorization: Bearer dfk_...`` token into a
|
|
``ServicePrincipal`` + workspace + scopes, so ``AuthMiddleware`` can
|
|
stamp the same contextvars a cookie-authenticated human would set
|
|
(spec D1: user_id = SA.id).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
from dataclasses import dataclass
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class ServicePrincipal:
|
|
"""Non-human principal backing an API key. Satisfies the
|
|
``deerflow.runtime.user_context.CurrentUser`` protocol."""
|
|
|
|
id: str
|
|
is_service_account: bool = True
|
|
|
|
|
|
def parse_scopes(scopes: str) -> list[str]:
|
|
"""Parse a comma-separated scope string into a permission list.
|
|
|
|
``"threads:read, threads:write"`` -> ``["threads:read", "threads:write"]``.
|
|
Empty / whitespace-only segments are dropped.
|
|
"""
|
|
return [s.strip() for s in scopes.split(",") if s.strip()]
|