Repository: zitadel/oidc
Pull request #691 (2024-12-17 09:52:53)

fix: allow native applications to use https:// on loopback redirect addresses
This pull request addresses an issue where native clients were unable to utilize HTTPS for redirects on loopback addresses.

**Changes Made:**
- Updated the redirect validation logic to accommodate HTTPS uri's for native applications

Part of this: https://github.com/zitadel/zitadel/issues/4091



Patch:
diff --git a/pkg/op/auth_request.go b/pkg/op/auth_request.go
index b020f39..d6db62b 100644
--- a/pkg/op/auth_request.go
+++ b/pkg/op/auth_request.go
@@ -312,12 +312,12 @@ func ValidateAuthReqRedirectURI(client Client, uri string, responseType oidc.Res
 		return oidc.ErrInvalidRequestRedirectURI().WithDescription("The redirect_uri is missing in the request. " +
 			"Please ensure it is added to the request. If you have any questions, you may contact the administrator of the application.")
 	}
-	if strings.HasPrefix(uri, "https://") {
-		return checkURIAgainstRedirects(client, uri)
-	}
 	if client.ApplicationType() == ApplicationTypeNative {
 		return validateAuthReqRedirectURINative(client, uri)
 	}
+	if strings.HasPrefix(uri, "https://") {
+		return checkURIAgainstRedirects(client, uri)
+	}
 	if err := checkURIAgainstRedirects(client, uri); err != nil {
 		return err
 	}
@@ -338,12 +338,15 @@ func ValidateAuthReqRedirectURI(client Client, uri string, responseType oidc.Res
 // ValidateAuthReqRedirectURINative validates the passed redirect_uri and response_type to the registered uris and client type
 func validateAuthReqRedirectURINative(client Client, uri string) error {
 	parsedURL, isLoopback := HTTPLoopbackOrLocalhost(uri)
-	isCustomSchema := !strings.HasPrefix(uri, "http://")
+	isCustomSchema := !(strings.HasPrefix(uri, "http://") || strings.HasPrefix(uri, "https://"))
 	if err := checkURIAgainstRedirects(client, uri); err == nil {
 		if client.DevMode() {
 			return nil
 		}
-		// The RedirectURIs are only valid for native clients when localhost or non-"http://"
+		if !isLoopback && strings.HasPrefix(uri, "https://") {
+			return nil
+		}
+		// The RedirectURIs are only valid for native clients when localhost or non-"http://" and "https://"
 		if isLoopback || isCustomSchema {
 			return nil
 		}
@@ -373,11 +376,11 @@ func HTTPLoopbackOrLocalhost(rawURL string) (*url.URL, bool) {
 	if err != nil {
 		return nil, false
 	}
-	if parsedURL.Scheme != "http" {
-		return nil, false
+	if parsedURL.Scheme == "http" || parsedURL.Scheme == "https" {
+		hostName := parsedURL.Hostname()
+		return parsedURL, hostName == "localhost" || net.ParseIP(hostName).IsLoopback()
 	}
-	hostName := parsedURL.Hostname()
-	return parsedURL, hostName == "localhost" || net.ParseIP(hostName).IsLoopback()
+	return nil, false
 }
 
 // ValidateAuthReqResponseType validates the passed response_type to the registered response types


Test patch:
diff --git a/pkg/op/auth_request_test.go b/pkg/op/auth_request_test.go
index 6b4af17..765e602 100644
--- a/pkg/op/auth_request_test.go
+++ b/pkg/op/auth_request_test.go
@@ -433,6 +433,24 @@ func TestValidateAuthReqRedirectURI(t *testing.T) {
 			},
 			false,
 		},
+		{
+			"code flow registered https loopback v4 native ok",
+			args{
+				"https://127.0.0.1:4200/callback",
+				mock.NewClientWithConfig(t, []string{"https://127.0.0.1/callback"}, op.ApplicationTypeNative, nil, false),
+				oidc.ResponseTypeCode,
+			},
+			false,
+		},
+		{
+			"code flow registered https loopback v6 native ok",
+			args{
+				"https://[::1]:4200/callback",
+				mock.NewClientWithConfig(t, []string{"https://[::1]/callback"}, op.ApplicationTypeNative, nil, false),
+				oidc.ResponseTypeCode,
+			},
+			false,
+		},
 		{
 			"code flow unregistered http native fails",
 			args{