Repository: jazzband/django-oauth-toolkit

Issue:
/.well-known/openid-configuration is redirected to /.well-known/openid-configuration/
**Describe the bug**
https://openid.net/specs/openid-connect-discovery-1_0.html#rfc.section.4 
specifies the path as /.well-known/openid-configuration

currently when one requests that path they are redirected to /.well-known/openid-configuration
which slows discovery on the client and can cause cors issues with the redirect. 


**To Reproduce**
start up tests/app/idp and open http://localhost:8000/o/.well-known/openid-configuration in your browsers, you will be redirected to 
http://localhost:8000/o/.well-known/openid-configuration/

**Expected behavior**
The JSON is returned and there is no redirect.

**Version**
2.3.0




Discussion:

Resolving patch:
diff --git a/oauth2_provider/settings.py b/oauth2_provider/settings.py
--- a/oauth2_provider/settings.py
+++ b/oauth2_provider/settings.py
@@ -295,7 +295,7 @@ def oidc_issuer(self, request):
         else:
             raise TypeError("request must be a django or oauthlib request: got %r" % request)
         abs_url = django_request.build_absolute_uri(reverse("oauth2_provider:oidc-connect-discovery-info"))
-        return abs_url[: -len("/.well-known/openid-configuration/")]
+        return abs_url[: -len("/.well-known/openid-configuration")]
 
 
 oauth2_settings = OAuth2ProviderSettings(USER_SETTINGS, DEFAULTS, IMPORT_STRINGS, MANDATORY)
diff --git a/oauth2_provider/urls.py b/oauth2_provider/urls.py
--- a/oauth2_provider/urls.py
+++ b/oauth2_provider/urls.py
@@ -31,8 +31,12 @@
 ]
 
 oidc_urlpatterns = [
+    # .well-known/openid-configuration/ is deprecated
+    # https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig
+    # does not specify a trailing slash
+    # Support for trailing slash should shall be removed in a future release.
     re_path(
-        r"^\.well-known/openid-configuration/$",
+        r"^\.well-known/openid-configuration/?$",
         views.ConnectDiscoveryInfoView.as_view(),
         name="oidc-connect-discovery-info",
     ),


Test patch:
diff --git a/tests/test_oidc_views.py b/tests/test_oidc_views.py
--- a/tests/test_oidc_views.py
+++ b/tests/test_oidc_views.py
@@ -50,11 +50,37 @@ def test_get_connect_discovery_info(self):
             "token_endpoint_auth_methods_supported": ["client_secret_post", "client_secret_basic"],
             "claims_supported": ["sub"],
         }
-        response = self.client.get(reverse("oauth2_provider:oidc-connect-discovery-info"))
+        response = self.client.get("/o/.well-known/openid-configuration")
+        self.assertEqual(response.status_code, 200)
+        assert response.json() == expected_response
+
+    def test_get_connect_discovery_info_deprecated(self):
+        expected_response = {
+            "issuer": "http://localhost/o",
+            "authorization_endpoint": "http://localhost/o/authorize/",
+            "token_endpoint": "http://localhost/o/token/",
+            "userinfo_endpoint": "http://localhost/o/userinfo/",
+            "jwks_uri": "http://localhost/o/.well-known/jwks.json",
+            "scopes_supported": ["read", "write", "openid"],
+            "response_types_supported": [
+                "code",
+                "token",
+                "id_token",
+                "id_token token",
+                "code token",
+                "code id_token",
+                "code id_token token",
+            ],
+            "subject_types_supported": ["public"],
+            "id_token_signing_alg_values_supported": ["RS256", "HS256"],
+            "token_endpoint_auth_methods_supported": ["client_secret_post", "client_secret_basic"],
+            "claims_supported": ["sub"],
+        }
+        response = self.client.get("/o/.well-known/openid-configuration/")
         self.assertEqual(response.status_code, 200)
         assert response.json() == expected_response
 
-    def expect_json_response_with_rp(self, base):
+    def expect_json_response_with_rp_logout(self, base):
         expected_response = {
             "issuer": f"{base}",
             "authorization_endpoint": f"{base}/authorize/",
@@ -83,7 +109,7 @@ def expect_json_response_with_rp(self, base):
 
     def test_get_connect_discovery_info_with_rp_logout(self):
         self.oauth2_settings.OIDC_RP_INITIATED_LOGOUT_ENABLED = True
-        self.expect_json_response_with_rp(self.oauth2_settings.OIDC_ISS_ENDPOINT)
+        self.expect_json_response_with_rp_logout(self.oauth2_settings.OIDC_ISS_ENDPOINT)
 
     def test_get_connect_discovery_info_without_issuer_url(self):
         self.oauth2_settings.OIDC_ISS_ENDPOINT = None
@@ -117,7 +143,7 @@ def test_get_connect_discovery_info_without_issuer_url_with_rp_logout(self):
         self.oauth2_settings.OIDC_RP_INITIATED_LOGOUT_ENABLED = True
         self.oauth2_settings.OIDC_ISS_ENDPOINT = None
         self.oauth2_settings.OIDC_USERINFO_ENDPOINT = None
-        self.expect_json_response_with_rp("http://testserver/o")
+        self.expect_json_response_with_rp_logout("http://testserver/o")
 
     def test_get_connect_discovery_info_without_rsa_key(self):
         self.oauth2_settings.OIDC_RSA_PRIVATE_KEY = None