diff --git a/pkg/auth/pages.go b/pkg/auth/pages.go
index 88d6c731..a7396557 100644
--- a/pkg/auth/pages.go
+++ b/pkg/auth/pages.go
@@ -17,7 +17,8 @@ limitations under the License.
package auth
import (
- "fmt"
+ "encoding/json"
+ "html/template"
"log/slog"
"net/http"
)
@@ -25,14 +26,19 @@ import (
const pageStyle = `font-family:system-ui,sans-serif;display:flex;` +
`justify-content:center;align-items:center;height:100vh;margin:0`
+// JS redirect + clickable fallback is more reliable than meta-refresh for
+// Cursor's cursor:// and http://localhost:8787/callback handoffs.
const redirectPageTmpl = `
-%s
-
+{{.Message}}
-
+
+
`
@@ -40,26 +46,65 @@ const callbackPageTmpl = `
Authentication Successful
-
Authentication complete
-
You may now close this window.
+
Returning to Cursor…
+
If Cursor stays on “waiting for callback”, click:
+
Open Cursor callback
+
`
+type redirectPageData struct {
+ Message string
+ // URL is typed template.URL (rather than string) because html/template
+ // otherwise sanitizes href values against a scheme allowlist that does
+ // NOT include custom schemes like cursor:// — an untyped string would
+ // silently render as the inert placeholder "#ZgotmplZ" instead of the
+ // real link. Callers must only pass already-validated redirect URIs
+ // (see isValidRedirectURI / HandleRegister's scheme checks).
+ URL template.URL
+ URLJS template.JS
+}
+
func writeRedirectPage(w http.ResponseWriter, targetURL, message string) {
+ writeHTMLTemplate(w, redirectPageTmpl, redirectPageData{
+ Message: message,
+ URL: template.URL(targetURL),
+ URLJS: jsString(targetURL),
+ })
+}
+
+func writeCallbackPage(w http.ResponseWriter, redirectURL string) {
+ writeHTMLTemplate(w, callbackPageTmpl, redirectPageData{
+ URL: template.URL(redirectURL),
+ URLJS: jsString(redirectURL),
+ })
+}
+
+func writeHTMLTemplate(w http.ResponseWriter, tmpl string, data redirectPageData) {
w.Header().Set("Content-Type", "text/html; charset=utf-8")
- if _, err := fmt.Fprintf(w, redirectPageTmpl, message, targetURL, message); err != nil {
+ t, err := template.New("page").Parse(tmpl)
+ if err != nil {
+ slog.Error("failed to parse redirect page template", "error", err)
+ http.Error(w, "internal error", http.StatusInternalServerError)
+ return
+ }
+ if err := t.Execute(w, data); err != nil {
slog.Error("failed to write redirect page", "error", err)
}
}
-func writeCallbackPage(w http.ResponseWriter, redirectURL string) {
- w.Header().Set("Content-Type", "text/html; charset=utf-8")
- if _, err := fmt.Fprintf(w, callbackPageTmpl, redirectURL); err != nil {
- slog.Error("failed to write callback page", "error", err)
+// jsString returns s as a safely-quoted JS string literal for embedding
+// directly inside a