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=Laxcookie
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
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)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| hypershub_sso-0.1.0.tar.gz | 67.6 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| 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.