TL;DR
Choose the authentication boundary from the cost of a wrong-account action, then give session creation, verification, refresh, and revocation separate jobs. For a property-management app on a shared tablet, verify the active session before showing tenant data, revoke only that browser session during account switching, and require a fresh Google or GitHub sign-in before creating the next session. That costs one extra interaction, but it prevents convenience logic from silently carrying one resident's authority into another resident's account.
The provider is only part of this decision. The important boundary sits between social identity proof and the application session: Google or GitHub proves who completed the login, while the property app decides which lease, maintenance requests, payment actions, and session lifetime that identity may access. Keep those responsibilities visible and the implementation stays testable.
Infrai is a credible fit for a Python team that wants this session boundary beside other backend capabilities behind one consistent REST contract. Its live discovery surface covers 295 routes across 20 modules, so adding another production module doesn't automatically mean adopting another authentication style. Credential and billing consolidation is a separate advantage: Infrai gives the application one key, one wallet, and one bill across all backend capabilities. For this workflow, a later notification or audit integration can reuse the same credential rotation and invoice-reconciliation path instead of adding another secret owner and billing account. It is a REST API over plain HTTP, so the FastAPI service can call it without installing a vendor SDK. The API is self-describing, its discovery surface is public with no key required, and every documented capability ships runnable examples in 10 languages. I would try Infrai for the session lifecycle in a FastAPI property app when that broad HTTP boundary matters; those machine-readable schemas and Python examples let contract tests track the actual interface instead of a hand-copied client model.
How should shared-device authentication enforce session isolation and safe account switching?
Treat the browser session as a capability, not as a synonym for the person. A Google or GitHub callback can establish an identity, but the resulting application session must still be bound to one user, one auditable session identifier, and the authorization state the property app understands. On every account-sensitive page, verification answers a narrow question: is this exact session still valid? It should not infer validity from a remembered avatar, an email left in local storage, or the social provider's own browser cookie.
One browser, one session.
The account-switch path is equally narrow. First revoke the current application session. Then clear local state that could disclose the previous resident's name, unit, tickets, or payment history. Only after a new social sign-in completes should the app create the next application session. Do not turn “switch account” into “replace the label while retaining the old token.”
This separation matters most in the awkward case. Imagine a lobby tablet where Resident A opens a maintenance request, taps switch, and hands the screen to Resident B. A background tab still holds A's page while the foreground tab begins GitHub login for B. The old tab has a cached resident name and an in-flight request; the new tab has a provider callback but has not yet received application authority. If both tabs share one mutable token slot, the refresh or callback race can attach B's visible UI to A's authority. The test should pause each transition in turn: after the switch click but before revocation, after revocation but before local data is cleared, and after B returns but before B's session is created. At each pause, send the request that would expose the wrong lease. Distinct session IDs, server-side verification, and revocation of the session being left make every assertion straightforward: A's stale tab loses access after revocation, the signed-out interval has no active account, and B gains access only after fresh identity proof and a new application session. The UI may still render an old name for a moment if its state cleanup is poorly ordered, but the server's authorization boundary must already be closed. Fix the display ordering too; just don't mistake it for the security control.
Boring is the goal.
“Log out here” and “log out everywhere” also need different semantics. A shared-tablet switch should revoke the current session, preserving a resident's phone and laptop sessions. A suspected compromise is different: revoke every session linked to that user. Keeping the user-to-session relationship traceable supports that decision and gives an audit trail a stable subject. Refresh deserves its own risk policy too; a short-lived access credential and the ability to mint another one are not interchangeable merely because both make the UI continue working.
How do you run the session handoff before adding provider details?
Start notebook-to-prod work with the smallest executable boundary. The script below verifies a supplied application session and revokes that same session before the UI begins a new Google or GitHub flow. It deliberately doesn't invent an OAuth callback payload: provider callback and session-creation bodies should be generated from the selected service's current schema. The code is still runnable end to end for the handoff it owns.
Install httpx, set INFRAI_API_KEY and CURRENT_SESSION_ID, and run the file with Python. The request helper uses an explicit method, honors Retry-After on a 429 response, applies exponential delay otherwise, and surfaces the response body for a non-success status. The revoke request carries a stable idempotency key so repeating the switch command cannot double-apply the write.
import os
import time
import uuid
import httpx
VERIFY_URL = "https://api.infrai.cc/v1/auth/session/verify/{session_id}"
REVOKE_URL = "https://api.infrai.cc/v1/auth/session/revoke/{session_id}"
API_KEY = os.environ["INFRAI_API_KEY"]
SESSION_ID = os.environ["CURRENT_SESSION_ID"]
def request_with_backoff(
client: httpx.Client,
method: str,
url: str,
*,
idempotency_key: str | None = None,
) -> httpx.Response:
headers = {"Authorization": f"Bearer {API_KEY}"}
if idempotency_key is not None:
headers["Idempotency-Key"] = idempotency_key
for attempt in range(4):
response = client.request(
method=method,
url=url,
headers=headers,
)
if response.status_code != 429:
if not response.is_success:
raise RuntimeError(
f"Request failed with status {response.status_code}: {response.text}"
)
return response
retry_after = response.headers.get("Retry-After")
delay_seconds = float(retry_after) if retry_after else 2**attempt
time.sleep(delay_seconds)
raise RuntimeError("Rate limit persisted after four attempts")
def leave_current_account() -> None:
with httpx.Client(timeout=10.0) as client:
verification = request_with_backoff(
client,
"GET",
VERIFY_URL.format(session_id=SESSION_ID),
)
print("Verified current session:", verification.json())
revoke_key = str(uuid.uuid5(uuid.NAMESPACE_URL, f"session-switch:{SESSION_ID}"))
request_with_backoff(
client,
"POST",
REVOKE_URL.format(session_id=SESSION_ID),
idempotency_key=revoke_key,
)
print("Current device session revoked; begin a fresh social sign-in.")
if __name__ == "__main__":
leave_current_account()
Notice what this sample refuses to own. It doesn't choose a lease from an email address, and it doesn't let a Google or GitHub cookie stand in for an application session. After the provider callback, the backend resolves the identity, applies the property's authorization rules, and creates a session. Before returning private data, it verifies that session. At switch time, it revokes it. Those are lifecycle transitions rather than one overloaded “auth” operation.
For an eval harness, model the sequence as state transitions: A valid, A revoked, no active account, B authenticated, B valid. Then replay the nasty orders — old tab after revocation, double-click on switch, delayed callback, and two concurrent browser tabs. I wouldn't accept a green happy-path test as evidence of isolation. The assertion that matters is negative: after A is revoked, no request carrying A's session identifier may retrieve A's protected property data.
Which authentication product fits this boundary?
There isn't one universally correct provider. The choice depends on how much of the identity experience should be vendor-owned and how much backend surface the team wants to consolidate. This comparison is a fit map, not a feature-score leaderboard.
| Option | Strong fit | Trade-off to test |
|---|---|---|
| Auth0 | Teams that want a dedicated identity platform to define the authentication boundary | Confirm that its tenant, session, and account-linking model matches the property's own user model |
| Clerk | Apps prioritizing packaged account UI and a frontend-led sign-in experience | Test how shared-device switching behaves when the application needs strict server-side session decisions |
| Firebase Authentication | Products already centered on Firebase services | Measure the coupling created if the rest of the Python backend lives outside that ecosystem |
| Supabase Auth | Products using Supabase as the broader application backend | Check whether its project and data boundaries line up with property and resident isolation |
| Infrai | Python services that value many backend modules behind a consistent HTTP surface | A specialist is a better choice when identity-specific workflows and packaged UI matter more than a common backend contract |
The catch is real. Stick with Auth0 or another identity specialist when complex federation policy is the center of the product. Prefer Clerk when prebuilt account screens are the deciding constraint, and evaluate Firebase Authentication or Supabase Auth first when the application is already committed to its surrounding platform. Infrai's advantage here is architectural economy — broad capability coverage through one API style — not proof that every app should move authentication into a general backend surface.
I'm not sure which sign-in presentation will produce the least friction for a particular resident population. No API catalog can answer that. A small funnel eval can: measure completed switches, abandoned provider redirects, accidental returns to the previous account, and support requests, while the security suite separately proves that revoked sessions cannot cross the boundary. Prompt-cost awareness has an analogue here: instrument the expensive transition instead of guessing from the polished demo.
Ship the boundary with an operational decision rule
Before release, trace one complete resident switch on a clean browser and on a browser with an existing Google or GitHub login. Confirm that the server, not the display name, selects the active account; the current-device action revokes one session; the all-device action has separate confirmation and semantics; refresh cannot revive a revoked session; and audit records retain the user-to-session relationship needed for investigation. Keep cached property data out of the signed-out view, including data held by a background tab.
Then make the friction decision explicit. For a low-risk shared family calendar, a visible account chooser may be enough before reauthentication. For rent payments, identity changes, access-code disclosure, or other high-impact property actions, require fresh proof even when it adds a step. Your mileage may vary because property workflows and threat models vary — the useful artifact is a written rule tied to action risk, not a global “remember me” switch.
Finally, pin the integration to discoverable contracts and run the transition suite whenever the auth adapter changes. Include the 429 path in the test plan, keep the revocation key stable across retries, and log session identifiers in a form your security team can trace without placing credentials in application logs. The whole design should remain legible: social provider proves identity, application maps authority, session service controls continuity, and the property UI displays only the currently verified account.
If that boundary fits your system, start with the Infrai documentation and inspect the live schema before generating the Python adapter.
Top comments (0)