Compare commits

...

2 Commits

Author SHA1 Message Date
copilot-swe-agent[bot]
9d28a855c4 Fix OAuth state parameter re-encoding in redirect URL to prevent state mismatch
Co-authored-by: hsluoyz <3787410+hsluoyz@users.noreply.github.com>
2026-03-12 13:55:51 +00:00
copilot-swe-agent[bot]
726cf1082b Initial plan 2026-03-12 13:45:30 +00:00
4 changed files with 5 additions and 12 deletions

View File

@@ -1414,7 +1414,7 @@ func (c *ApiController) Callback() {
code := c.GetString("code")
state := c.GetString("state")
frontendCallbackUrl := fmt.Sprintf("/callback?code=%s&state=%s", code, state)
frontendCallbackUrl := fmt.Sprintf("/callback?code=%s&state=%s", url.QueryEscape(code), url.QueryEscape(state))
c.Ctx.Redirect(http.StatusFound, frontendCallbackUrl)
}

View File

@@ -144,9 +144,6 @@
}
var state = getRefinedValue(innerParams.get("state"));
if (state.indexOf("/auth/oauth2/login.php?wantsurl") === 0) {
state = encodeURIComponent(state);
}
if (redirectUri.indexOf("#") !== -1 && state === "") {
state = getRawGetParameter("state", queryString);
}
@@ -373,7 +370,7 @@
if (responseMode === "form_post") {
createFormAndSubmit(oAuthParams.redirectUri, {code: res.data, state: oAuthParams.state});
} else {
window.location.replace(oAuthParams.redirectUri + concatChar + "code=" + res.data + "&state=" + oAuthParams.state);
window.location.replace(oAuthParams.redirectUri + concatChar + "code=" + encodeURIComponent(res.data) + "&state=" + encodeURIComponent(oAuthParams.state));
}
return;
}
@@ -387,7 +384,7 @@
state: oAuthParams.state
});
} else {
window.location.replace(oAuthParams.redirectUri + concatChar + responseType + "=" + res.data + "&state=" + oAuthParams.state + "&token_type=bearer");
window.location.replace(oAuthParams.redirectUri + concatChar + responseType + "=" + encodeURIComponent(res.data) + "&state=" + encodeURIComponent(oAuthParams.state) + "&token_type=bearer");
}
return;
}

View File

@@ -116,7 +116,7 @@ class AuthCallback extends React.Component {
createFormAndSubmit(oAuthParams?.redirectUri, params);
} else {
const code = res.data;
Setting.goToLink(`${oAuthParams.redirectUri}${concatChar}code=${code}&state=${oAuthParams.state}`);
Setting.goToLink(`${oAuthParams.redirectUri}${concatChar}code=${encodeURIComponent(code)}&state=${encodeURIComponent(oAuthParams.state)}`);
}
} else if (responseTypes.includes("token") || responseTypes.includes("id_token")) {
if (res.data3) {
@@ -135,7 +135,7 @@ class AuthCallback extends React.Component {
createFormAndSubmit(oAuthParams?.redirectUri, params);
} else {
const token = res.data;
Setting.goToLink(`${oAuthParams.redirectUri}${concatChar}${responseType}=${token}&state=${oAuthParams.state}&token_type=bearer`);
Setting.goToLink(`${oAuthParams.redirectUri}${concatChar}${responseType}=${encodeURIComponent(token)}&state=${encodeURIComponent(oAuthParams.state)}&token_type=bearer`);
}
} else if (responseType === "link") {
let from = innerParams.get("from");

View File

@@ -130,10 +130,6 @@ export function getOAuthGetParameters(params) {
}
let state = getRefinedValue(queries.get("state"));
if (state.startsWith("/auth/oauth2/login.php?wantsurl")) {
// state contains URL param encoding for Moodle, URLSearchParams automatically decoded it, so here encode it again
state = encodeURIComponent(state);
}
if (redirectUri.includes("#") && state === "") {
state = getRawGetParameter("state");
}