rgboards/rg-boards
Lanes, team task boards you run from the web or from Claude/ChatGPT (MCP). FastAPI + DataK3 + appid + Dodil Models.
A remix template · 0 remixes · Remix rgboards/rg-boards
app/boards/doors/identity.py
"""Who is calling. The Dodil gateway signs the person in through the app's user pool and passes
them as the X-Dodil-User header (JSON: sub, email, app_roles). It strips any copy a client sends,
so the app trusts it and ships no login code of its own.
Local development: set DEV_USER=you@example.com to act as that person without the gateway.
DEV_USER is ignored whenever the app runs with a user pool (DODIL_USER_POOL is set by
.dodil/deploy.yaml), so a stray env var can never open a deployed app to the signed-out.
"""
import json
import os
from typing import Optional
from boards.domain.model import Person
def _dev_user() -> str:
if os.environ.get("DODIL_USER_POOL"):
return ""
return os.environ.get("DEV_USER", "").strip().lower()
def person_from(headers) -> Optional[Person]:
raw = headers.get("x-dodil-user")
if raw:
try:
user = json.loads(raw)
except ValueError:
return None
if not isinstance(user, dict): # a malformed header is "nobody", never a crash
return None
email = str(user.get("email") or user.get("sub") or "").strip().lower()
return Person(email=email) if email else None
dev = _dev_user()
return Person(email=dev) if dev else None