Skip to main content

altium-auth (Python)

PyPI Python CI license

Altium 365 OAuth2 / OpenID Connect authentication for Python. Supports both client types across Commercial Cloud, GovCloud, and AES (on-prem):

  • Public clients (desktop, native) — browser sign-in with PKCE over Altium's ActionWait long-poll: AltiumAuthClient.sign_in.
  • Confidential clients (web/server backends) — the standard authorization-code redirect flow: create_authorization_url + exchange_code.
  • Workspace tokens, refresh, revocation, and first-class GovCloud + AES support.

Zero runtime dependencies (stdlib only). Python 3.10+.

Documentation

The library implements the protocol described in the language-neutral guides (start here if you're new to Altium Identity):

Installation

pip install altium-auth

Quick start

Construct an AltiumAuthClient once with an AltiumAuthConfig. Only client_id and scopes are required — endpoints default to the Commercial Cloud.

Public apps (desktop — ActionWait sign-in)

from altium_auth import AltiumAuthClient, AltiumAuthConfig

client = AltiumAuthClient(AltiumAuthConfig(client_id="your-client-id", scopes="openid profile"))

# Opens a browser login page and waits for the callback.
tokens = client.sign_in()

# Persist `tokens` yourself — a keyring, an OS credential store, or a file.
workspace = client.sign_into_workspace(tokens.access_token, "workspace-id-here")

Provide a custom browser opener (e.g. an IDE/host bridge) via config; the library still owns PKCE, ActionWait polling, state correlation, CSRF validation, and the token exchange:

config = AltiumAuthConfig(
    client_id="your-client-id",
    scopes="openid profile",
    open_browser=lambda url: my_host.open_external(url),
)

Confidential apps (web / server — authorization-code redirect)

from altium_auth import AltiumAuthClient, AltiumAuthConfig

client = AltiumAuthClient(
    AltiumAuthConfig(
        client_id="your-client-id",
        client_secret="your-client-secret",  # confidential client → HTTP Basic
        scopes="openid profile offline_access",
    )
)
redirect_uri = "https://my-service.example.com/oauth/callback"

# On your login route: build the URL, stash state + verifier, then redirect.
req = client.create_authorization_url(redirect_uri=redirect_uri)
session["oauth"] = {"state": req.state, "code_verifier": req.code_verifier}
# redirect(req.url)

# On your callback route: verify state, then exchange the code.
if request.args["state"] != session["oauth"]["state"]:
    raise ValueError("state mismatch")
tokens = client.exchange_code(
    request.args["code"],
    code_verifier=session["oauth"]["code_verifier"],
    redirect_uri=redirect_uri,
)

GovCloud

from altium_auth import AltiumAuthClient, AltiumAuthConfig, GOV_CLOUD_ENDPOINTS

client = AltiumAuthClient(
    AltiumAuthConfig(
        client_id="your-gov-client-id",
        scopes="openid profile",
        endpoints=GOV_CLOUD_ENDPOINTS,
    )
)
tokens = client.sign_in()  # secure=1 is added to token requests automatically

AES (on-prem)

from altium_auth import AltiumAuthClient, AltiumAuthConfig, aes_endpoints

endpoints = aes_endpoints("https://aes.server.example:9785")
scopes = AltiumAuthClient.get_client_scopes(endpoints.scope_endpoint, "your-aes-client-id")
client = AltiumAuthClient(
    AltiumAuthConfig(
        client_id="your-aes-client-id",
        scopes=" ".join(scopes),
        endpoints=endpoints,
    )
)
tokens = client.sign_in()

Using from async code

The library is synchronous. From an event loop, bridge with the stdlib:

import asyncio

tokens = await asyncio.to_thread(client.refresh_token, refresh_token)

API reference

Method Description
create_authorization_url(*, redirect_uri=None, state=None, code_verifier=None, scopes=None, select_workspace=WorkspaceSelection.NONE) Build a PKCE authorization URL (no I/O). Returns AuthorizationRequest(url, state, code_verifier).
exchange_code(code, *, code_verifier=None, redirect_uri=None, timeout=30.0) Authorization-code grant → TokenSet.
sign_in(*, select_workspace=WorkspaceSelection.NONE, timeout=180.0) Full ActionWait sign-in → TokenSet.
sign_into_workspace(base_access_token, workspace_auth_id, *, timeout=30.0) RFC 8693 workspace exchange → TokenSet.
refresh_token(refresh_token, *, timeout=30.0) Refresh grant (no scope resent) → TokenSet.
revoke_refresh_token(refresh_token, *, timeout=30.0) RFC 7009 revocation (idempotent).
AltiumAuthClient.get_client_scopes(scope_endpoint, client_id, *, timeout=30.0) Static; scope introspection → list[str].

Types

  • AltiumAuthConfig(client_id, scopes, client_secret=None, endpoints=COMMERCIAL_CLOUD_ENDPOINTS, secure=None, open_browser=None) — properties is_confidential, use_secure.
  • AltiumEndpoints(authorize_endpoint, token_endpoint, action_wait_endpoint, redirect_uri, scope_endpoint=None) — constants COMMERCIAL_CLOUD_ENDPOINTS, GOV_CLOUD_ENDPOINTS; factory aes_endpoints(origin).
  • TokenSet(access_token, token_type, expires_in, expires_at, refresh_token, id_token, scope) — expires_at computed with a 30 s clock-skew buffer.
  • WorkspaceSelection — NONE / STRICT / OPTIONAL.

access_token is a signed JWT — decode it to read iss, workspaceId, secure, and scopes. See Access token claims.

Error handling

All errors subclass AltiumAuthError:

Class When
ConfigurationError Missing client_id/scopes, invalid endpoint URL, or empty required argument.
OAuthError Token/revocation/scope endpoint returned a non-success status (carries .status, .error, .error_description).
ActionWaitError ActionWait timed out, was cancelled (410), or returned an unusable body.
StateMismatchError Returned state ≠ wait token (CSRF guard). Subclass of ActionWaitError.
TransportError Network-level failure.
TlsError TLS/certificate failure. Subclass of TransportError.

Development

uv sync --extra dev
uv run pytest            # unit + conformance
uv run ruff check .
uv run mypy
uv build

Live E2E sign-in

uv run python tools/signin_test.py YOUR_CLIENT_ID
uv run python tools/signin_test.py --env gov YOUR_GOV_CLIENT_ID
uv run python tools/signin_test.py --env aes --aes-origin https://aes.server.example:9785 YOUR_AES_CLIENT_ID

Security

Report vulnerabilities privately — see SECURITY.md.

License

MIT © Altium Limited

Metadata

Release files for altium-auth 0.2.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for altium-auth 0.2.1
File Size Uploaded Provenance Actions
altium_auth-0.2.1.tar.gz 12.0 kB With provenance Details for altium_auth-0.2.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for altium-auth 0.2.1
File Interpreter ABI Platform Actions
altium_auth-0.2.1-py3-none-any.whl Python 3 none any Details for altium_auth-0.2.1-py3-none-any.whl

Total release size: 26.7 kB

Release files / altium_auth-0.2.1.tar.gz

Download URL altium_auth-0.2.1.tar.gz
Size 12.0 kB
Tags Source
SHA-256 checksum
How to use checksums
3d44b2aee72e577c48e7ac70abfcd9898a28b337faadb0cfbae4952c98628609
BLAKE2b-256 checksum
How to use checksums
ca809aa0c186d52d3d4ef8442cbae07962403f7c2b8fa32b44b2ec265db62dcb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 7, 2026.

Transparency log

Release files / altium_auth-0.2.1-py3-none-any.whl

Download URL altium_auth-0.2.1-py3-none-any.whl
Size 14.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f7e4de1a4f343e86cf9fab7e14393f40225a94282aa967dd0dece05c6e9a4212
BLAKE2b-256 checksum
How to use checksums
1bb36adb9b89a8eefc197e374fbb85880e837541875d316cf2f44c106d21c37f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 7, 2026.

Transparency log

Security for altium-auth 0.2.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for altium_auth-0.2.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 7, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.2.1 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page