RFC 0013 — Fediverse: routes HTTP du flow d'auth AP-native (slice routes 2/N)
- Auteur : EBO (rustwarden)
- Date : 2026-05-10
- Statut : Accepted (auto-revue mainteneur unique 2026-05-10, score 26/35)
- Apps consommatrices concernées : toute app utilisant
rustwarden-corequi veut permettre à un utilisateur d'un IdP fediverse externe de se connecter via HTTP/JSON. - Plan associé :
docs/plans/2026-05-09-fediverse-identity-federation.md, Phase 2 — clôture HTTP. - Dépendances : RFC 0006 (
FediverseAuthService), RFC 0011 (FediverseOutboundService), RFC 0012 (pattern routes +SignatureVerifier).
Summary
Exposer 5 routes HTTP qui rendent FediverseAuthService (RFC 0006) utilisable end-to-end :
POST /api/v1/auth/login/fediverse/initiate(côté clientb.tld) — démarre un challenge.GET /api/v1/auth/login/fediverse/status/{challenge_id}— polling.POST /api/v1/auth/login/fediverse/consume/{challenge_id}— émet le JWT remote depuis un challengeApproved.POST /fediverse/auth/inbox(côté IdPa.tld) — reçoit l'AuthRequestsigné d'un autre Rustwarden.POST /api/v1/fediverse/auth/consent(côté IdP) — Approve / Reject par l'utilisateur.
Le code reste minimal : chaque handler est un thin wrapper autour du service. Aucune UI n'est livrée (Phase 2 finale UI), aucune crypto réelle n'est ajoutée.
Motivation
Sans cette RFC, FediverseAuthService n'a aucun chemin HTTP : un consommateur souhaitant le flow doit écrire ses 5 handlers à la main. La promesse Phase 2 du master plan « 2 instances locales : bob@a.tld se connecte sur b.tld » est encore non-tenable.
Non-goals
- Pas de UI HTML (pages
/login/fediverse,/login/fediverse/waiting,/fediverse/consent) —rustwarden-uiPhase 2 finale. - Pas de polling SSE — les apps qui veulent un long-poll envelopperont
statuscôté handler de leur app. - Pas de signature HTTP réelle — le verifier reste pluggable (
SignatureVerifierde RFC 0010),AlwaysAcceptVerifierpar défaut. - Pas de CSRF middleware sur les API JSON — les apps consommatrices configurent leur middleware (Axum-level) selon leur SPA.
- Pas de routes team-invite — RFC 0014.
API proposée
Bodies JSON
// POST /api/v1/auth/login/fediverse/initiate #[derive(Deserialize)] pub struct InitiateBody { pub handle: String, pub redirect_url: Option<String> } #[derive(Serialize)] pub struct InitiateResponse { pub challenge_id: Uuid, pub nonce: String, pub expires_at: String /* RFC3339 */ } // GET /api/v1/auth/login/fediverse/status/{challenge_id} #[derive(Serialize)] pub struct StatusResponse { pub challenge_id: Uuid, pub status: String /* pending|approved|rejected|expired|consumed */ } // POST /api/v1/auth/login/fediverse/consume/{challenge_id} #[derive(Serialize)] pub struct ConsumeResponse { pub jwt: String, pub remote_identity_id: Uuid, pub handle: String } // POST /fediverse/auth/inbox (IdP side) // body : raw AP `AuthRequest` JSON-LD (vérifié par SignatureVerifier). // Retour : 202 Accepted (challenge enregistré, l'utilisateur sera invité à // approuver via UI ou via l'API consent ci-dessous). // POST /api/v1/fediverse/auth/consent #[derive(Deserialize)] pub struct ConsentBody { pub challenge_id: Uuid, pub decision: String /* "approve"|"reject" */ }
Câblage
Le RustwardenBuilder::with_fediverse() mounte les 5 routes via une nouvelle fonction routes::auth_flow_router(...) chaînée après inbox. Les routes API JSON utilisent une AuthConfig partagée (la même qui sert au flow login local).
États HTTP
| Endpoint | Succès | Erreurs |
|---|---|---|
initiate | 201 Created | 400 handle invalide |
status | 200 OK | 404 challenge inconnu |
consume | 200 OK | 400 non Approved, 409 déjà Consumed |
auth/inbox | 202 Accepted | 401 signature, 400 body |
consent | 200 OK | 404 challenge inconnu, 409 déjà décidé |
Analyse de compatibilité
-
Non-breaking : 5 nouveaux paths, gated par
experimental-fediverse. - Pas de schéma DB.
- Aucune API publique existante n'est modifiée.
Alternatives considérées
Alternative A (recommandée) — 5 endpoints REST minces
Pros : conforme aux conventions JSON existantes ; SPA-friendly ; reste dans l'esprit Phase 2.
Cons : 5 paths à mémoriser pour le consommateur.
Alternative B — Endpoint unique /api/v1/auth/login/fediverse avec champ action
Cons : nuit à la lisibilité de l'audit log + des middlewares de rate-limit.
Rejeté.
Alternative C — Tout en GraphQL
Cons : hors stack actuelle.
Rejeté.
Alternative D — Ne rien faire
Cons : Phase 2 reste théorique.
Rejeté.
Testing plan
10 tests :
initiate_returns_201_with_challenge_id.initiate_returns_400_for_invalid_handle.status_returns_pending_for_fresh_challenge.status_returns_404_for_unknown_id.consume_returns_jwt_for_approved_challenge.consume_returns_400_when_pending.auth_inbox_returns_202_for_signed_authrequest.auth_inbox_returns_401_when_signature_missing.consent_approve_marks_challenge_approved.consent_reject_marks_challenge_rejected.
Tests via axum::Router + tower::ServiceExt::oneshot.
Migration guide
### Added (rustwarden-core, feature `experimental-fediverse`) - 5 routes HTTP : `POST /api/v1/auth/login/fediverse/initiate`, `GET /api/v1/auth/login/fediverse/status/{id}`, `POST /api/v1/auth/login/fediverse/consume/{id}`, `POST /fediverse/auth/inbox`, `POST /api/v1/fediverse/auth/consent`. - Module `rustwarden_core::fediverse::auth_routes`. - Bodies / responses publics : `InitiateBody`, `InitiateResponse`, `StatusResponse`, `ConsumeResponse`, `ConsentBody`. ### Migration steps 1. Aucun changement obligatoire : les routes ne sont mountées que si `with_fediverse()` est appelé (déjà gated par feature). 2. Apps consommatrices SPA : peuvent maintenant piloter le flow complet via JSON.
Open questions
Toutes résolues à l'auto-revue :
-
TTL challenge :
fediverse.auth_challenge_ttl_secs(300 s par défaut). -
auth/inboxpath :/fediverse/auth/inbox(distinct de/inboxqui sert les signaux lifecycle, scope clair). -
Rate limiting : pas dans cette RFC ; les apps appliquent leur middleware comme pour
/api/v1/auth/login.
Tracking issue
À ouvrir au moment de la PR.
Score d'évaluation
| Critère | Note (1-5) | Commentaire |
|---|---|---|
| Généralité | 4 | Endpoints standards REST, faciles à wrapper en SPA. |
| Stabilité API | 4 | Additif, gated. |
| Performance | 4 | Tous les handlers sont O(1) lookups. |
| Sécurité | 3 | Pas de rate-limit dans cette RFC, pas de CSRF (API JSON). |
| Complexité d'implémentation | 4 | ~500 lignes (5 handlers + state + 10 tests). |
| Maintenance | 3 | 5 nouveaux paths à conserver compatibles. |
| Documentation | 4 | Rustdoc EN, doctest, CHANGELOG, migration guide. |
| Total | 26/35 | ≥ 25 → Accepted |
GitRust