# Jetons de décision

Lorsqu'un point de contrôle arrive à une décision finale, Maetra émet une **jeton de décision** — un JWT signé en `decision_token`C'est vrai. Elle lie la décision à l'enveloppe d'action canonique, aux versions exactes des politiques, à l'espace de travail et à l'exécuteur-exécuteur prévu.

Vérifiez-le localement pour le rejet rapide, puis consommez-le par `POST /v1/executions/authorize` immédiatement avant l'action extérieure. Ce contrôle faisant autorité impose la révocation et la sémantique à usage unique.

### Clés publiques (JWKS)

`GET /.well-known/jwks.json` — **Aucune authentification n'est requise.** Renvoie l'ensemble de clés utilisé pour signer les jetons de décision. Récupère une fois et cache; l'en-tête du jeton `kid` identifie la clé qui l'a signée.

#### cURL

```bash
curl "https://api.maetra.io/.well-known/jwks.json" \
  -H "Authorization: Bearer $MAETRA_API_KEY"
```

#### JavaScript

```javascript
const res = await fetch("https://api.maetra.io/.well-known/jwks.json", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.MAETRA_API_KEY}`,
  },
});
if (!res.ok) throw new Error(`Maetra API ${res.status}`);
const data = await res.json();
console.log(data);
```

#### TypeScript

```typescript
const res = await fetch("https://api.maetra.io/.well-known/jwks.json", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.MAETRA_API_KEY}`,
  },
});
if (!res.ok) throw new Error(`Maetra API ${res.status}`);
const data = (await res.json());
```

#### Python

```python
import os, requests

res = requests.get(
    "https://api.maetra.io/.well-known/jwks.json",
    headers={"Authorization": f"Bearer {os.environ['MAETRA_API_KEY']}"},
)
res.raise_for_status()
print(res.json())
```

#### Rust

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let key = std::env::var("MAETRA_API_KEY")?;
    let client = reqwest::Client::new();
    let res = client
        .get("https://api.maetra.io/.well-known/jwks.json")
        .bearer_auth(&key)
        .send()
        .await?;
    let data: serde_json::Value = res.json().await?;
    println!("{data:#}");
    Ok(())
}
```

#### C++

```cpp
#include <curl/curl.h>
#include <cstdlib>
#include <string>

int main() {
    CURL* curl = curl_easy_init();
    std::string auth = "Authorization: Bearer " + std::string(std::getenv("MAETRA_API_KEY"));
    struct curl_slist* headers = nullptr;
    headers = curl_slist_append(headers, auth.c_str());
    curl_easy_setopt(curl, CURLOPT_URL, "https://api.maetra.io/.well-known/jwks.json");
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
    curl_easy_perform(curl);   // response is written to stdout by default
    curl_slist_free_all(headers);
    curl_easy_cleanup(curl);
    return 0;
}
```

#### Java

```java
import java.net.URI;
import java.net.http.*;

var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.maetra.io/.well-known/jwks.json"))
    .header("Authorization", "Bearer " + System.getenv("MAETRA_API_KEY"))
    .method("GET", HttpRequest.BodyPublishers.noBody())
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
```


```json
{ "keys": [ { "kty": "OKP", "crv": "Ed25519", "alg": "EdDSA", "kid": "…", "x": "…" } ] }
```

### Vérification d'un jeton

Les jetons de décision sont signés avec **EdDSA utilisant Ed25519**C'est vrai. Vérifier avec une bibliothèque JWT qui prend en charge Ed25519 et le JWKS ci-dessus.

#### JavaScript / TypeScript

```typescript
import { jwtVerify, createRemoteJWKSet } from "jose";

const JWKS = createRemoteJWKSet(new URL("https://api.maetra.io/.well-known/jwks.json"));

export async function verifyDecision(token: string) {
  const { payload } = await jwtVerify(token, JWKS, {
    algorithms: ["EdDSA"],
    issuer: "maetra-govern",
    audience: "payments-worker",
  });
  if (payload.status !== "approved" || payload.maxUses !== 1) {
    throw new Error(`Action not approved: ${payload.status}`);
  }
  return payload; // identifies the checkpoint, action, decision, and expiry
}
```

#### Python

```python
import jwt  # PyJWT
from jwt import PyJWKClient

jwks = PyJWKClient("https://api.maetra.io/.well-known/jwks.json")

def verify_decision(token: str) -> dict:
    key = jwks.get_signing_key_from_jwt(token).key
    payload = jwt.decode(token, key, algorithms=["EdDSA"], issuer="maetra-govern", audience="payments-worker")
    if payload.get("status") != "approved":
        raise ValueError(f"Action not approved: {payload.get('status')}")
    return payload
```

#### Go

```go
// Use github.com/lestrrat-go/jwx/v2/jwk + /jwt
keySet, _ := jwk.Fetch(ctx, "https://api.maetra.io/.well-known/jwks.json")
tok, err := jwt.Parse(raw, jwt.WithKeySet(keySet), jwt.WithValidate(true))
if err != nil { /* reject */ }
if status, _ := tok.Get("status"); status != "approved" {
    // do not perform the action
}
```


#### Quoi vérifier

* **Signature** — doit être validée par une clé dans le JWKS.
* **`status`** — ne procéder que lorsque: `approved`.
* **Expiration** — refus des jetons expirés (standard `exp`).
* **Émetteur et public** — exiger `iss=maetra-govern` et votre exécuteur est exact. `aud` valeur.
* **Reliure** — recalculer et comparer `actionEnvelopeHash`, puis comparer `checkpointId`, `workspaceId`et `policyDigest`.
* **Utiliser le plafond** — exiger `maxUses=1` et d'autoriser par l'intermédiaire d'Maetra ainsi un replay ou jeton révoqué échoue à l'exécution.

> **Note**
> Traiter le jeton comme une capacité d'utilisation unique de courte durée. `decision_token_expires_at` limite le jeton; point de contrôle `expires_at` est le délai d'approbation.