Add local auth: AuthProvider, mailer, sessions, /api/v1/auth
Pluggable AuthProvider interface with a local (email+password) implementation, and a Mailer interface (ConsoleMailer for dev, SMTPMailer for operators). The auth service owns registration, login, opaque session issuance, email verification, and password reset (which revokes prior sessions). Endpoints under /api/v1/auth; sessions are returned as a Bearer token and set as an HttpOnly cookie. Replaces the temporary X-User-Id shim: get_current_user now resolves a real session (Bearer or cookie). The open user-bootstrap endpoint is gone (registration replaces it). App logging is configured so the ConsoleMailer's verification/reset links are visible to self-hosters. Verified end-to-end on the deploy target, including the email-verification flow. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Justin Paul <justin@jpaul.me>
This commit is contained in:
@@ -5,6 +5,9 @@ OpenAPI contract. All domain logic lives in the service layer; the privacy
|
||||
engine is the single enforcement point for reads.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import sys
|
||||
|
||||
from fastapi import FastAPI, Request
|
||||
from fastapi.responses import JSONResponse
|
||||
|
||||
@@ -14,6 +17,19 @@ from app.core.config import get_settings
|
||||
from app.services.exceptions import Conflict, Forbidden, NotFound
|
||||
|
||||
|
||||
def _configure_logging() -> None:
|
||||
"""Emit the app's own ``provenance.*`` logs at INFO to stdout (uvicorn only
|
||||
configures its own loggers). The ConsoleMailer relies on this so self-hosters
|
||||
can read verification/reset links from the logs."""
|
||||
app_logger = logging.getLogger("provenance")
|
||||
app_logger.setLevel(logging.INFO)
|
||||
if not app_logger.handlers:
|
||||
handler = logging.StreamHandler(sys.stdout)
|
||||
handler.setFormatter(logging.Formatter("%(levelname)s [%(name)s] %(message)s"))
|
||||
app_logger.addHandler(handler)
|
||||
app_logger.propagate = False
|
||||
|
||||
|
||||
def _register_error_handlers(app: FastAPI) -> None:
|
||||
@app.exception_handler(NotFound)
|
||||
async def _not_found(request: Request, exc: NotFound) -> JSONResponse:
|
||||
@@ -29,6 +45,7 @@ def _register_error_handlers(app: FastAPI) -> None:
|
||||
|
||||
|
||||
def create_app() -> FastAPI:
|
||||
_configure_logging()
|
||||
settings = get_settings()
|
||||
app = FastAPI(
|
||||
title=settings.app_name,
|
||||
|
||||
Reference in New Issue
Block a user