"""FlowDeck — Auth routes: login, callback, logout.""" from __future__ import annotations import logging import secrets from fastapi import APIRouter, Body, Query, Request from fastapi.responses import HTMLResponse, RedirectResponse from app.auth.session import SessionManager from app.config import settings from app.templating import CSP_NONCE logger = logging.getLogger(__name__) router = APIRouter(tags=["auth"], prefix="/auth") def get_redirect_uri(request: Request) -> str: """OAuth redirect URI for this request. Explicit `OAUTH_REDIRECT_URI` env override wins (must be registered in the provider's OAuth app). Otherwise it is derived from the request so it always matches the URL the user actually used: scheme from `X-Forwarded-Proto` (reverse proxies) falling back to the request scheme, host from `X-Forwarded-Host` falling back to the `Host` header. """ if settings.oauth_redirect_uri: return settings.oauth_redirect_uri proto = request.headers.get("x-forwarded-proto", "") scheme = proto.split(",")[0].strip() or request.url.scheme or "http" fwd_host = request.headers.get("x-forwarded-host", "") host = fwd_host.split(",")[0].strip() or request.headers.get("host", "localhost:8080") return f"{scheme}://{host}/auth/callback" def _sso_login_url() -> str: """URL du bouton « Login with ObsiGate (SSO) ». Émettrice = ``obsigate_url()`` (DRACO_SSO_URL explicite, sinon l'environnement de la requête — v7.82.4) ; retour = URL publique de cette instance résolue de la même façon (FLOWDECK_URL / OAUTH_REDIRECT_URI explicites, sinon hôte de la requête, le callback = sa propre origine résolue) + ``/auth/draco``. Aucun nom public figé. """ from urllib.parse import quote from app.services import draco_urls retour = f"{draco_urls.flowdeck_url()}/auth/draco" return (f"{draco_urls.obsigate_url()}/sso/authorize" f"?return_to={quote(retour, safe='')}") # Échec de connexion locale (fusion #144) : le message suggère la voie # centrale — un compte créé dans le Hub Dracodev n'a pas de mot de # passe local, son entrée est le bouton « Login with ObsiGate (SSO) » # du même écran (libellé repris tel quel). MESSAGE_ECHEC_CONNEXION_LOCALE = ( "Identifiants invalides. Si votre compte a été créé dans le Hub " "Dracodev, connectez-vous avec le bouton « Login with ObsiGate " "(SSO) » de cet écran : les comptes de la suite n'ont pas de mot " "de passe local." ) def _page_inscription_fermee() -> str: """Page de refus propre du parcours d'inscription fermé (#146).""" from app.services import draco_urls, reglages_acces hub = draco_urls.hub_url() message = reglages_acces.message_inscription_fermee() return f"""
Cette instance n'accepte que la connexion centrale de la suite Dracodev. Les comptes se créent dans le Hub Dracodev.
🧭 Login with ObsiGate (SSO)