@@ -181,7 +181,7 @@ func (h *AuthHandler) V4OAuth2Callback(c echo.Context) error {
181181}
182182
183183func (h * AuthHandler ) oauthRedirectWithError (c echo.Context , provider * OAuthProvider , detail string ) error {
184- u , err := resolveOAuthClientRedirect ( c , provider )
184+ u , err := oauthErrorClientRedirect ( provider )
185185 if err != nil {
186186 return writeError (c , http .StatusBadRequest , "Bad Request" , err .Error ())
187187 }
@@ -191,6 +191,28 @@ func (h *AuthHandler) oauthRedirectWithError(c echo.Context, provider *OAuthProv
191191 return c .Redirect (http .StatusFound , u .String ())
192192}
193193
194+ // oauthErrorClientRedirect returns a safe redirect base for OAuth errors (never uses redirect_uri).
195+ func oauthErrorClientRedirect (provider * OAuthProvider ) (* url.URL , error ) {
196+ configured := strings .TrimSpace (provider .CallbackURL )
197+ if configured == "" {
198+ return & url.URL {Path : "/" }, nil
199+ }
200+ if strings .HasPrefix (configured , "//" ) {
201+ return nil , fmt .Errorf ("invalid provider callback_url" )
202+ }
203+ u , err := url .Parse (configured )
204+ if err != nil {
205+ return nil , fmt .Errorf ("invalid provider callback_url" )
206+ }
207+ if u .Scheme != "" && u .Host != "" {
208+ return u , nil
209+ }
210+ if strings .HasPrefix (u .Path , "/" ) {
211+ return u , nil
212+ }
213+ return nil , fmt .Errorf ("invalid provider callback_url" )
214+ }
215+
194216// resolveOAuthClientRedirect picks a safe post-login redirect URL.
195217// Configured provider.CallbackURL wins; otherwise only same-site relative paths are allowed.
196218func resolveOAuthClientRedirect (c echo.Context , provider * OAuthProvider ) (* url.URL , error ) {
0 commit comments