gamesheet_sdk.common.auth¶
Authentication flows and token management for GameSheet.
Functions
|
Extract a human-readable error string from a Firebase Auth response body. |
|
Read the SPA's access token from the saved browser storage state. |
|
Read the SPA's refresh token from the saved browser storage state. |
|
Log into the GameSheet dashboard, leaving the session authenticated. |
|
Exchange refresh_token for a fresh {access, refresh, roles} bundle. |
|
Resolve the login email from explicit argument or config. |
|
Resolve the login password from explicit argument or config. |
|
Persist new token values back into the saved browser storage state. |
Classes
Browser-based |
|
Admin-pillar session that refreshes via the admin token endpoint. |
|
Abstract base for sessions that auto-refresh their bearer on 401 or 403. |
|
Structural interface for authentication flows. |
- class gamesheet_sdk.common.auth.AdminLoginFlow[source]¶
Bases:
objectBrowser-based
LoginFlowfor the admin dashboard.Wraps the headless-browser
login()flow in a class that conforms to theLoginFlowprotocol. After the browser session closes (persisting localStorage to disk), the access and refresh tokens are read back and returned so callers can use them without touching the state file directly.Example:
from gamesheet_sdk.common.auth.login import AdminLoginFlow from gamesheet_sdk.common.config import Config config = Config() flow = AdminLoginFlow(config) tokens = flow.authenticate(email="user@example.com") print(tokens["access"])
Store the configuration for later browser-session creation.
- Parameters:
config (Config) – SDK configuration (credentials, URLs, storage paths).
- __init__(config)[source]¶
Store the configuration for later browser-session creation.
- Parameters:
config (Config) – SDK configuration (credentials, URLs, storage paths).
- authenticate(email=None, password=None, *, timeout=None)[source]¶
Run the browser-based admin login and return tokens.
Opens a
BrowserSession, drives the Firebase login form vialogin(), and reads the persisted tokens from the saved browser state file.- Parameters:
- Returns:
Token bundle with
"access"and"refresh"keys.- Return type:
- Raises:
AuthenticationError – If credentials are missing, the auth backend rejects them, or tokens are not found in the saved state after login.
- class gamesheet_sdk.common.auth.AuthenticatedSession[source]¶
Bases:
BaseAuthenticatedSessionAdmin-pillar session that refreshes via the admin token endpoint.
Delegates to
refresh_access_token(), forwarding the session’sUser-Agentheader so the admin gateway can log the calling client.Example:
from gamesheet_sdk.common.auth import load_access_token, load_refresh_token, save_tokens from gamesheet_sdk.common.auth.session import AuthenticatedSession from gamesheet_sdk.admin.associations import list_associations from gamesheet_sdk.common.config import Config config = Config() with AuthenticatedSession( config, access_token=load_access_token(config), refresh_token=load_refresh_token(config), on_refresh=lambda tokens: save_tokens(config, **tokens), ) as s: for assoc in list_associations(s): print(assoc.name)
Initialize an authenticated session with token auto-refresh on 401/403.
- Parameters:
config (Config | None) – Optional configuration object. If
None, a defaultConfigis created.access_token (str) – Current access token to use as the bearer in the
Authorizationheader.refresh_token (str) – Refresh token used to renew the access token on 401/403 responses.
on_refresh (OnRefreshCallback | None) – Optional callback invoked with a token dict after a successful token refresh. Use this to persist the new tokens to disk (e.g. via
save_tokens()).
- __init__(config=None, *, access_token, refresh_token, on_refresh=None)¶
Initialize an authenticated session with token auto-refresh on 401/403.
- Parameters:
config (Config | None) – Optional configuration object. If
None, a defaultConfigis created.access_token (str) – Current access token to use as the bearer in the
Authorizationheader.refresh_token (str) – Refresh token used to renew the access token on 401/403 responses.
on_refresh (OnRefreshCallback | None) – Optional callback invoked with a token dict after a successful token refresh. Use this to persist the new tokens to disk (e.g. via
save_tokens()).
- close()¶
Persist cookies and release the underlying HTTP connection pool.
- property cookies: RequestsCookieJar¶
Underlying cookie jar.
Mutating this affects subsequent requests. :returns: Return value. :rtype: RequestsCookieJar
- delete(url, **kwargs)¶
Send a DELETE request.
See
request(). :param url: Absolute URL, or a path relative toConfig.base_url. :type url: str :param kwargs: Additional keyword arguments forwarded torequest(). :type kwargs: Any :returns: Return value. :rtype: requests.Response- Return type:
- get(url, **kwargs)¶
Send a GET request.
See
request(). :param url: Absolute URL, or a path relative toConfig.base_url. :type url: str :param kwargs: Additional keyword arguments forwarded torequest(). :type kwargs: Any :returns: Return value. :rtype: requests.Response- Return type:
- property headers: MutableMapping[str, str | bytes]¶
Default headers attached to every request from this session.
The underlying mapping is a case-insensitive dict (as supplied by
requests.Session), but the declared return type matches the stub forrequests.Session.headers. :returns: Return value. :rtype: MutableMapping[str, str | bytes]
- patch(url, **kwargs)¶
Send a PATCH request.
See
request(). :param url: Absolute URL, or a path relative toConfig.base_url. :type url: str :param kwargs: Additional keyword arguments forwarded torequest(). :type kwargs: Any :returns: Return value. :rtype: requests.Response- Return type:
- post(url, **kwargs)¶
Send a POST request.
See
request(). :param url: Absolute URL, or a path relative toConfig.base_url. :type url: str :param kwargs: Additional keyword arguments forwarded torequest(). :type kwargs: Any :returns: Return value. :rtype: requests.Response- Return type:
- put(url, **kwargs)¶
Send a PUT request.
See
request(). :param url: Absolute URL, or a path relative toConfig.base_url. :type url: str :param kwargs: Additional keyword arguments forwarded torequest(). :type kwargs: Any :returns: Return value. :rtype: requests.Response- Return type:
- request(method, url, *, timeout=None, **kwargs)¶
Send a request, refreshing the bearer and retrying once on 401 or 403.
- Parameters:
- Returns:
HTTP response object from the request. If token refresh fails, returns the original 401/403 response without raising an exception.
- Return type:
- save()¶
Persist the current cookie state to
Config.session_path.The on-disk format preserves the full cookie attribute set (
domain,path,secure,expires) so that reloaded cookies are sent against the correct scopes.
- set_bearer_token(token)¶
Attach
Authorization: Bearer <token>to all subsequent requests.Convenience for
s.headers["Authorization"] = f"Bearer {token}". :param token: The bearer token to attach :type token: str
- class gamesheet_sdk.common.auth.BaseAuthenticatedSession[source]¶
-
Abstract base for sessions that auto-refresh their bearer on 401 or 403.
Subclasses provide
_do_refresh()to perform the actual token refresh HTTP call against their pillar’s endpoint. Everything else — constructor, retry logic, callback notification — is shared.On any 401 or 403 response the session calls
_do_refresh(), updates its bearer, optionally invokeson_refreshwith the new token bundle, and retries the original request once. Both 401 and 403 are treated as authentication failures because different GameSheet API endpoints use different status codes for expired tokens. If the refresh itself fails the original response propagates to the caller.Initialize an authenticated session with token auto-refresh on 401/403.
- Parameters:
config (Config | None) – Optional configuration object. If
None, a defaultConfigis created.access_token (str) – Current access token to use as the bearer in the
Authorizationheader.refresh_token (str) – Refresh token used to renew the access token on 401/403 responses.
on_refresh (OnRefreshCallback | None) – Optional callback invoked with a token dict after a successful token refresh. Use this to persist the new tokens to disk (e.g. via
save_tokens()).
- __init__(config=None, *, access_token, refresh_token, on_refresh=None)[source]¶
Initialize an authenticated session with token auto-refresh on 401/403.
- Parameters:
config (Config | None) – Optional configuration object. If
None, a defaultConfigis created.access_token (str) – Current access token to use as the bearer in the
Authorizationheader.refresh_token (str) – Refresh token used to renew the access token on 401/403 responses.
on_refresh (OnRefreshCallback | None) – Optional callback invoked with a token dict after a successful token refresh. Use this to persist the new tokens to disk (e.g. via
save_tokens()).
- request(method, url, *, timeout=None, **kwargs)[source]¶
Send a request, refreshing the bearer and retrying once on 401 or 403.
- Parameters:
- Returns:
HTTP response object from the request. If token refresh fails, returns the original 401/403 response without raising an exception.
- Return type:
- close()¶
Persist cookies and release the underlying HTTP connection pool.
- property cookies: RequestsCookieJar¶
Underlying cookie jar.
Mutating this affects subsequent requests. :returns: Return value. :rtype: RequestsCookieJar
- delete(url, **kwargs)¶
Send a DELETE request.
See
request(). :param url: Absolute URL, or a path relative toConfig.base_url. :type url: str :param kwargs: Additional keyword arguments forwarded torequest(). :type kwargs: Any :returns: Return value. :rtype: requests.Response- Return type:
- get(url, **kwargs)¶
Send a GET request.
See
request(). :param url: Absolute URL, or a path relative toConfig.base_url. :type url: str :param kwargs: Additional keyword arguments forwarded torequest(). :type kwargs: Any :returns: Return value. :rtype: requests.Response- Return type:
- property headers: MutableMapping[str, str | bytes]¶
Default headers attached to every request from this session.
The underlying mapping is a case-insensitive dict (as supplied by
requests.Session), but the declared return type matches the stub forrequests.Session.headers. :returns: Return value. :rtype: MutableMapping[str, str | bytes]
- patch(url, **kwargs)¶
Send a PATCH request.
See
request(). :param url: Absolute URL, or a path relative toConfig.base_url. :type url: str :param kwargs: Additional keyword arguments forwarded torequest(). :type kwargs: Any :returns: Return value. :rtype: requests.Response- Return type:
- post(url, **kwargs)¶
Send a POST request.
See
request(). :param url: Absolute URL, or a path relative toConfig.base_url. :type url: str :param kwargs: Additional keyword arguments forwarded torequest(). :type kwargs: Any :returns: Return value. :rtype: requests.Response- Return type:
- put(url, **kwargs)¶
Send a PUT request.
See
request(). :param url: Absolute URL, or a path relative toConfig.base_url. :type url: str :param kwargs: Additional keyword arguments forwarded torequest(). :type kwargs: Any :returns: Return value. :rtype: requests.Response- Return type:
- save()¶
Persist the current cookie state to
Config.session_path.The on-disk format preserves the full cookie attribute set (
domain,path,secure,expires) so that reloaded cookies are sent against the correct scopes.
- set_bearer_token(token)¶
Attach
Authorization: Bearer <token>to all subsequent requests.Convenience for
s.headers["Authorization"] = f"Bearer {token}". :param token: The bearer token to attach :type token: str
- class gamesheet_sdk.common.auth.LoginFlow[source]¶
Bases:
ProtocolStructural interface for authentication flows.
Any class that exposes an
authenticatemethod with the signature below is a validLoginFlow— no explicit inheritance needed (structural subtyping viatyping.Protocol).Implementations hold whatever state they need (a
Config, aBrowserSession, HTTP clients, etc.) and expose only the commonauthenticateentry point.The returned dict contains at minimum
"access"and"refresh"keys. Admin flows may also include"roles". The shape matchesrefresh_access_token()’s return value and can be unpacked directly intosave_tokens().- authenticate(email=None, password=None, *, timeout=None)[source]¶
Authenticate with the GameSheet platform and return tokens.
Credential resolution follows a standard fallback chain: explicit arguments →
GAMESHEET_USERNAME/GAMESHEET_PASSWORDenv vars →Configfields. Implementations raiseAuthenticationErrorwhen credentials are missing or authentication is rejected.- Parameters:
- Returns:
Token bundle with at least
"access"and"refresh"keys.- Return type:
- Raises:
AuthenticationError – If credentials are missing or the auth backend rejects them.
- __init__(*args, **kwargs)¶
- gamesheet_sdk.common.auth.extract_firebase_error(body, status)[source]¶
Extract a human-readable error string from a Firebase Auth response body.
Firebase returns
{"error": {"code": N, "message": "CODE_NAME", ...}}; themessageis a stable identifier likeEMAIL_NOT_FOUNDthat we surface verbatim so callers can react programmatically.
- gamesheet_sdk.common.auth.load_access_token(config)[source]¶
Read the SPA’s access token from the saved browser storage state.
Returns the value of the
accessTokenlocalStorage entry for the SPA’s origin (Config.base_url), orNoneif the storage state file is missing, unreadable, or does not contain a token. The access token is used for authenticating API requests and typically has a short lifetime (10 minutes).Example:
from gamesheet_sdk.common.auth.tokens import load_access_token from gamesheet_sdk.common.config import Config config = Config() token = load_access_token(config) if token: print("Access token loaded successfully")
- gamesheet_sdk.common.auth.load_refresh_token(config)[source]¶
Read the SPA’s refresh token from the saved browser storage state.
Companion to
load_access_token(). Returns the value of therefreshTokenlocalStorage entry. Used to driverefresh_access_token()andAuthenticatedSession.
- gamesheet_sdk.common.auth.login(session, email=None, password=None, *, timeout=None, post_login_path='/associations')[source]¶
Log into the GameSheet dashboard, leaving the session authenticated.
Success is determined by:
HTTP 200 from the Firebase signInWithPassword call, and
HTTP 200 from the subsequent
/api/tokenexchange.
On failure the Firebase error.message (e.g.
EMAIL_NOT_FOUND,INVALID_LOGIN_CREDENTIALS,TOO_MANY_ATTEMPTS_TRY_LATER) is surfaced verbatim in the raisedAuthenticationErrorso callers know exactly what was wrong.- Parameters:
session (BrowserSession) – An open
BrowserSession.email (str | None) – Login email; falls back to
session.config.username.password (str | None) – Login password; falls back to
session.config.password.get_secret_value().timeout (float | None) – Seconds to wait for the auth backend round-trip (default 15).
post_login_path (str | None) – Path to navigate to after the auth round-trip succeeds. The SPA performs its real routing and post-login data fetches when it reaches this page, so the saved storage state afterwards captures a fully-settled session (cookies + any SPA-cached state) rather than just the bare auth cookie. Pass
Noneto skip the post-login navigation entirely. Default isPOST_LOGIN_PATH.
- Raises:
AuthenticationError – If authentication fails (missing credentials, Firebase rejection, token exchange failure, or timeout).
- gamesheet_sdk.common.auth.refresh_access_token(refresh_token, *, user_agent=None, timeout=30.0)[source]¶
Exchange refresh_token for a fresh {access, refresh, roles} bundle.
POSTs to
REFRESH_URLwithAuthorization: Bearer <refresh_token>and an empty JSON body. The gateway returns a new access token (10-min TTL), a new refresh token (long TTL, replaces the one you sent), and a roles token.This is a standalone HTTP call that does not use a
Session, so it can be used from insideAuthenticatedSession’s retry path without recursing.Example:
Refresh an expired access token:
from gamesheet_sdk.common.auth.tokens import ( load_refresh_token, refresh_access_token, save_tokens, ) from gamesheet_sdk.common.config import Config config = Config() refresh = load_refresh_token(config) if refresh: try: tokens = refresh_access_token(refresh) save_tokens( config, access=tokens["access"], refresh=tokens["refresh"], roles=tokens["roles"], ) except AuthenticationError: print("Refresh token expired, please log in again")
- Parameters:
- Returns:
Dictionary with keys
access,refresh, androles, each containing the corresponding token string.- Return type:
- Raises:
AuthenticationError – If the refresh token is rejected (HTTP 401). This typically means the token has expired and the user needs to re-authenticate via
gamesheet-admin login.GameSheetError – For any other non-2xx HTTP response from the token refresh endpoint.
- gamesheet_sdk.common.auth.resolve_email(cfg, email)[source]¶
Resolve the login email from explicit argument or config.
Falls through: explicit
emailargument →GAMESHEET_USERNAMEenv var →Config.username.- Parameters:
- Returns:
The resolved email address.
- Return type:
- Raises:
AuthenticationError – If no email is available from any source.
- gamesheet_sdk.common.auth.resolve_password(cfg, password)[source]¶
Resolve the login password from explicit argument or config.
Falls through: explicit
passwordargument →GAMESHEET_PASSWORDenv var →Config.password.- Parameters:
- Returns:
The resolved password string.
- Return type:
- Raises:
AuthenticationError – If no password is available from any source.
- gamesheet_sdk.common.auth.save_tokens(config, *, access, refresh=None, roles=None)[source]¶
Persist new token values back into the saved browser storage state.
Reads
Config.browser_state_path(or starts with an empty state if it is missing or malformed), updates the localStorage entries forconfig.base_urlin place, and writes the file back. Only the keys that were passed are written; unspecified ones are left alone. BothBrowserSessionand direct token loading use this same storage format, making them mutually compatible.Example:
Save tokens after a successful refresh:
from gamesheet_sdk.common.config import Config from gamesheet_sdk.common.auth.tokens import save_tokens config = Config() save_tokens( config, access="new_access_token", refresh="new_refresh_token", roles="roles_token", )
- Parameters:
config (Config) – Configuration object containing the base URL and browser state path where tokens will be saved.
access (str) – The access token to save (required).
refresh (str | None) – The refresh token to save, or
Noneto leave unchanged.roles (str | None) – The roles token to save, or
Noneto leave unchanged.