gamesheet_sdk.common.auth.tokens module

Token loading, saving, and refreshing.

This module provides functions for managing GameSheet authentication tokens:

  • Loading access and refresh tokens from browser storage state

  • Saving updated tokens back to persistent storage

  • Refreshing expired access tokens using refresh tokens

The token storage mechanism uses a browser storage state file (JSON) that mirrors the structure of Playwright’s persistent context storage. This allows tokens to be shared between headless browser sessions and direct HTTP sessions.

Example:

Load existing tokens and refresh if needed:

gamesheet_sdk.common.auth.tokens.load_access_token(config)[source]

Read the SPA’s access token from the saved browser storage state.

Returns the value of the accessToken localStorage entry for the SPA’s origin (Config.base_url), or None if 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")
Parameters:

config (Config) – Configuration object containing the base URL and browser state path.

Returns:

The access token string if found, otherwise None.

Return type:

str | None

gamesheet_sdk.common.auth.tokens.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 the refreshToken localStorage entry. Used to drive refresh_access_token() and AuthenticatedSession.

Parameters:

config (Config) – Configuration object containing the base URL and browser state path.

Returns:

The refresh token string if found, otherwise None.

Return type:

str | None

gamesheet_sdk.common.auth.tokens.build_token_updates(*, access, refresh, roles)[source]

Build a localStorage-update dict from the present keyword arguments.

Creates a dictionary mapping localStorage keys to token values, including only the tokens that were provided (non-None). This is used internally by save_tokens() to prepare the updates for browser storage.

Example:

updates = build_token_updates(
    access="access_token_value",
    refresh="refresh_token_value",
    roles=None,
)
sorted(updates.keys())
# ['accessToken', 'refreshToken']
Parameters:
  • access (str) – The access token to store (required).

  • refresh (str | None) – The refresh token to store, or None to skip.

  • roles (str | None) – The roles token to store, or None to skip.

Returns:

Dictionary mapping localStorage keys (accessToken, refreshToken, rolesToken) to their values.

Return type:

dict[str, str]

gamesheet_sdk.common.auth.tokens.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 for config.base_url in place, and writes the file back. Only the keys that were passed are written; unspecified ones are left alone. Both BrowserSession and 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 None to leave unchanged.

  • roles (str | None) – The roles token to save, or None to leave unchanged.

gamesheet_sdk.common.auth.tokens.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_URL with Authorization: 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 inside AuthenticatedSession’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:
  • refresh_token (str) – The refresh token to exchange for new tokens.

  • user_agent (str | None) – Optional User-Agent header value for the request.

  • timeout (float) – Request timeout in seconds. Defaults to REFRESH_TIMEOUT_S.

Returns:

Dictionary with keys access, refresh, and roles, each containing the corresponding token string.

Return type:

dict[str, str]

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.