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) => { +
@@ -323,6 +326,7 @@ router.post("/oauth/authorize", async (req, res, next) => { scope, code_challenge, code_challenge_method, + state, decision, } = req.body; @@ -365,6 +369,7 @@ router.post("/oauth/authorize", async (req, res, next) => { "error_description", "The resource owner denied the request", ); + if (state) url.searchParams.set("state", state); return redirectToUri(res, redirect_uri, url.toString()); } return res.status(403).json({ @@ -413,9 +418,10 @@ router.post("/oauth/authorize", async (req, res, next) => { `); } - // Redirect with code + // Redirect with code (and state, which must be echoed back per OAuth 2.0 spec) const url = new URL(redirect_uri); url.searchParams.set("code", code); + if (state) url.searchParams.set("state", state); redirectToUri(res, redirect_uri, url.toString()); } catch (error) { next(error);