Skip to main content

hypershub-sso

Typed synchronous and asynchronous OAuth 2.0 / OpenID Connect client for HypersHub SSO. It implements Authorization Code + PKCE for Python backends and BFFs, verifies ID Tokens, and manages refreshable server-side sessions.

Use this package only in a trusted Python server. Never expose the OAuth client secret, PKCE verifier, authorization code, access token, or refresh token to browser code.

Requirements

  • Python 3.11 or newer
  • An SSO client registration with an exact HTTPS redirect URI
  • A server-side session store such as Redis, Valkey, or a database
  • A high-entropy opaque browser session identifier in a host-only HttpOnly; Secure; SameSite=Lax cookie

Install

python -m pip install hypershub-sso

Synchronous client

Use SsoClient with Flask, Django, or another synchronous application:

import os

from hypershub_sso import (
    KeyValueStore,
    SsoClient,
    create_encrypted_session_store,
)


class RedisStore(KeyValueStore):
    def get(self, key: str) -> str | None:
        value = redis.get(key)
        return value.decode() if value is not None else None

    def set(self, key: str, value: str, ttl_seconds: int) -> None:
        redis.set(key, value, ex=ttl_seconds)

    def delete(self, key: str) -> None:
        redis.delete(key)


session_store = create_encrypted_session_store(
    RedisStore(),
    os.environ["SSO_SESSION_ENCRYPTION_KEY"],
)

sso = SsoClient(
    issuer="https://main.example.com/sso",
    client_id=os.environ["SSO_CLIENT_ID"],
    client_secret=os.environ["SSO_CLIENT_SECRET"],
    redirect_uri="https://project.example.com/auth/callback",
    store=session_store,
)

Asynchronous client

Use AsyncSsoClient with FastAPI, Starlette, Quart, or another asyncio application. The raw store methods must also be async:

from hypershub_sso import (
    AsyncSsoClient,
    create_async_encrypted_session_store,
)

session_store = create_async_encrypted_session_store(
    async_redis_store,
    os.environ["SSO_SESSION_ENCRYPTION_KEY"],
)

sso = AsyncSsoClient(
    issuer="https://main.example.com/sso",
    client_id=os.environ["SSO_CLIENT_ID"],
    client_secret=os.environ["SSO_CLIENT_SECRET"],
    redirect_uri="https://project.example.com/auth/callback",
    store=session_store,
)

Close a client during application shutdown with sso.close() or await sso.aclose(). A caller-supplied httpx.Client or httpx.AsyncClient remains owned by the caller and is not closed by the SDK.

Route integration

The SDK does not own framework cookies or responses. Your application supplies the opaque browser session ID as key:

# GET /auth/login
return redirect(sso.begin_login(session_id, "/dashboard"))

# GET /auth/callback?code=...&state=...
result = sso.handle_callback(session_id, request.args)
return redirect(result.return_to)

# Before a protected handler
session = sso.require_session(session_id)
user_subject = session.principal.sub

# POST /auth/logout; protect this route with normal CSRF controls
sso.logout(session_id)
clear_session_cookie()

For AsyncSsoClient, await each method. Only the opaque session ID belongs in the cookie; token-bearing SsoSession objects remain in server-side storage.

Encryption key

Generate a 256-bit key once, then store it in your secret manager:

python -c "from hypershub_sso import generate_session_encryption_key as g; print(g())"

The encrypted adapters use AES-256-GCM and authenticate the storage key to prevent ciphertext swapping. Rotating the key requires a key-ring migration or invalidating existing local sessions. Never commit it to source control.

For multi-process deployments, the raw store may implement with_lock using a Redis SET NX lock and owner-token checked Lua release. The encrypted adapter automatically exposes it to the client as a distributed refresh lock.

Errors

Expected failures are SsoClientError instances with stable codes:

from hypershub_sso import SsoClientError

try:
    session = sso.require_session(session_id)
except SsoClientError as error:
    if error.code == "AUTH_REAUTH_REQUIRED":
        return redirect("/auth/login")
    if error.retriable:
        return service_unavailable()
    raise
  • AUTH_REAUTH_REQUIRED: the local or refresh session is invalid; begin login.
  • SSO_TEMPORARILY_UNAVAILABLE: network, timeout, rate-limit, JWKS, or SSO 5xx failure. Return 503 or retry later; do not log the user out.
  • SSO_STATE_MISMATCH, SSO_NONCE_MISMATCH, SSO_ID_TOKEN_INVALID: reject the callback and do not create an application session.
  • SSO_TOKEN_ERROR: the token endpoint rejected a non-retryable request.

Messages do not include credentials or tokens. Optional SDK logs contain only fixed text and non-sensitive error metadata.

Defaults

Option Default Purpose
refresh_ahead_seconds 300 Refresh before access-token expiry
session_idle_seconds 43200 Sliding local-session idle lifetime
session_absolute_seconds 2592000 Maximum local-session lifetime
refresh_max_attempts 3 Attempts for transient refresh failures
refresh_retry_base_delay 0.2 Initial exponential delay in seconds
request_timeout 10 Token, revocation, and JWKS timeout
clock_tolerance_seconds 60 ID Token clock-skew tolerance
validate_return_to relative paths only Prevent open redirects

Remote JWKS honor bounded Cache-Control: max-age caching. An unknown kid causes one immediate refresh. Plain HTTP is rejected except for loopback development hosts unless allow_insecure_http=True is explicitly set.

License

MIT

Metadata

Release files for hypershub-sso 0.1.0

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

Source distribution (sdist)

Source distribution for hypershub-sso 0.1.0
File Size Uploaded Provenance
hypershub_sso-0.1.0.tar.gz 67.6 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for hypershub-sso 0.1.0
File Interpreter ABI Platform
hypershub_sso-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 85.3 kB

Release files / hypershub_sso-0.1.0.tar.gz

Download URL hypershub_sso-0.1.0.tar.gz
Size 67.6 kB
Tags Source
SHA-256 checksum
How to use checksums
1a1b8c36f34bb21f98eb51f79cec64642105687199aceecd5928e0aabde068dd
BLAKE2b-256 checksum
How to use checksums
5fb690f9f4f77adfe11e64b1fda25ba5183e839044ca1046a6a5005a8781efc6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.15

Release files / hypershub_sso-0.1.0-py3-none-any.whl

Download URL hypershub_sso-0.1.0-py3-none-any.whl
Size 17.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
4a2cf342a4675f9ca043a4b471361905d4791412e38b80e186602198335ab584
BLAKE2b-256 checksum
How to use checksums
364a757cbb2577229159a6ca93fd04897f205b07980a656275f0b6bf0c738b6b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.15

Security for hypershub-sso 0.1.0

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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

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.1.0 This release

2 release files No 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