From 29dd2cb3e5c556b57ecfb6123d956adc25cbd591 Mon Sep 17 00:00:00 2001 From: Jason Ernst Date: Fri, 25 Sep 2026 11:06:18 -0700 Subject: [PATCH 1/2] Link to /login/github instead of building the OAuth URL here MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The GitHub button used to assemble GitHub's authorize URL in an inline script, concatenating window.location straight into redirect_uri; a next containing & ended the value early and the rest reached GitHub as further authorize parameters (goblog #631). goblog builds the URL now, so this is a plain anchor at /login/github carrying an escaped next — no client_id in the page and no inline script. Needs goblog with #631 for the /login/github route. Co-Authored-By: Claude Opus 5 (1M context) --- templates/login.html | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/templates/login.html b/templates/login.html index 0362902..647d4fe 100644 --- a/templates/login.html +++ b/templates/login.html @@ -54,16 +54,10 @@

Sign In

Log in to manage {{ .settings.site_title.Value }}

- + Continue with GitHub - - {{ if .email_login_enabled }}

or sign in with email

From 7577ebde5a08e441e7146c5691389101dc2c60dc Mon Sep 17 00:00:00 2001 From: Jason Ernst Date: Fri, 25 Sep 2026 13:20:05 -0700 Subject: [PATCH 2/2] Drop the ?code= block: the server handles GitHub's return now goblog exchanges the code at /login itself, against a state it minted, so this block can never fire (goblog #637). It was also the client half of the login CSRF: it posted whatever code appeared in the query to /api/login, which no longer exists. The email-login endpoints are posted to relatively rather than rebuilding an origin, since the variable holding it went with the removed block. Needs goblog with #637. Co-Authored-By: Claude Opus 5 (1M context) --- templates/login.html | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/templates/login.html b/templates/login.html index 647d4fe..bb6d190 100644 --- a/templates/login.html +++ b/templates/login.html @@ -5,19 +5,8 @@ // script has run by the time DOMContentLoaded fires, which also makes the // old $(function () { ... }) wrapper redundant. document.addEventListener("DOMContentLoaded", function () { - var host = location.protocol + '//' + window.location.host - var urlParams = new URLSearchParams(window.location.search); - var code = urlParams.get('code'); // Where to go after logging in; validated server-side to a same-site path. var next = {{ .next }}; - - if (code) { - var post = $.post(host + "/api/login", {"code": code}); - post.done(function(data) { - window.location.href = next; - }); - } - var emailForm = $("#email-form"), codeForm = $("#code-form"), status = $("#email-login-status"), change = $("#email-change"); if (!emailForm.length) { return; } @@ -27,7 +16,7 @@ emailForm.on("submit", function (e) { e.preventDefault(); status.text(""); - $.post(host + "/api/login/email", {email: $("#email-input").val()}) + $.post("/api/login/email", {email: $("#email-input").val()}) .done(function () { emailForm.hide(); codeForm.css("display", "flex"); change.show(); status.text("Check your inbox for a 6-digit code."); @@ -38,7 +27,7 @@ codeForm.on("submit", function (e) { e.preventDefault(); status.text(""); - $.post(host + "/api/login/email/verify", {email: $("#email-input").val(), code: $("#code-input").val()}) + $.post("/api/login/email/verify", {email: $("#email-input").val(), code: $("#code-input").val()}) .done(function () { window.location.href = next; }) .fail(function (xhr) { showError(xhr, "Could not verify the code."); }); });