oauthsonas
oauthsonas est un petit fournisseur OpenID Connect en mémoire pour le
développement local et les tests d'intégration. Il implémente un vrai flux
navigateur Authorization Code avec S256 PKCE, des refresh tokens rotatifs, des
JWT d'accès et d'identité signés RS256, la découverte, JWKS, userinfo, logout et
des personas configurables.
- Module :
github.com/optimiweb/oauthsonas - Install :
go install github.com/optimiweb/oauthsonas/cmd/oauthsonas@latest - Licence : MIT
- Issuer par défaut :
http://127.0.0.1:8181(correspondance exacte — ne substituez paslocalhost)
Avertissement de sécurité
Usage développement et test uniquement. N'exposez jamais ce serveur à Internet et ne le déployez pas en production.
Il dispose d'un sélecteur de personas en mémoire à la place d'une vraie
authentification, génère une nouvelle clé de signature à chaque démarrage, et
n'a pas d'état persistant. Il se lie à 127.0.0.1 par défaut et refuse les
adresses non-loopback sauf si OAUTHSONAS_ALLOW_NON_LOOPBACK=true est défini
explicitement.
Lisez la politique de sécurité avant de signaler une vulnérabilité.
À quoi ça sert
- Remplacer un fournisseur OIDC externe en développement local et en CI sans court-circuiter le vrai flux navigateur de la partie cliente.
- Exercer la découverte, Authorization Code + S256 PKCE, la préservation du
statede callback, l'échange de tokens, la validation JWKS, userinfo, logout et la rotation des refresh tokens. - Fournir des claims applicatifs stables (
roles,org_idoptionnel,membershipsoptionnel) avec des noms de claims configurables. - Garder des identités reproductibles en YAML tout en laissant l'autorisation applicative et l'expansion rôle → permissions à la partie cliente.
Ce que ce n'est pas
Il n'y a intentionnellement pas de base de données, de flux mot de passe, d'API d'admin, d'UI de provisioning, d'API Organizations / Management Auth0, de fournisseur d'identité externe, ni de manifeste de déploiement production. Tout l'état protocole est en mémoire — redémarrez le processus pour effacer codes et tokens émis.
Démarrage rapide
-
Démarrez le fournisseur avec le client et les personas d'exemple :
go run ./cmd/oauthsonas --config config.example.yaml -
Pointez votre dashboard (ou autre RP) vers les variables de l'exemple dashboard.
-
Lancez le flux de login et choisissez un persona sur la page d'autorisation locale (par exemple Acme Administrator).
-
Le callback reçoit un code d'autorisation normal ; la bibliothèque OIDC l'échange et valide les tokens RS256 contre le JWKS publié.
Valider la configuration sans démarrer le serveur :
go run ./cmd/oauthsonas --config config.example.yaml --check-config
Afficher la version :
oauthsonas --version
Découverte :
http://127.0.0.1:8181/.well-known/openid-configuration
Exécuter dans un conteneur
podman build -t oauthsonas -f Containerfile .
podman run --rm -p 127.0.0.1:8181:8181 \
-e OAUTHSONAS_ALLOW_NON_LOOPBACK=true oauthsonas
Docker utilise les mêmes commandes avec docker à la place de podman.
L'image se lie à 0.0.0.0 pour que le port-forwarding fonctionne. Vous devez
définir OAUTHSONAS_ALLOW_NON_LOOPBACK=true pour reconnaître l'exposition.
Gardez le port publié lié à la loopback (-p 127.0.0.1:8181:8181).
Images publiées (après un tag Git SemVer) :
podman pull ghcr.io/optimiweb/oauthsonas:1.2.3
podman run --rm -p 127.0.0.1:8181:8181 \
-e OAUTHSONAS_ALLOW_NON_LOOPBACK=true \
ghcr.io/optimiweb/oauthsonas:1.2.3
Pousser v1.2.3 publie 1.2.3, 1.2, 1 et latest. Les tags pre-release
tels que v1.2.3-rc.1 publient uniquement leur version exacte et ne déplacent
pas latest.
Exemple dashboard
Configurez un dashboard navigateur avec l'équivalent de sa bibliothèque OIDC :
OIDC_AUTHORITY=http://127.0.0.1:8181
OIDC_CLIENT_ID=dashboard
OIDC_REDIRECT_URI=http://127.0.0.1:5173/auth/callback
OIDC_POST_LOGOUT_REDIRECT_URI=http://127.0.0.1:5173/
OIDC_SCOPE="openid profile email"
OIDC_AUDIENCE=https://api.optimicdn.test
Le client d'exemple est public et exige S256 PKCE. La page
d'autorisation laisse un développeur choisir un persona configuré, puis
redirige vers le callback du dashboard avec un code d'autorisation normal et un
state inchangé.
Pour clients, personas, noms de claims et TTL, voir Configuration.
Comportement protocole
- Flux : Authorization Code avec S256 PKCE obligatoire,
response_type=codeet scopeopenid. - Scopes :
openid,profile,email, et optionnellementoffline_access. - Audience : optionnelle à l'authorize ; si fournie elle doit égaler
exactement
api_audience. Les access tokens utilisent toujours cette audience API. - Refresh :
offline_accessémet un refresh token. Fosite fait tourner les refresh tokens et détecte/rejette la réutilisation. Fournirscopeau refresh ne peut que réduire la portée ; l'ensemble plus étroit devient le grant du token rotaté. - Codes : courte durée de vie et à usage unique. Le
stateest renvoyé inchangé. Les nonces sont copiés dans les ID tokens. - Userinfo :
GETouPOST /userinfovalide le bearer access token et renvoie le sous-ensemble de claims profil/personnalisés accordé. - Logout :
GET /logoutne redirige que vers unpost_logout_redirect_urienregistré. Avecid_token_hint, le client est dérivé de l'auddu token (logout initié par le RP sansclient_idexplicite).
Endpoints
| Méthode | Chemin | Rôle |
|---|---|---|
GET | /healthz | Liveness |
GET | /readyz | Readiness |
GET | /.well-known/openid-configuration | Découverte |
GET | /.well-known/jwks.json | Clés publiques de signature |
GET | /oauth2/auth | Autorisation (sélecteur de personas) |
POST | /oauth2/auth/select | Sélection de persona |
POST | /oauth2/token | Endpoint token |
GET | POST | /userinfo | Userinfo |
GET | /logout | Logout initié par le RP |
Santé et readiness
GET /healthz renvoie 200 :
{"status":"ok","version":"1.0.0","issuer":"http://127.0.0.1:8181","uptime":"5m23s"}
GET /readyz renvoie 200 une fois le serveur prêt :
{"status":"ready","issuer":"http://127.0.0.1:8181"}
Les deux définissent Cache-Control: no-store. Utilisez-les pour les probes
Kubernetes ou le signalement d'orchestration.
Journalisation structurée
Le serveur utilise log/slog en JSON (défaut) ou texte :
--log-format json|text (défaut : json)
--log-level debug|info|warn|error (défaut : info)
Attributs de requête : method, path, status, duration. Les événements
OAuth ajoutent client_id, des champs grant/persona, et un interaction_id
tronqué le cas échéant. Jamais journalisés : codes d'autorisation,
access/refresh/ID tokens, cookies, valeurs CSRF ou vérificateurs PKCE.
Contraintes Kubernetes
oauthsonas est conçu pour des déploiements single-replica uniquement :
- Une réplique max. Tokens, codes, interactions et clés de signature sont locaux au processus. Plusieurs répliques provoquent des décalages de cookies et un JWKS invalide.
- Pas de rolling surge. Utilisez
strategy: Recreate. Un second pod génèrerait une clé différente et casserait la validation. - Pas d'équilibrage de charge partagé entre instances.
- Un redémarrage invalide tout — tous les tokens et codes émis sont perdus.
- Utilisez
/healthzpour la liveness et/readyzpour la readiness.
Le serveur garbage-collecte l'état expiré en mémoire. Pour les instances longues, envisagez un cycle de vie de processus qui redémarre périodiquement le pod.
Automation navigateur
Le sélecteur de personas expose des sélecteurs stables pour Playwright, Cypress et outils similaires.
| Élément | Sélecteur |
|---|---|
| Formulaire persona | form[data-testid="persona-form-<id>"] ou .persona-form |
| Champ CSRF | input[data-testid="csrf-input"] |
| Interaction ID | input[data-testid="interaction-id-input"] |
| Soumission | button[data-testid="persona-select-<id>"] |
Flux
- Naviguez vers
GET /oauth2/auth?…avec les paramètres OIDC standard. - La page contient un
<form>par persona. - Extrayez
csrfetinteraction_iddes champs cachés. POST /oauth2/auth/selectaveccsrf,interaction_idetpersona.- Attendez un 302 vers le
redirect_urienregistré aveccodeetstate. - Échangez le code à
POST /oauth2/token.
Exigences : inclure le cookie oauthsonas_interaction_<id> de l'étape 1 ; le
CSRF est à usage unique (replay → 403) ; paramètres de formulaire en double →
400.
Tester et contribuer
go test -race ./...
go vet ./...
Voir CONTRIBUTING.md pour les guidelines de pull request.
Suite
- Configuration — clients YAML, personas, claims et TTL.
- Vue d'ensemble open source — autres projets Optimi.
