# HG changeset patch
# User Kim Alvefur <zash@zash.se>
# Date 1682444981 -7200
# Node ID 93d445b260637520aa0075c7dd5606a62286a97a
# Parent  db4c66a1d24b9987aa538ff34ac7b46e09d83abd
mod_http_oauth2: Validate redirect URI depending on application type

Per https://openid.net/specs/openid-connect-registration-1_0.html
require that web applications use https:// and native applications must
use either http://localhost or a custom (non-https) URI.

Previous requirement that hostname matches that of client_uri is kept
for web applications.

diff -r db4c66a1d24b -r 93d445b26063 mod_http_oauth2/mod_http_oauth2.lua
--- a/mod_http_oauth2/mod_http_oauth2.lua	Tue Apr 25 18:09:08 2023 +0200
+++ b/mod_http_oauth2/mod_http_oauth2.lua	Tue Apr 25 19:49:41 2023 +0200
@@ -657,6 +657,7 @@
 			};
 			default = { "authorization_code" };
 		};
+		application_type = { type = "string"; enum = { "native"; "web" }; default = "web" };
 		response_types = { type = "array"; items = { type = "string"; enum = { "code"; "token" } }; default = { "code" } };
 		client_name = { type = "string" };
 		client_uri = { type = "string"; format = "uri"; luaPattern = "^https:" };
@@ -677,6 +678,15 @@
 	};
 }
 
+local function redirect_uri_allowed(redirect_uri, client_uri, app_type)
+	local uri = url.parse(redirect_uri);
+	if app_type == "native" then
+		return uri.scheme == "http" and uri.host == "localhost" or uri.scheme ~= "https";
+	elseif app_type == "web" then
+		return uri.scheme == "https" and uri.host == client_uri.host;
+	end
+end
+
 function create_client(client_metadata)
 	if not schema.validate(registration_schema, client_metadata) then
 		return nil, oauth_error("invalid_request", "Failed schema validation.");
@@ -695,13 +705,8 @@
 	end
 
 	for _, redirect_uri in ipairs(client_metadata.redirect_uris) do
-		local components = url.parse(redirect_uri);
-		if not components or not components.scheme then
-			return nil, oauth_error("invalid_request", "Invalid redirect URI.");
-		elseif components.scheme == "http" and components.host ~= "localhost" then
-			return nil, oauth_error("invalid_request", "Insecure redirect URI forbidden (except http://localhost)");
-		elseif components.scheme == "https" and components.host ~= client_uri.host then
-			return nil, oauth_error("invalid_request", "Redirects must use the same hostname as client_uri");
+		if not redirect_uri_allowed(redirect_uri, client_uri, client_metadata.application_type) then
+			return nil, oauth_error("invalid_request", "Invalid, insecure or inappropriate redirect URI.");
 		end
 	end