Fulla Python Client
Typed Python SDK for Fulla — the embeddable C++ OAuth2/OIDC authorization server.
- Distribution name:
fulla-oauth2(the shorterfullaname on PyPI belongs to an unrelated project) - Import name:
fulla - API surface: generated from the server's single-source OpenAPI spec
(
apps/server/openapi.yaml) with openapi-python-client 0.29.0 — 78 operations, fully typed (py.typed),attrs-based models overhttpx - Auth layer: handwritten (token lifecycle is too sensitive to template — see the design doc)
pip install fulla-oauth2
Published to PyPI since v1.3.0 (release pipeline's
sdk-pythonjob). Prefer the released wheel; a checkout install (pip install clients/python) still works for development.
Quickstart: machine-to-machine (client_credentials)
from fulla import m2m_client
from fulla.generated.api.o_auth_2 import post_oauth2_introspect
from fulla.generated.models.post_oauth_2_introspect_body import PostOauth2IntrospectBody
client = m2m_client(
"http://localhost:5555",
client_id="backend-svc",
client_secret="…",
scopes=["tokens:read"],
)
# Every request carries a valid Bearer token: fetched lazily, cached,
# refreshed 30 s before expiry, force-refreshed once on a 401.
result = post_oauth2_introspect.sync(
client=client, body=PostOauth2IntrospectBody(token=some_access_token)
)
print(result.active)
# When done: closes BOTH the API client and the auth layer's token pool
# (closing the generated client alone leaks the token connection pool).
from fulla import close_m2m_client
close_m2m_client(client)
Async is symmetric:
from fulla import async_m2m_client
client = async_m2m_client("http://localhost:5555", "backend-svc", "…", scopes=["tokens:read"])
result = await post_oauth2_introspect.asyncio(client=client, body=body)
One-shot token fetch (scripts, benchmarks):
from fulla import fetch_client_credentials_token
token, expires_in = fetch_client_credentials_token(
"http://localhost:5555", "backend-svc", "…", ["tokens:read"]
)
Introspect / revoke (client Basic authentication)
/oauth2/introspect and /oauth2/revoke authenticate the calling client, not a user bearer
token (RFC 7662 §2.1). Use a client whose every request carries HTTP Basic — confidential
clients must use Basic; the server rejects credentials in the body (F-017):
from fulla import basic_auth_client
client = basic_auth_client("http://localhost:5555", "backend-svc", "…")
result = post_oauth2_introspect.sync(client=client, body=PostOauth2IntrospectBody(token=tok))
Authorization-code flow (web apps, with PKCE)
from fulla import AuthorizationCodeFlow, PkcePair
flow = AuthorizationCodeFlow(
"http://localhost:5555", "my-client", "my-secret",
redirect_uri="https://my.app/callback", scopes=["openid", "profile"],
)
pkce = PkcePair.generate()
authorize_url = flow.build_authorize_url(state=session_csrf, pkce=pkce)
# → send the user's browser to authorize_url; Fulla redirects back with ?code=…&state=…
# → VERIFY state, then:
tokens = flow.exchange_code(code, pkce.verifier)
# … later; Fulla rotates refresh tokens on every use (V008):
tokens = flow.refresh(tokens.refresh_token)
Generated API modules
Everything under fulla.generated is the typed surface of the whole server API:
from fulla.generated.api.open_id_connect import get_well_known_openid_configuration
from fulla.generated.api.o_auth_2 import get_oauth2_userinfo, post_oauth2_token
from fulla.generated.models.token_request import TokenRequest
Each endpoint module offers sync, sync_detailed, asyncio, asyncio_detailed. The
*_detailed variants return status code + raw response alongside the parsed model.
Development
cd clients/python
pip install -e ".[dev]"
pytest # unit tests (in-process MockTransport, no server needed)
# integration tests (needs a running full stack, see tests/integration/)
FULLA_BASE_URL=http://127.0.0.1:5555 pytest tests/integration
Regenerating the committed src/fulla/generated/ tree after an openapi.yaml change:
pip install openapi-python-client==0.29.0
python tools/clients/regen_clients.py # from the repo root
CI (.github/workflows/clients-sdk.yml) re-generates and diffs on every PR touching
clients/** or the spec — committed generated code can never go stale.
Versioning
The package version is locked to the server's cmake/Version.cmake (enforced by
tools/clients/regen_clients.py --version-only at release time). Breaking HTTP API changes
require a major bump on both sides (guarded by the openapi-governance oasdiff workflow).
Local network note
If go/module proxies are unreachable from your network, the Go generator download mentioned
in the regen docs needs a GOPROXY mirror (e.g. GOPROXY=https://goproxy.cn,direct). This only
affects regenerating clients/go — installing and using this Python package is unaffected.
Metadata
Release files for fulla-oauth2 1.4.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 | |
|---|---|---|---|
| fulla_oauth2-1.4.0.tar.gz | 91.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| fulla_oauth2-1.4.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 401.7 kB
Release files / fulla_oauth2-1.4.0.tar.gz
| Download URL | fulla_oauth2-1.4.0.tar.gz |
|---|---|
| Size | 91.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
43951e17544feb3eb32cac678f0bb83d7e7ce57a894ee87ac5836b1f0b259747
|
|
BLAKE2b-256 checksum How to use checksums |
20da1f84743a2f78637892a982d108e93b771b352dfc45c7a4a7a80f29964e07
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.15
|
Release files / fulla_oauth2-1.4.0-py3-none-any.whl
| Download URL | fulla_oauth2-1.4.0-py3-none-any.whl |
|---|---|
| Size | 310.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
520061c47571e5cba5b5ebec21cb61f0445fad96d47211f7cb1246d73c5ac7c6
|
|
BLAKE2b-256 checksum How to use checksums |
7af64f16bc4ba497d794cfeae2f85350d1847bcb4606f9ac5ec52f633ec2f07c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.15
|