Skip to content
APIsPar jeton d'identité Posos

Authentification sécurisée sur l’API POSOS

L’API POSOS est protégée par une API Gateway, permettant d’assurer la sécurité de l’accès aux API et aux données. Cette interface utilise les protocoles OAuth 2 et OpenID Connect pour autoriser les accès, et valide l’identité de l’appelant grâce à une clé privée. Cette clé vous est transmise par POSOS sous forme d’un fichier .json et est strictement secrète. Elle doit pouvoir être changée rapidement en cas de révocation.

Sur le principe, l’appelant construit une assertion signée avec sa clé privée, l’envoie au service d’authentification Posos Auth qui lui renvoie en retour un jeton d’accès. Cette preuve d’authentification sera ensuite jointe dans l’en-tête des requêtes subséquentes, et validée par la passerelle sans nouvel appel au service d’authentification (validation hors ligne via JWKS).

La documentation de référence se trouve à l’adresse suivante :

Authenticate with Private Key JWT

L’appelant a besoin de deux éléments :

  • sa clé privée (fichier .json)
  • l’URL de l’émetteur (issuer) propre à l’environnement appelé. Elle est stable pour chaque environnement (preprod, production).

Contrairement à l’authentification legacy (Google IAP), aucun identifiant de client OAuth ni audience cible n’est à demander à POSOS : l’audience de l’assertion est l’émetteur lui-même.

Clé privée

Le fichier .json transmis par POSOS a la forme suivante :

service-account-key.json

{
  "type": "serviceaccount",
  "keyId": "..........",
  "key": "-----BEGIN RSA PRIVATE KEY-----\n..........\n-----END RSA PRIVATE KEY-----\n",
  "userId": ".........."
}
  • userId — identifiant du compte de service, utilisé comme iss et sub de l’assertion
  • keyId — identifiant de la clé, à placer dans l’en-tête kid de l’assertion
  • key — clé privée RSA servant à signer l’assertion (strictement secrète)

Émetteur (issuer) par environnement

Issuer

https://zitadel.preprod.posos.co

Le point de terminaison de récupération du jeton est toujours <issuer>/oauth/v2/token.

Scopes

Trois scopes doivent être demandées lors de l’échange de l’assertion contre un jeton d’accès :

PortéeRôle
openidPortée OpenID Connect standard
urn:zitadel:iam:org:project:id:PROJECT_ID:audAjoute le projet POSOS à l’audience du jeton
urn:zitadel:iam:org:projects:rolesInclut les rôles du compte de service dans le jeton (revendication posos:roles)

La portée urn:zitadel:iam:org:projects:roles est indispensable : sans elle, le jeton est bien émis mais ne contient aucun rôle, et la passerelle rejette les requêtes avec un 403.

PROJECT_ID est l’identifiant du projet POSOS, propre à chaque environnement. Il vous est transmis par POSOS en même temps que la clé.

Project ID

380745938064375828

La demande d’un jeton d’accès peut se faire avec n’importe quelle technologie capable de faire une requête HTTP, mais la plupart des langages disposent de librairies permettant de construire et signer l’assertion JWT automatiquement.

Exemples d’implémentations

Exemples

import json
import time
 
import jwt  # PyJWT
import requests
 
# La clé privée est dans le fichier .json transmis par POSOS
KEY_FILE = "service-account-key.json"
 
# Valeurs propres à l'environnement appelé, à fournir
# par des variables d'environnement
ISSUER = "https://zitadel.preprod.posos.co"
PROJECT_ID = "380745938064375828"
 
SCOPE = " ".join(
    [
        "openid",
        f"urn:zitadel:iam:org:project:id:{PROJECT_ID}:aud",
        "urn:zitadel:iam:org:projects:roles",
    ]
)
 
with open(KEY_FILE) as f:
    key = json.load(f)
 
now = int(time.time())
 
# iss et sub valent l'identifiant du compte de service,
# aud vaut l'issuer. Posos Auth limite l'assertion à 1 h.
assertion = jwt.encode(
    {
        "iss": key["userId"],
        "sub": key["userId"],
        "aud": ISSUER,
        "iat": now,
        "exp": now + 3600,
    },
    key["key"],
    algorithm="RS256",
    headers={"kid": key["keyId"]},
)
 
response = requests.post(
    f"{ISSUER}/oauth/v2/token",
    data={
        "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
        "assertion": assertion,
        "scope": SCOPE,
    },
    timeout=10,
)
response.raise_for_status()
 
token = response.json()["access_token"]
# token contient le jeton d'accès à joindre aux requêtes

Envoi des requêtes authentifiées

Le jeton d’accès doit être joint en en-tête des requêtes dans le header Authorization sous le format Bearer <contenu du jeton>.

curl --request GET --url 'https://api.preprod.posos.co/[...]' --header 'Authorization: Bearer <token>'

Durée de vie et réutilisation du jeton

La réponse du point de terminaison /oauth/v2/token contient le champ expires_in (en secondes) indiquant la durée de validité du jeton d’accès.

Réutilisez le même jeton jusqu’à son expiration plutôt que d’en demander un nouveau à chaque requête : le fournisseur d’identité applique une limitation de débit sur ce point de terminaison. Prévoyez une marge de sécurité (par exemple, renouveler le jeton lorsqu’il reste moins de 5 minutes de validité).

Vérification du jeton

Le jeton d’accès émis est un JWT : vous pouvez décoder sa partie centrale (base64url) pour inspecter ses revendications. La revendication posos:roles doit contenir les rôles attribués à votre compte de service.

echo "$ACCESS_TOKEN" | cut -d. -f2 \
  | python3 -c 'import base64,sys; s=sys.stdin.read().strip(); print(base64.urlsafe_b64decode(s + "=" * (-len(s) % 4)).decode())' \
  | jq '."posos:roles"'

Si cette revendication est absente, vérifiez que la portée urn:zitadel:iam:org:projects:roles figure bien dans la demande de jeton, puis contactez POSOS si le problème persiste.