Source code for gamesheet_sdk.common.auth.flow

# Copyright (c) 2026 bdperkin
# SPDX-License-Identifier: MIT

"""Login flow protocol for pluggable authentication strategies.

Defines :class:`LoginFlow`, the structural interface that both admin (browser-based) and teams (HTTP-only)
authentication implement. Downstream code that needs to authenticate — CLI commands, session construction
helpers — depends on this protocol rather than on a concrete login function, so the auth mechanism can vary
per pillar without changing the consumer.

Example:
    Using a :class:`LoginFlow` implementation:

    .. code-block:: python

        from gamesheet_sdk.common.auth.flow import LoginFlow
        from gamesheet_sdk.common.auth.tokens import save_tokens
        from gamesheet_sdk.common.config import Config


        def run_login(flow: LoginFlow, config: Config) -> None:
            tokens = flow.authenticate(email="user@example.com")
            save_tokens(config, **tokens)

"""

from __future__ import annotations

from typing import Protocol, runtime_checkable


[docs] @runtime_checkable class LoginFlow(Protocol): """Structural interface for authentication flows. Any class that exposes an ``authenticate`` method with the signature below is a valid :class:`LoginFlow` — no explicit inheritance needed (structural subtyping via :class:`typing.Protocol`). Implementations hold whatever state they need (a :class:`~gamesheet_sdk.common.config.Config`, a :class:`~gamesheet_sdk.common.browser.BrowserSession`, HTTP clients, etc.) and expose only the common ``authenticate`` entry point. The returned dict contains at minimum ``"access"`` and ``"refresh"`` keys. Admin flows may also include ``"roles"``. The shape matches :func:`~gamesheet_sdk.common.auth.tokens.refresh_access_token`'s return value and can be unpacked directly into :func:`~gamesheet_sdk.common.auth.tokens.save_tokens`. """
[docs] def authenticate( self: LoginFlow, email: str | None = None, password: str | None = None, *, timeout: float | None = None, ) -> dict[str, str]: """Authenticate with the GameSheet platform and return tokens. Credential resolution follows a standard fallback chain: explicit arguments → ``GAMESHEET_USERNAME`` / ``GAMESHEET_PASSWORD`` env vars → :class:`~gamesheet_sdk.common.config.Config` fields. Implementations raise :class:`~gamesheet_sdk.common.exceptions.AuthenticationError` when credentials are missing or authentication is rejected. Args: email (str | None): Login email, or ``None`` to resolve from config/env. password (str | None): Login password, or ``None`` to resolve from config/env. timeout (float | None): Auth round-trip timeout in seconds, or ``None`` for the implementation's default. Returns: dict[str, str]: Token bundle with at least ``"access"`` and ``"refresh"`` keys. """ _ = (self, email, password, timeout) return {}