Compare commits

..

1 Commits

Author SHA1 Message Date
giles
bfd8d55f27 Silent SSO via sso_hint cookie
- Federation sets sso_hint=1 on .rose-ash.com after magic link login
- Client apps: before_request checks sso_hint, triggers silent OAuth
  once per session (sso_checked flag prevents loops)
- Logout clears sso_hint cookie on all apps

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 11:23:26 +00:00
2 changed files with 23 additions and 3 deletions

View File

@@ -5,7 +5,7 @@ import os
from pathlib import Path
from typing import Callable, Awaitable, Sequence
from quart import Quart, request, g, send_from_directory
from quart import Quart, request, g, redirect, send_from_directory
from shared.config import init_config, config, pretty
from shared.models import KV # ensure shared models imported
@@ -122,6 +122,24 @@ def create_base_app(
for fn in before_request_fns:
app.before_request(fn)
# Silent SSO: if federation set sso_hint cookie, trigger OAuth once
if name != "federation":
from urllib.parse import quote as _quote
@app.before_request
async def _sso_check():
from quart import session as qs
if request.path.startswith("/auth/"):
return
if qs.get("uid"):
return
if qs.get("sso_checked"):
return
if not request.cookies.get("sso_hint"):
return
qs["sso_checked"] = True
return redirect(f"/auth/login/?next={_quote(request.url, safe='')}")
@app.before_request
async def _csrf_protect():
await protect()

View File

@@ -125,8 +125,10 @@ def create_oauth_blueprint(app_name: str) -> Blueprint:
async def logout():
qsession.pop(SESSION_USER_KEY, None)
qsession.pop("cart_sid", None)
# Redirect to blog home — avoids re-auth loop on apps that require login
qsession.pop("sso_checked", None)
from shared.infrastructure.urls import blog_url
return redirect(blog_url("/"))
resp = redirect(blog_url("/"))
resp.delete_cookie("sso_hint", domain=".rose-ash.com", path="/")
return resp
return bp