From d946926c36dd3e1e06743f28a494b5ae01ead7d0 Mon Sep 17 00:00:00 2001 From: Stavros Date: Tue, 14 Jul 2026 16:36:57 +0300 Subject: [PATCH] feat: allow existing query params in oidc redirect uri (#1003) --- internal/controller/oidc_controller.go | 63 ++++++++++++++------------ 1 file changed, 34 insertions(+), 29 deletions(-) diff --git a/internal/controller/oidc_controller.go b/internal/controller/oidc_controller.go index 0c5ac918..59856244 100644 --- a/internal/controller/oidc_controller.go +++ b/internal/controller/oidc_controller.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "net/http" + "net/url" "slices" "strconv" "strings" @@ -343,27 +344,31 @@ func (controller *OIDCController) authorizeComplete(c *gin.Context) { // Create the authorization code code := controller.oidc.CreateCode(*authorizeReq, *userContext) - queries, err := query.Values(AuthorizeCallback{ - Code: code, - State: authorizeReq.State, - }) + cu, err := url.Parse(authorizeReq.RedirectURI) if err != nil { controller.authorizeError(c, authorizeErrorParams{ - err: err, - reason: "Failed to build query", - reasonPublic: "Failed to build query", - callback: authorizeReq.RedirectURI, - callbackError: "server_error", - state: authorizeReq.State, - json: true, + err: err, + reason: "Failed to parse redirect URI", + reasonPublic: "Failed to parse redirect URI", + json: true, }) return } + q := cu.Query() + + q.Set("code", code) + + if authorizeReq.State != "" { + q.Set("state", authorizeReq.State) + } + + cu.RawQuery = q.Encode() + c.JSON(200, gin.H{ "status": 200, - "redirect_uri": fmt.Sprintf("%s?%s", authorizeReq.RedirectURI, queries.Encode()), + "redirect_uri": cu.String(), }) } @@ -639,37 +644,37 @@ func (controller *OIDCController) authorizeError(c *gin.Context, params authoriz controller.log.App.Error().Err(params.err).Str("reason", params.reason).Msg("Authorization error") if params.callback != "" { - errorQueries := CallbackError{ - Error: params.callbackError, - } - - if params.reasonPublic != "" { - errorQueries.ErrorDescription = params.reasonPublic - } - - if params.state != "" { - errorQueries.State = params.state - } - - queries, err := query.Values(errorQueries) + cu, err := url.Parse(params.callback) if err != nil { - controller.log.App.Error().Err(err).Msg("Failed to build callback error query") + controller.log.App.Error().Err(err).Msg("Failed to parse callback URL") c.AbortWithStatus(http.StatusInternalServerError) return } - redirectUrl := fmt.Sprintf("%s?%s", params.callback, queries.Encode()) + q := cu.Query() + + q.Set("error", params.callbackError) + + if params.reasonPublic != "" { + q.Set("error_description", params.reasonPublic) + } + + if params.state != "" { + q.Set("state", params.state) + } + + cu.RawQuery = q.Encode() if params.json { c.JSON(200, gin.H{ "status": 200, - "redirect_uri": redirectUrl, + "redirect_uri": cu.String(), }) return } - c.Redirect(http.StatusFound, redirectUrl) + c.Redirect(http.StatusFound, cu.String()) return }