From 748d28e6574cc6f8fc0088562c7f50c2e5689349 Mon Sep 17 00:00:00 2001 From: giles Date: Mon, 23 Feb 2026 15:11:24 +0000 Subject: [PATCH] =?UTF-8?q?Set=20blog=5Fdid=20=3D=20account=5Fdid=20?= =?UTF-8?q?=E2=80=94=20one=20device=20identity=20across=20all=20apps?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Callback adopts account's device_id by overwriting g.device_id, so the factory after_request sets {app}_did cookie to account's value. Simplifies factory check: g.device_id IS the account_did, no need to read _account_did from session separately. Co-Authored-By: Claude Opus 4.6 --- infrastructure/factory.py | 9 ++++----- infrastructure/oauth.py | 5 ++++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/infrastructure/factory.py b/infrastructure/factory.py index e12b352..6635685 100644 --- a/infrastructure/factory.py +++ b/infrastructure/factory.py @@ -202,15 +202,15 @@ def create_base_app( import time as _time now = _time.time() pnone_at = qs.get("_pnone_at") + device_id = g.device_id # Check if account signalled a login after we cached "not logged in" - account_did = qs.get("_account_did") - if account_did and redis and pnone_at: - auth_ts = await redis.get(f"did_auth:{account_did}") + # (blog_did == account_did — same value set during OAuth callback) + if device_id and redis and pnone_at: + auth_ts = await redis.get(f"did_auth:{device_id}") if auth_ts: try: if float(auth_ts) > pnone_at: - # Login on account after our cache — re-check now qs.pop("_pnone_at", None) return redirect(f"/auth/login?prompt=none&next={_quote(request.url, safe='')}") except (ValueError, TypeError): @@ -218,7 +218,6 @@ def create_base_app( if pnone_at and (now - pnone_at) < 300: return - device_id = g.device_id if device_id and redis: cached = await redis.get(f"prompt:{name}:{device_id}") if cached == b"none": diff --git a/infrastructure/oauth.py b/infrastructure/oauth.py index 919c39e..85f51f3 100644 --- a/infrastructure/oauth.py +++ b/infrastructure/oauth.py @@ -61,10 +61,13 @@ def create_oauth_blueprint(app_name: str) -> Blueprint: @bp.get("/callback") @bp.get("/callback/") async def callback(): - # Always store account_did when account passes it back + # Adopt account's device id as our own — one identity across all apps account_did = request.args.get("account_did", "") if account_did: qsession["_account_did"] = account_did + # Overwrite this app's device cookie with account's device id + g.device_id = account_did + g._new_device_id = True # factory after_request will set the cookie # Handle prompt=none error (user not logged in on account) error = request.args.get("error")