Planifier une modification de configuration
POST /v1/config-plans · permission config:read et la permission de lecture de chaque type du document
Compare un document de configuration à la configuration actuelle de l'environnement et enregistre le résultat sous forme de plan. Rien n'est modifié : un plan montre seulement ce que ferait l'application du document. Utilisez-le pour examiner une promotion de development vers staging ou production avant de l'appliquer.
Requête
| Champ | Description |
|---|---|
document |
Obligatoire. Un document de configuration au format de GET /v1/config-export. Il doit respecter le JSON Schema https://docs.keenauth.com/config/schema/v1.json. |
prune |
Facultatif, false par défaut. Si true, les ressources des types du document absentes du document sont planifiées pour suppression. |
- Les types du document sont
kindss'il est fourni (chaque ressource doit alors être d'un type listé), sinon les types de ses ressources. Seuls ces types sont comparés ; les autres restent inchangés. - Une ressource absente du document n'est pas supprimée sauf si
prunevauttrue. Les types singletons (environment_settings,identity_settings,branding) ne sont jamais supprimés. - Dans les types singletons, un champ absent du document reste inchangé : la valeur actuelle de la cible est conservée. Un document exporté avant l'ajout d'un champ ne réinitialise donc pas ce champ. Une valeur donnée explicitement, y compris
null, est toujours écrite. Dans les autres types, un champ absent prend sa valeur par défaut. - Le document ne doit contenir aucune valeur secrète. Un champ secret ne contient qu'un espace réservé
secret_refounull; une valeur est rejetée et n'est jamais renvoyée. - Les
warningsdu document sont ignorés ; 15 000 au plus sont acceptés (un export n'en contient jamais davantage). - Les permissions sont celles d'un export des mêmes types. Avec
prune, les types pouvant référencer une ressource supprimée sont aussi lus, leurs permissions sont donc également requises.
Réponse
201 Created avec Location: /v1/config-plans/{plan_id} et Cache-Control: no-store.
| Champ | Description |
|---|---|
id |
Identifiant du plan, cfgp_…. |
status |
planned ; expired après expires_at. |
expires_at |
Le plan est valable 1 heure. Il est supprimé 7 jours après son expiration. |
summary |
Nombre d'actions create, update, delete et no_op. |
changes |
Une entrée par ressource, dans l'ordre des types puis par key. |
warnings |
secret_required : la connexion a besoin d'un secret client que la cible n'a pas encore. |
Chaque modification contient kind, key, action (create, update, delete ou no_op), object_version (la version de la ressource cible au moment du plan ; null pour create), requires_secret, fields et, pour create et update, le spec souhaité. Chaque entrée de fields est une différence de champ : pointer (RFC 6901, par exemple /spec/name), op (add, remove ou replace, comme dans RFC 6902), before et after. Les listes sont comparées comme des valeurs entières.
Un document exporté fourni sans modification planifie no_op pour chaque ressource, quel que soit l'ordre des ressources et des listes de type ensemble.
{
"id": "cfgp_01m4qpqtywfs7930tb6kqn5rc5",
"status": "planned",
"prune": false,
"kinds": ["connection"],
"expires_at": "2026-10-12T11:00:00Z",
"summary": {"create": 1, "update": 1, "delete": 0, "no_op": 1},
"changes": [
{"kind": "connection", "key": "db", "action": "no_op", "object_version": 5, "requires_secret": false, "fields": []},
{"kind": "connection", "key": "github", "action": "create", "object_version": null, "requires_secret": true, "fields": [], "spec": {"type": "social", "strategy": "github", "name": "GitHub", "display_name": null, "status": "active", "settings": {}, "client_secret": {"secret_ref": {"source": "env", "name": "KEENAUTH_CONNECTION_GITHUB_CLIENT_SECRET"}}}},
{"kind": "connection", "key": "google", "action": "update", "object_version": 4, "requires_secret": false, "fields": [{"pointer": "/spec/name", "op": "replace", "before": "Google", "after": "Google Workspace"}], "spec": {"type": "social", "strategy": "google", "name": "Google Workspace", "display_name": null, "status": "active", "settings": {}, "client_secret": {"secret_ref": {"source": "env", "name": "KEENAUTH_CONNECTION_GOOGLE_CLIENT_SECRET"}}}}
],
"warnings": [{"code": "secret_required", "kind": "connection", "key": "github", "pointer": "/spec/client_secret"}]
}
Chaque plan écrit une entrée config_plan.created dans le journal de gestion de l'environnement.
Limites
- Débit : les plans ont leur propre limite par minute et par environnement : en
production, 20 en Free, 60 en Startup et Business, 120 en Enterprise ; endevelopmentetstaging, un dixième (au moins 2). - Quota par environnement : au plus 100 plans ni appliqués ni expirés, et au plus 2 000 plans et 1 Gio de plans stockés jusqu'à leur suppression (7 jours après l'expiration). Les plans des autres environnements ne comptent jamais.
- Capacité : le serveur calcule un nombre limité de grands plans à la fois ; un environnement peut utiliser au plus un quart de cette capacité.
- Limites de champs : ce sont celles que le service de configuration applique à l'écriture : le schéma borne les listes et les textes (par exemple
redirect_uris50,allowed_web_origins20,permissions1 000), lessettingsd'une connexion font au plus 32 Kio et 8 niveaux de profondeur, lesjwksd'une application et leconsent_text_i18nde chaque permission au plus 16 Kio.
Erreurs
| HTTP | code | Quand |
|---|---|---|
| 400 | malformed_request, unknown_field |
Le corps n'est pas du JSON ou contient un champ autre que document et prune. |
| 401 | unauthenticated |
Les identifiants sont absents, invalides ou révoqués. |
| 403 | insufficient_permissions |
Il manque une permission requise ; required_permissions les liste toutes. |
| 413 | config_document_too_large, payload_too_large |
Le document dépasse 5 000 ressources ou 10 Mio ; planifiez moins de types. |
| 422 | validation_failed |
Voir ci-dessous ; errors[].pointer pointe dans la requête (/document/...). |
| 429 | rate_limited |
La limite de débit des plans ou le quota de plans de l'environnement est atteint, ou l'environnement calcule trop de plans ; réessayez après le délai Retry-After (pour le quota, lorsque le plus ancien plan expire ou est supprimé). |
| 503 | service_unavailable |
Le calcul des plans est saturé ou une dépendance est temporairement indisponible ; réessayez après le délai Retry-After. |
errors[].code |
Signification |
|---|---|
required |
document est absent. |
invalid |
Le document ne respecte pas le schéma à ce pointeur. |
duplicate |
Deux ressources ont le même kind et la même key. |
kind_not_listed |
Le type de la ressource n'est pas dans kinds. |
secret_value |
Une valeur secrète a été trouvée ; utilisez un espace réservé secret_ref. |
unresolved_reference |
La key référencée n'existerait plus après la modification. |
key_in_use |
La key appartient à une application non gérée par la configuration (appartenant à une organisation ou auto-enregistrée), ou à l'API système. |
still_referenced |
/prune : une ressource conservée référence une ressource que le plan supprimerait. |
too_large |
Une ressource, un avertissement ou un champ de premier niveau contient plus de 200 000 valeurs JSON. |
too_long |
Les settings d'une connexion dépassent 32 Kio, ou les jwks d'une application ou le consent_text_i18n d'une permission dépassent 16 Kio. |
too_deep |
Les settings d'une connexion sont imbriqués sur plus de 8 niveaux. |
reserved |
L'identifier de l'API est dans l'espace de noms urn:idp: de la plateforme. |
Exemple
curl -X POST "https://api.eu.keenauth.com/v1/config-plans" \
-H "Authorization: Bearer $KEENAUTH_SECRET_KEY" \
-H "Content-Type: application/json" \
-d "{\"document\": $(cat keenauth.json), \"prune\": false}"
keenauth config plan -f keenauth.yaml