Authentification
Accès
Pour accéder à l’API Le Temps vous devez disposer d’une clé d’API.
Pour savoir comment obtenir une clé d’API rendez-vous sur cette page.
Une clé d’API est composée de deux éléments :
| Élément | Rôle | Confidentiel |
|---|---|---|
Identifiant d’accès (access_uuid) | Identifie votre clé, il est transmis à chaque appel | Non |
Secret (secret) | Sert à signer vos appels, il n’est jamais transmis | Oui |
Le secret commence toujours par spyri_secret_. Conservez-le comme un mot de passe : ne le commitez pas dans un dépôt de code, ne l’envoyez pas par e-mail en clair, ne l’utilisez pas dans du code exécuté par un navigateur ou une application mobile.
Si vous pensez que votre secret a été exposé, contactez-nous pour qu’il soit régénéré.
Signer une requête
Chaque appel de l’API doit être signé avec votre secret (HMAC-SHA256).
La signature lie la requête à sa méthode, à son chemin, à ses paramètres et à son corps : une requête interceptée ne peut être ni modifiée, ni rejouée.
La signature est transmise dans un header Authorization unique, dont les paramètres sont séparés par des ; :
Authorization: HMAC-SHA256 access_uuid=VOTRE_ACCESS_UUID;time=TIMESTAMP;signature=SIGNATUREHorodatage
TIMESTAMP est l’heure courante en timestamp Unix, en secondes (ex. 1762182000).
Chaîne à signer
Construisez une chaîne de quatre lignes séparées par un saut de ligne \n (sans saut de ligne final) :
MÉTHODE
CHEMIN
TIMESTAMP
EMPREINTE_DU_CORPSMÉTHODE: la méthode HTTP en majuscules (GET,POST,PATCH…) ;CHEMIN: le chemin de l’URL avec ses paramètres, exactement tel qu’il est envoyé, sans le nom de domaine (ex./api/users?email=jeandupont%40gmail.com) ;TIMESTAMP: la même valeur que celle du paramètretimedu header ;EMPREINTE_DU_CORPS: l’empreinte SHA-256 du corps brut de la requête, en hexadécimal minuscule. Pour une requête sans corps (unGET), c’est l’empreinte de la chaîne vide :e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855.
Signature
SIGNATURE est le HMAC-SHA256 de cette chaîne, calculé avec votre secret, en hexadécimal minuscule.
%40 pour @, ordre des paramètres…). Le plus sûr est de construire vous-même l’URL encodée, puis de signer et d’envoyer cette même valeur.Exemples
ACCESS_UUID="VOTRE_ACCESS_UUID"
SECRET="VOTRE_SECRET"
PATH_QUERY="/api/users?email=jeandupont%40gmail.com"
TIMESTAMP=$(date +%s)
BODY=""
BODY_HASH=$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | sed 's/^.* //')
SIGNATURE=$(printf 'GET\n%s\n%s\n%s' "$PATH_QUERY" "$TIMESTAMP" "$BODY_HASH" \
| openssl dgst -sha256 -hmac "$SECRET" -hex | sed 's/^.* //')
curl "https://www.letemps.ch$PATH_QUERY" \
-H "Authorization: HMAC-SHA256 access_uuid=$ACCESS_UUID;time=$TIMESTAMP;signature=$SIGNATURE"require "openssl"
require "net/http"
require "json"
access_uuid = "VOTRE_ACCESS_UUID"
secret = "VOTRE_SECRET"
path = "/api/users"
body = { user: { email: "jeandupont@gmail.com" } }.to_json
timestamp = Time.now.to_i.to_s
string_to_sign = ["POST", path, timestamp, OpenSSL::Digest::SHA256.hexdigest(body)].join("\n")
signature = OpenSSL::HMAC.hexdigest("SHA256", secret, string_to_sign)
request = Net::HTTP::Post.new(path)
request["Authorization"] = "HMAC-SHA256 access_uuid=#{access_uuid};time=#{timestamp};signature=#{signature}"
request["Content-Type"] = "application/json"
request.body = body
response = Net::HTTP.start("www.letemps.ch", 443, use_ssl: true) { |http| http.request(request) }La gem spyri-api signe les requêtes pour vous depuis sa version 0.2.0 :
client = SpyriApi::Client.new(access_uuid: "VOTRE_ACCESS_UUID", secret: "VOTRE_SECRET", host: "https://www.letemps.ch/api")
SpyriApi::Users.new(client).search(email: "jeandupont@gmail.com")import hashlib
import hmac
import json
import time
import requests
access_uuid = "VOTRE_ACCESS_UUID"
secret = "VOTRE_SECRET"
path = "/api/users"
body = json.dumps({"user": {"email": "jeandupont@gmail.com"}})
timestamp = str(int(time.time()))
string_to_sign = "\n".join(["POST", path, timestamp, hashlib.sha256(body.encode()).hexdigest()])
signature = hmac.new(secret.encode(), string_to_sign.encode(), hashlib.sha256).hexdigest()
response = requests.post(
"https://www.letemps.ch" + path,
data=body, # la chaîne signée telle quelle : json=... la sérialiserait à nouveau
headers={
"Authorization": f"HMAC-SHA256 access_uuid={access_uuid};time={timestamp};signature={signature}",
"Content-Type": "application/json",
},
)const crypto = require("node:crypto");
const accessUuid = "VOTRE_ACCESS_UUID";
const secret = "VOTRE_SECRET";
const path = "/api/users";
const body = JSON.stringify({ user: { email: "jeandupont@gmail.com" } });
const timestamp = Math.floor(Date.now() / 1000).toString();
const bodyHash = crypto.createHash("sha256").update(body).digest("hex");
const stringToSign = ["POST", path, timestamp, bodyHash].join("\n");
const signature = crypto.createHmac("sha256", secret).update(stringToSign).digest("hex");
const response = await fetch(`https://www.letemps.ch${path}`, {
method: "POST",
body,
headers: {
Authorization: `HMAC-SHA256 access_uuid=${accessUuid};time=${timestamp};signature=${signature}`,
"Content-Type": "application/json",
},
});Postman
Enregistrez votre identifiant d’accès et votre secret dans deux variables d’environnement, api_access_uuid et api_secret, puis ajoutez ce script dans Scripts → Pre-request, de préférence au niveau de la collection pour qu’il s’applique à toutes les requêtes :
const secret = pm.environment.get("api_secret");
const timestamp = Math.floor(Date.now() / 1000).toString();
const method = pm.request.method.toUpperCase();
// Variables résolues : on signe exactement ce que Postman envoie
const path = pm.variables.replaceIn(pm.request.url.getPathWithQuery());
const body = pm.request.body && pm.request.body.mode === "raw" ? pm.variables.replaceIn(pm.request.body.raw) : "";
const stringToSign = [method, path, timestamp, CryptoJS.SHA256(body).toString(CryptoJS.enc.Hex)].join("\n");
const signature = CryptoJS.HmacSHA256(stringToSign, secret).toString(CryptoJS.enc.Hex);
pm.request.headers.upsert({
key: "Authorization",
value: `HMAC-SHA256 access_uuid=${pm.environment.get("api_access_uuid")};time=${timestamp};signature=${signature}`
});- Réglez l’onglet Authorization sur No Auth, sinon Postman écrase le header défini par le script.
- Envoyez les corps de requête en
rawJSON (Content-Type: application/json) : un corpsform-dataoux-www-form-urlencodedserait signé comme vide et refusé.
Validité et rejeu
- L’horodatage doit être à moins de 5 minutes de l’heure de nos serveurs, dans un sens comme dans l’autre : gardez l’horloge de votre serveur synchronisée (NTP).
- Une signature n’est acceptée qu’une seule fois. Pour relancer une requête, signez-la à nouveau. Deux requêtes strictement identiques envoyées dans la même seconde ont la même signature : la seconde est refusée.
Erreurs d’authentification
Un appel qui ne peut pas être authentifié répond par une erreur 401 et indique un code :
{
"code": "signature_invalid"
}code | Signification |
|---|---|
api_key_invalid | Header Authorization absent, ou identifiant d’accès manquant ou inconnu |
signature_missing | Paramètre time ou signature absent du header |
signature_expired | Horodatage mal formé ou à plus de 5 minutes de l’heure de nos serveurs |
signature_invalid | La signature ne correspond pas : mauvais secret, ou méthode / chemin / paramètres / corps différents de ce qui a été signé |
signature_replayed | Cette signature a déjà été utilisée |
legacy_authentication_disabled | Clé transmise en clair (ancienne méthode, voir ci-dessous) alors que votre clé n’accepte que les requêtes signées |
Ancienne méthode (dépréciée)
Jusqu’ici, la clé d’API était transmise en clair dans le header Authorization :
Authorization: Bearer VOTRE_CLE_D_APICette méthode reste acceptée temporairement pour les clés créées avant l’introduction des requêtes signées, mais elle sera désactivée clé par clé : une clé transmise en clair peut être interceptée et réutilisée indéfiniment.
Si vous l’utilisez encore, demandez-nous votre identifiant d’accès et votre secret, et passez aux requêtes signées. Les nouvelles clés n’acceptent que les requêtes signées.
Permissions
Chaque clé d’API est configurée pour vous permettre d’accéder à certaines méthodes.
Par exemple votre clé peut vous permettre d’accéder à la recherche d’utilisateur mais pas à l’affichage d’une facture.
De même votre clé peut permettre - ou non - d’ajouter / modifier du contenu.
Si vous essayez d’appeler une méthode à laquelle vous n’avez pas accès vous obtiendrez une erreur 403 avec le code api_key_unauthorized et un message vous expliquant quel est le droit manquant :
{
"code": "api_key_unauthorized",
"details": "Il vous manque les droits suivants : XXX"
}