From b54146ce5b1d1eed1003ca2d046e746e90381b43 Mon Sep 17 00:00:00 2001 From: svemagie <869694+svemagie@users.noreply.github.com> Date: Fri, 27 Mar 2026 16:47:42 +0100 Subject: [PATCH] fix(oauth): echo state parameter back in authorization redirect MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit OAuth 2.0 requires the server to echo the state parameter in the callback redirect. Mastodon clients (e.g. murmel.social) send a state value and fail with 'missing parameters' if it is absent. Thread state through: GET query → session store → hidden form field → POST body → callback redirect (approve and deny paths). --- lib/mastodon/routes/oauth.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/mastodon/routes/oauth.js b/lib/mastodon/routes/oauth.js index 20cd096..2ca8a87 100644 --- a/lib/mastodon/routes/oauth.js +++ b/lib/mastodon/routes/oauth.js @@ -206,6 +206,7 @@ router.get("/oauth/authorize", async (req, res, next) => { code_challenge, code_challenge_method, force_login, + state, } = req.query; // Restore OAuth params from session after login redirect. @@ -221,6 +222,7 @@ router.get("/oauth/authorize", async (req, res, next) => { scope = p.scope; code_challenge = p.code_challenge; code_challenge_method = p.code_challenge_method; + state = p.state; } if (response_type !== "code") { @@ -262,7 +264,7 @@ router.get("/oauth/authorize", async (req, res, next) => { // login redirect chain due to a re-encoding bug in indieauth.js. req.session.pendingOAuth = { client_id, redirect_uri, response_type, scope, - code_challenge, code_challenge_method, + code_challenge, code_challenge_method, state, }; // Redirect to Indiekit's login page with a simple return path. return res.redirect("/session/login?redirect=/oauth/authorize"); @@ -300,6 +302,7 @@ router.get("/oauth/authorize", async (req, res, next) => { +