Aller au contenu

Sudo (élévation)

Le sudo (élévation / step-up) demande à un ou plusieurs validateurs humains d’approuver une action sensible depuis leur app Bloonio Authenticator avant que le backend ne l’exécute. Le relais expose une primitive de dispatch (signée HMAC #1) ; le protocole en deux appels côté tenant — 403 puis re-appel — est fourni par le SDK Python.

  1. Le client appelle votre route protégée (ex. POST /transfer/execute) sans en-tête X-Sudo-Instruction-Key. → le SDK crée un instruction_id, déclenche le dispatch + le push, et renvoie 403 { "error": "SUDO_INSTRUCTION_KEY_REQUIRED", "instruction_id": "abc..." }.
  2. L’appareil reçoit le push → l’utilisateur approuve → le relais POST l’ApprovalEvent vers votre callback (vérifié HMAC) → le store marque l’instruction_id comme validated.
  3. Le client ré-émet la même requête avec l’en-tête X-Sudo-Instruction-Key: abc.... → la requête passe.

POST /relay/sudo/dispatch crée un événement de validation et diffuse les pushes de challenge aux participants. Le relais le transmet à auth_api et vous renvoie event_id, status et expires_at.

Règles de validation du corps :

  • event_type{ sudo_action, sudo_group_action, sudo_delegated_action }.
  • action_type{ creation, deletion, update, upsert }.
  • Au moins un de relay_user_linked_id_list (cibles individuelles) ou relay_group_linked_id_list (cibles de groupe) doit être non vide.
  • data_items est requis quand data_access_type=static ; data_fetch_url quand data_access_type=dynamic.
  • tenant_id n’est pas dans le corps — le relais le dérive du contexte authentifié.
Fenêtre de terminal
curl $BASE_URL/api/v1/relay/sudo/dispatch \
-X POST \
-H "X-Bloonio-Tenant-Id: tnt_..." \
-H "X-Bloonio-Timestamp: 1718966400000" \
-H "X-Bloonio-Signature: <hex_hmac_sha256>" \
-H "Content-Type: application/json" \
-d '{
"event_type": "sudo_action",
"action_type": "update",
"idempotency_key": "idem_abc123",
"relay_user_linked_id_list": ["652f1f77bcf86cd799439011"],
"title": "Confirmer le virement",
"description": "Approuver un virement de 1 000 USD vers ACME Corp.",
"data_access_type": "static",
"data_items": [
{ "display_title": "Montant", "display_value": "1000 USD", "data_type": "CURRENCY_USD" },
{ "display_title": "Bénéficiaire", "display_value": "ACME Corp", "data_type": "PARTY_NAME" }
],
"on_validate_callback_url": "https://api.example.com/relay-callbacks/sudo-validated",
"on_reject_callback_url": "https://api.example.com/relay-callbacks/sudo-rejected"
}'
{
"success": true,
"status_code": 201,
"message": "Dispatched.",
"data": { "event_id": "...", "status": "pending", "expires_at": "2026-06-21T..." }
}
  • relay_user_linked_id_list — identifiants opaques côté relais de validateurs individuels (relay_user_id).
  • relay_group_linked_id_list — identifiants de groupes ; auth_api étend l’appartenance et diffuse les pushes aux membres. Le relais ne peut pas étendre les groupes lui-même (l’appartenance vit sur auth_api).

Le couple relay_user_id est le validateur universel : voir Multi-tenant & relay_user_id.

Pour passer des relay_user_linked_id / relay_group_linked_id à dispatch, résolvez-les d’abord depuis les identifiants publics. Ces GET sont de purs pass-through (HMAC #1 entrant) ; auth_api applique le périmètre du tenant.

MéthodeCheminRôle
GET/relay/sudo/groupsLister les groupes de validation visibles par le tenant.
GET/relay/sudo/groups/by-public-idRésoudre un bgr-… en relay_group_linked_id (?public_id_str=).
GET/relay/sudo/paired-usersLister les utilisateurs appairés (validateurs potentiels).
GET/relay/sudo/paired-users/by-public-idRésoudre un bth-… en relay_user_linked_id (?public_id_str=).
GET/relay/sudo/pending-validationsValidations en attente pour un utilisateur (?relay_user_linked_id=).
GET/relay/sudo/paired-users/signatureImage de signature d’un utilisateur (?relay_user_linked_id=).
Fenêtre de terminal
curl "$BASE_URL/api/v1/relay/sudo/groups/by-public-id?public_id_str=bgr-abc123" \
-H "X-Bloonio-Tenant-Id: tnt_..." \
-H "X-Bloonio-Timestamp: 1718966400000" \
-H "X-Bloonio-Signature: <hex_hmac_sha256>"

POST /relay/sudo/verify-totp valide le TOTP émis par Bloonio Authenticator pour l’appairage identifié par relay_user_linked_id, sans que le tenant ne détienne le secret par-utilisateur. Renvoie 200 en cas de correspondance, 401 sur un code erroné / inconnu.

Fenêtre de terminal
curl $BASE_URL/api/v1/relay/sudo/verify-totp \
-X POST \
-H "X-Bloonio-Tenant-Id: tnt_..." \
-H "X-Bloonio-Timestamp: 1718966400000" \
-H "X-Bloonio-Signature: <hex_hmac_sha256>" \
-H "Content-Type: application/json" \
-d '{ "relay_user_linked_id": "652f1f77bcf86cd799439011", "totp": "123456" }'

En FastAPI, le décorateur monte tout le protocole en deux appels sur la route :

@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),
],
)],
)
async def transfer_execute(...): ...

Voir le SDK Python pour l’installation, la configuration et l’équivalent Django.