Corrige la déconnexion : accepter le POST de formulaire (urlencoded)
All checks were successful
Publier l'image Docker / test (push) Successful in 17s
Publier l'image Docker / publish (push) Successful in 9s

Le <form> de déconnexion envoie `application/x-www-form-urlencoded` ;
Fastify n'ayant aucun parseur pour ce type répondait 415
(FST_ERR_CTP_INVALID_MEDIA_TYPE) avant même d'atteindre le handler.

Ajout d'un parseur `application/x-www-form-urlencoded` (URLSearchParams
-> objet, sans dépendance). Le test de déconnexion envoie désormais
l'en-tête du navigateur pour couvrir le cas.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Nicolas 2026-09-10 19:48:15 +02:00
parent 8d8cfb6fad
commit 60d7ba1c39
2 changed files with 19 additions and 1 deletions

View file

@ -68,6 +68,20 @@ export async function buildApp(
taskDone(null, payload);
});
// Formulaires HTML (déconnexion) : sinon Fastify répond 415 sur le POST du <form>.
app.addContentTypeParser(
'application/x-www-form-urlencoded',
{ parseAs: 'string' },
(_request, body: string | Buffer, taskDone) => {
try {
const raw = typeof body === 'string' ? body : body.toString('utf8');
taskDone(null, Object.fromEntries(new URLSearchParams(raw)));
} catch (error) {
taskDone(error instanceof Error ? error : new Error('Corps de formulaire invalide'));
}
},
);
await app.register(secureSession, {
key: config.session.key,
cookieName: SESSION_COOKIE_NAME,

View file

@ -71,11 +71,15 @@ describe('flux d’authentification', () => {
expect(me.json()).toEqual({ authenticated: true, name: 'Alice' });
});
it('POST /auth/logout vide la session', async () => {
it('POST /auth/logout vide la session (soumission de <form> HTML)', async () => {
const cookie = await login(app, idp);
// Le navigateur envoie un POST application/x-www-form-urlencoded : le serveur
// doit l'accepter (et non répondre 415).
const out = await app.inject({
method: 'POST',
url: '/auth/logout',
headers: { 'content-type': 'application/x-www-form-urlencoded' },
payload: '',
cookies: { [SESSION_COOKIE]: cookie },
});
expect(out.statusCode).toBe(302);