https://github.com/python/cpython/commit/270a30ab307d03ece8f93722eb402ce92883ac37
commit: 270a30ab307d03ece8f93722eb402ce92883ac37
branch: 3.14
author: Miss Islington (bot) <[email protected]>
committer: orsenthil <[email protected]>
date: 2026-10-29T13:30:35-07:00
summary:

[3.14] gh-53852 Proxy Auth failure to raise 407 instead of 401 (GH-160917) 
(#160920)

gh-53852 Proxy Auth failure to raise 407 instead of 401 (GH-160917)

Proxy Auth failure to raise 407 instead of 401

https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/407
is the correct status code to raise for the Proxy Authentication.

https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/401
is the generic code that can be raised for unauthorized response.
(cherry picked from commit 2e1666f1f24c128a9a85bd39680c59aee90f2275)

Co-authored-by: Senthil Kumaran <[email protected]>

files:
A Misc/NEWS.d/next/Library/2026-10-28-12-00-00.gh-issue-53852.Pr0xy4.rst
M Lib/test/test_urllib2.py
M Lib/test/test_urllib2_localnet.py
M Lib/urllib/request.py

diff --git a/Lib/test/test_urllib2.py b/Lib/test/test_urllib2.py
index 16123842235a15..80a56759d61e18 100644
--- a/Lib/test/test_urllib2.py
+++ b/Lib/test/test_urllib2.py
@@ -1854,6 +1854,25 @@ def test_unsupported_auth_digest_handler(self):
         opener.add_handler(http_handler)
         self.assertRaises(ValueError, opener.open, "http://www.example.com";)
 
+    def test_digest_auth_failure_code(self):
+        # gh-53852: a failed proxy digest auth must report 407, not 401.
+        headers = http.client.HTTPMessage()
+        for handler_class, auth_header, code in [
+                (urllib.request.HTTPDigestAuthHandler,
+                 'www-authenticate', 401),
+                (urllib.request.ProxyDigestAuthHandler,
+                 'proxy-authenticate', 407)]:
+            with self.subTest(handler=handler_class.__name__):
+                handler = handler_class()
+                handler.retried = 6
+                req = Request("http://www.example.com/";)
+                with self.assertRaises(urllib.error.HTTPError) as cm:
+                    handler.http_error_auth_reqed(auth_header,
+                                                  "www.example.com",
+                                                  req, headers)
+                self.assertEqual(cm.exception.code, code)
+                cm.exception.close()
+
     def test_unsupported_auth_basic_handler(self):
         # While using BasicAuthHandler
         opener = OpenerDirector()
diff --git a/Lib/test/test_urllib2_localnet.py 
b/Lib/test/test_urllib2_localnet.py
index c2646b9448f297..8f93ee74252f5c 100644
--- a/Lib/test/test_urllib2_localnet.py
+++ b/Lib/test/test_urllib2_localnet.py
@@ -368,12 +368,14 @@ def test_proxy_with_bad_password_raises_httperror(self):
         self.digest_auth_handler.set_qop("auth")
         with self.assertRaises(urllib.error.HTTPError) as cm:
             self.opener.open(self.URL)
+        self.assertEqual(cm.exception.code, 407)
         cm.exception.close()
 
     def test_proxy_with_no_password_raises_httperror(self):
         self.digest_auth_handler.set_qop("auth")
         with self.assertRaises(urllib.error.HTTPError) as cm:
             self.opener.open(self.URL)
+        self.assertEqual(cm.exception.code, 407)
         cm.exception.close()
 
     def test_proxy_qop_auth_works(self):
diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py
index e44691a169275a..ebbb4010abdf06 100644
--- a/Lib/urllib/request.py
+++ b/Lib/urllib/request.py
@@ -1091,7 +1091,11 @@ def http_error_auth_reqed(self, auth_header, host, req, 
headers):
             # prompting for the information. Crap. This isn't great
             # but it's better than the current 'repeat until recursion
             # depth exceeded' approach <wink>
-            raise HTTPError(req.full_url, 401, "digest auth failed",
+            if auth_header.lower() == 'proxy-authenticate':
+                code = 407
+            else:
+                code = 401
+            raise HTTPError(req.full_url, code, "digest auth failed",
                             headers, None)
         else:
             self.retried += 1
diff --git 
a/Misc/NEWS.d/next/Library/2026-10-28-12-00-00.gh-issue-53852.Pr0xy4.rst 
b/Misc/NEWS.d/next/Library/2026-10-28-12-00-00.gh-issue-53852.Pr0xy4.rst
new file mode 100644
index 00000000000000..6b6c7fa1e17513
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-10-28-12-00-00.gh-issue-53852.Pr0xy4.rst
@@ -0,0 +1,3 @@
+:class:`urllib.request.ProxyDigestAuthHandler` now raises
+:exc:`~urllib.error.HTTPError` with status code 407 (Proxy Authentication
+Required) instead of 401 when proxy authentication fails.

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to