Aller au contenu

SDK Python

bloonio_auth_relay_client est le SDK backend de l’Auth Relay. Il enveloppe la signature HMAC #1, le protocole sudo en deux appels, le handshake d’appairage et les callbacks — un cœur agnostique du framework, plus de fins adaptateurs FastAPI et Django.

Fenêtre de terminal
pip install "bloonio-auth-relay-client[fastapi,redis]"
# ou
pip install "bloonio-auth-relay-client[django,redis]"

Extras disponibles : fastapi, django, redis, mongo, all.

  • RelayClient / AsyncRelayClient — wrapper HTTP signé HMAC autour du relais. Version synchrone pour Django, asynchrone pour FastAPI ; même surface.
  • SudoInstructionStore — store court (~180 s) qui suit « cette instruction a passé le sudo, voici la fenêtre de re-appel avec X-Sudo-Instruction-Key ». Backend par défaut : Redis.
  • PendingOpStore — store plus long (10–30 min) qui conserve la mutation d’origine pour rejeu côté serveur (requis pour le quorum de groupe v2 / le cross-org v3).
  • @sudo_required — le décorateur ; mêmes arguments en FastAPI et Django.
  • DataType + ValidationField — blocs d’affichage structurés que l’app authentificateur rend (devise, IBAN, date, référence d’entité, etc.).

RelaySettings lit le préfixe BLOONIO_RELAY_. Les clés essentielles :

VariableRôle
BLOONIO_RELAY_BASE_URLURL de base du relais, ex. https://auth-relay.bloonio.com.
BLOONIO_RELAY_TENANT_IDLe tenant_id du tenant appelant.
BLOONIO_RELAY_TENANT_SECRETLe tenant_secret (signature HMAC #1).
BLOONIO_RELAY_STATE_BACKENDredis (défaut) ou memory.
BLOONIO_RELAY_STATE_BACKEND_URLURL Redis quand state_backend=redis.
BLOONIO_RELAY_CALLBACK_PATHChemin où le relais POST les ApprovalEvent (défaut /api/sudo-callback).
BLOONIO_RELAY_BASE_URL=https://auth-relay.bloonio.com
BLOONIO_RELAY_TENANT_ID=tnt_...
BLOONIO_RELAY_TENANT_SECRET=sk_...
BLOONIO_RELAY_STATE_BACKEND=redis
BLOONIO_RELAY_STATE_BACKEND_URL=redis://localhost:6379/0

BloonioAuthAdapter.from_env(app) construit RelaySettings depuis l’environnement, instancie un AsyncRelayClient, monte le middleware de dispatch, le routeur d’auto-réponse (/_bloonio/submit-response) et le routeur de callback.

Pour des routes nommées où l’on sait à l’avance quels champs afficher :

from fastapi import FastAPI
from bloonio_auth_relay_client import DataType, SudoActionType, ValidationField
from bloonio_auth_relay_client.adapters.fastapi import BloonioAuthAdapter
app = FastAPI()
bloonio = BloonioAuthAdapter.from_env(app) # lit les BLOONIO_RELAY_*
@app.post(
"/transfer/execute",
dependencies=[bloonio.sudo_required(
expected_action="transfer_funds",
custom_type=SudoActionType.LOCAL_AUTH,
user_socket_hash=lambda req: req.state.user.socket_hash,
title="Confirmer le virement",
fields=lambda req: [
ValidationField(key="amount", title="Montant",
value=str(req.state.body["amount"]),
data_type=DataType.CURRENCY_USD),
ValidationField(key="to", title="Bénéficiaire",
value=req.state.body["recipient"],
data_type=DataType.PARTY_NAME),
],
)],
)
async def transfer_execute(...): ...

Quand le sudo est requis, le SDK crée un instruction_id, écrit l’état Redis, appelle send_auth_challenge (push FCM), et renvoie 403 {error: "SUDO_INSTRUCTION_KEY_REQUIRED", instruction_id}. À l’approbation, l’état bascule en validated et le re-appel avec X-Sudo-Instruction-Key passe. Voir Sudo (élévation).

settings.py
INSTALLED_APPS = [..., "bloonio_auth_relay_client.adapters.django"]
MIDDLEWARE = [..., "bloonio_auth_relay_client.adapters.django.middleware.SudoActionMiddleware"]
BLOONIO_AUTH_RELAY = {
"BASE_URL": "https://auth-relay.bloonio.com",
"TENANT_ID": os.environ["RELAY_TENANT_ID"],
"TENANT_SECRET": os.environ["RELAY_TENANT_SECRET"],
"STATE_BACKEND": "redis",
"STATE_BACKEND_URL": os.environ["REDIS_URL"],
"CALLBACK_PATH": "/api/sudo-callback/",
}
urls.py
from bloonio_auth_relay_client.adapters.django import urls as relay_urls
urlpatterns = [..., path("", include(relay_urls))]
views.py
from bloonio_auth_relay_client.adapters.django import sudo_required
from bloonio_auth_relay_client import DataType, SudoActionType, ValidationField
@sudo_required(
expected_action="transfer_funds",
custom_type=SudoActionType.LOCAL_AUTH,
user_socket_hash=lambda req: req.user.socket_hash,
title="Confirmer le virement",
fields=lambda req: [
ValidationField(key="amount", title="Montant",
value=str(req.POST["amount"]),
data_type=DataType.CURRENCY_USD),
],
)
def transfer_execute(request):
...

Fonctionne sur les vues simples, @api_view et APIView/ViewSet de DRF, et les vues asynchrones (Django 4.1+). Même décorateur, mêmes arguments — juste req.user au lieu de req.state.user et req.POST au lieu de req.state.body.

Appelé une fois par appairage d’appareil, depuis votre handler de QR après authentification de l’utilisateur :

from bloonio_auth_relay_client import AsyncRelayClient, RelaySettings
relay = AsyncRelayClient(RelaySettings())
result = await relay.prepare_pairing(
user_socket_hash=user.socket_hash,
backend_user_id=str(user.id),
user_email=user.email,
user_phone=user.phone,
first_name=user.first_name,
last_name=user.last_name,
display_name="Example",
display_logo_url="https://example.com/logo.png",
)
pairing_proof = result["pairing_proof"] # à transmettre à l'appareil

Voir Appairage & appareils pour la suite du flux côté appareil.