"""Verify Firebase ID tokens sent as `Authorization: Bearer `. The Firebase web config is public by design. What protects us is verifying every token's signature, audience (our project id) and issuer against Google's published keys. Tests replace `verify` with a stub. """ from __future__ import annotations from fastapi import Header, HTTPException from google.auth.transport import requests as g_requests from google.oauth2 import id_token from .config import get_settings _request = g_requests.Request() def verify(token: str) -> dict: """Return the token claims, or raise ValueError.""" return id_token.verify_firebase_token(token, _request, audience=get_settings().firebase_project_id) def claims_from_header(authorization: str | None) -> dict | None: if not authorization or not authorization.lower().startswith("bearer "): return None token = authorization[7:].strip() try: c = verify(token) except Exception: # noqa: BLE001 - any failure means "not authenticated" raise HTTPException(401, "Sign-in expired or invalid. Please sign in again.") return {"uid": c["sub"], "email": (c.get("email") or "").lower(), "email_verified": bool(c.get("email_verified")), "name": (c.get("name") or "").strip(), "provider": (c.get("firebase") or {}).get("sign_in_provider", "")} def current_user(authorization: str | None = Header(default=None)) -> dict: c = claims_from_header(authorization) if not c: raise HTTPException(401, "Sign in to continue.") return c