import time from fastapi import APIRouter, Request from fastapi.responses import RedirectResponse from sqlalchemy import select from app.db import SessionLocal from app.models import User from app.security.oidc import oauth from app.services import diagnostics router = APIRouter(prefix="/auth", tags=["auth"]) @router.get("/login") async def login(request: Request): # If OIDC isn't configured, the client was never registered and calling it # would raise an opaque 500. Send the operator to the setup check instead, # which spells out exactly which variables are missing. if not diagnostics.oidc_configured(): return RedirectResponse(url="/setup") redirect_uri = request.url_for("auth_callback") return await oauth.pocketid.authorize_redirect(request, redirect_uri) @router.get("/callback", name="auth_callback") async def auth_callback(request: Request): token = await oauth.pocketid.authorize_access_token(request) userinfo = token.get("userinfo") or await oauth.pocketid.userinfo(token=token) sub = userinfo["sub"] email = userinfo.get("email") name = userinfo.get("name") now = time.time() with SessionLocal() as db: user = db.execute(select(User).where(User.oidc_sub == sub)).scalar_one_or_none() if user is None: user = User(oidc_sub=sub, email=email, name=name, last_login_at=now) db.add(user) else: user.email = email user.name = name user.last_login_at = now db.commit() request.session["user"] = {"sub": sub, "email": email, "name": name} return RedirectResponse(url="/") @router.get("/logout") async def logout(request: Request): request.session.clear() end_session_endpoint = None metadata = await oauth.pocketid.load_server_metadata() end_session_endpoint = metadata.get("end_session_endpoint") if end_session_endpoint: return RedirectResponse(url=end_session_endpoint) return RedirectResponse(url="/")