scitex_hub.account.token

Python parity for scitex-hub account token {create,list,revoke}.

Each function thin-wraps the corresponding /api/me/... HTTP endpoint that PR #273 / #274 wired up server-side. The transport is the stdlib requests library — same as the CLI in src/scitex_hub/_cli/_account/_token.py — so behaviour matches the shell-out path 1:1.

Authentication uses scitex_hub.account._auth.resolve_bearer(), which fails loud (RuntimeError) if no token is available rather than silently anonymising the call.

Module Attributes

DEFAULT_SCOPES

Default scopes for a CLI/API-issued token.

Functions

create([name, scopes, user, password, ...])

Mint a new scitex_xxxx API token.

list()

List existing API tokens (never re-shows the secret value).

list_()

List existing API tokens (never re-shows the secret value).

revoke(token_id)

Revoke a single API token by id.

scitex_hub.account.token.DEFAULT_SCOPES: tuple[str, ...] = ('publish',)

Default scopes for a CLI/API-issued token. Mirrors the server-side ALLOWED_CLI_SCOPES allowlist on apps.infra.accounts_app.views.me_token_views.

scitex_hub.account.token.create(name: str = 'scitex-hub-api', scopes: Sequence[str] | None = None, *, user: str | None = None, password: str | None = None, server: str | None = None, request_fn=None) dict[source]

Mint a new scitex_xxxx API token.

POSTs to /api/me/token/. Server-side validates the scope allowlist (currently {"publish"}), rate-limits per-IP + per-username, and uses a constant-time error path so a wrong password is indistinguishable from an unknown user.

Parameters:
  • name – Human-readable name for the token (visible in the UI). Defaults to "scitex-hub-api" so the agent-programmatic path is visually distinct from the CLI default ("scitex-hub-cli").

  • scopes – Iterable of scope strings. Defaults to DEFAULT_SCOPES.

  • user – Username for basic-auth minting. Required when calling create() without an existing cached bearer token (the normal first-time login flow).

  • password – Password for basic-auth minting. Required alongside user.

  • server – Override server URL. Defaults to _auth.resolve_server() (env / cache / scitex.ai).

  • request_fn – Dependency-injection seam for the HTTP transport. When None, uses requests.post directly. Tests pass a hand-rolled fake (see tests/scitex_hub/account/).

Returns:

Dict with token, prefix, scopes, and name.

Raises:
  • ValueErroruser/password missing (no other auth path).

  • RuntimeError – Server rejected the request (bad creds, scope not allowlisted, rate limit, etc.).

Example

>>> from scitex_hub.account import token
>>> token.create(name="ci", scopes=["publish"],
...              user="ywatanabe", password="...")
{'token': 'scitex_...', 'prefix': '...',
 'scopes': ['publish'], 'name': 'ci'}
scitex_hub.account.token.list_() list[dict][source]

List existing API tokens (never re-shows the secret value).

GETs /api/me/tokens/ with the cached bearer token. Useful for answering “is my CI token still active?” without re-minting.

Returns:

List of token-metadata dicts. Each row carries id, name, prefix, scopes, is_active, created_at, and last_used_at — but never the secret token itself (only create ever returns the secret).

Raises:

RuntimeError – No bearer token resolved (_auth.resolve_bearer()) or server returned non-200.

Example

>>> from scitex_hub.account import token
>>> token.list_()
[{'id': 1, 'name': 'cli', 'prefix': 'scitex_abcd',
  'scopes': ['publish'], 'is_active': True, ...}]
scitex_hub.account.token.list() list[dict]

List existing API tokens (never re-shows the secret value).

GETs /api/me/tokens/ with the cached bearer token. Useful for answering “is my CI token still active?” without re-minting.

Returns:

List of token-metadata dicts. Each row carries id, name, prefix, scopes, is_active, created_at, and last_used_at — but never the secret token itself (only create ever returns the secret).

Raises:

RuntimeError – No bearer token resolved (_auth.resolve_bearer()) or server returned non-200.

Example

>>> from scitex_hub.account import token
>>> token.list_()
[{'id': 1, 'name': 'cli', 'prefix': 'scitex_abcd',
  'scopes': ['publish'], 'is_active': True, ...}]
scitex_hub.account.token.revoke(token_id: int) dict[source]

Revoke a single API token by id.

DELETEs /api/me/token/{token_id}/. Server responds 204 on success or 404 if the token doesn’t belong to this user.

Parameters:

token_id – Server-assigned integer id (from list_()).

Returns:

Dict {"success": True, "token_id": <id>} on success.

Raises:

RuntimeError – No bearer token resolved, token not found (404), or any other non-204 response.

Example

>>> from scitex_hub.account import token
>>> token.revoke(7)
{'success': True, 'token_id': 7}
scitex_hub.account.token._handle_create_response(resp: dict) dict[source]

Normalise the /api/me/token/ response into a plain dict.

scitex_hub.account.token._default_post(url: str, body: dict) dict[source]

Default POST transport (used when no request_fn is injected).

Wraps the response in a plain dict so the same shape works for real HTTP and for the hand-rolled test fakes — no requests object leaks across the boundary.

scitex_hub.account.token._wrap(r) dict[source]

Turn a requests.Response into a dict the handlers expect.