fix(api): redirect the OIDC callback to FrontendURL, not a relative path

handleSessionCallback's redirects (success and all 4 failure branches)
were relative paths, which resolve against the backend's own origin --
broken in this project's own supported split-origin local dev setup,
since the Go backend serves no "/" route at all. Now uses the new
config.Config.FrontendURL (defaults to PublicBaseURL, so no change for
single-origin production deployments).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-25 22:52:15 +02:00
parent f93aa331d9
commit db2e8e487d
3 changed files with 14 additions and 8 deletions

View File

@@ -21,6 +21,10 @@ type SessionConfig struct {
// providers, including Keycloak, require this to be an absolute URL
// matching one registered on the client, not a bare relative path.
PublicBaseURL string
// FrontendURL is the origin the browser should land on after the OIDC
// callback (success or failure) -- see config.Config.FrontendURL for why
// this can differ from PublicBaseURL in a split-origin deployment.
FrontendURL string
}
type sessionMeResponse struct {
@@ -49,7 +53,7 @@ func (s *Server) handleSessionCallback(w http.ResponseWriter, r *http.Request) {
txnCookie, err := r.Cookie(auth.TxnCookieName)
if err != nil {
log.Printf("session callback: missing txn cookie: %v", err)
http.Redirect(w, r, "/?auth_error=failed", http.StatusFound)
http.Redirect(w, r, s.Session.FrontendURL+"/?auth_error=failed", http.StatusFound)
return
}
http.SetCookie(w, auth.ClearCookie(auth.TxnCookieName, s.Session.Secure))
@@ -57,18 +61,18 @@ func (s *Server) handleSessionCallback(w http.ResponseWriter, r *http.Request) {
txn, err := auth.ParseTxnCookie(txnCookie, s.Session.Secret)
if err != nil {
log.Printf("session callback: failed to parse txn cookie: %v", err)
http.Redirect(w, r, "/?auth_error=failed", http.StatusFound)
http.Redirect(w, r, s.Session.FrontendURL+"/?auth_error=failed", http.StatusFound)
return
}
result, err := s.Auth.HandleCallback(r.Context(), txn, r.URL.Query())
if err != nil {
log.Printf("session callback: HandleCallback failed (state mismatch, code exchange, or ID-token verification): %v", err)
http.Redirect(w, r, "/?auth_error=failed", http.StatusFound)
http.Redirect(w, r, s.Session.FrontendURL+"/?auth_error=failed", http.StatusFound)
return
}
if !result.Authorized {
http.Redirect(w, r, "/?auth_error=forbidden", http.StatusFound)
http.Redirect(w, r, s.Session.FrontendURL+"/?auth_error=forbidden", http.StatusFound)
return
}
@@ -78,7 +82,7 @@ func (s *Server) handleSessionCallback(w http.ResponseWriter, r *http.Request) {
return
}
http.SetCookie(w, sessionCookie)
http.Redirect(w, r, "/", http.StatusFound)
http.Redirect(w, r, s.Session.FrontendURL+"/", http.StatusFound)
}
func (s *Server) handleSessionLogout(w http.ResponseWriter, r *http.Request) {