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.3.1
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.3.1.tar.gz | 65.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| fulla_oauth2-1.3.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 255.2 kB
Release files / fulla_oauth2-1.3.1.tar.gz
| Download URL | fulla_oauth2-1.3.1.tar.gz |
|---|---|
| Size | 65.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c5234c6904f5e885a2bc3eebd7d76135476961a0c7eb4170c2646d5f578970b6
|
|
BLAKE2b-256 checksum How to use checksums |
7a7f8d26c9e6db58059aed0bb7911dd95db5b18fe731a726c2bd09aec3e36294
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.14
|
Release files / fulla_oauth2-1.3.1-py3-none-any.whl
| Download URL | fulla_oauth2-1.3.1-py3-none-any.whl |
|---|---|
| Size | 190.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6c529458806caaf373119f2613dc5a92c04389619824f6341689fd420c33a1e4
|
|
BLAKE2b-256 checksum How to use checksums |
65c0d1c6404c11a18968a638347074dc558296eabdf9a1f0c18f96b0dd518a5c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.14
|