@@ -181,37 +181,89 @@ def test_pkce_uniqueness(self):
181181 assert pkce1 .code_challenge != pkce2 .code_challenge
182182
183183
184- class TestExtractFieldFromWwwAuth :
185- def test_uses_first_bearer_challenge_when_multiple_are_present ( self ):
186- response = httpx .Response (
187- 401 ,
188- headers = {
189- "WWW-Authenticate" : (
190- 'Basic realm ="legacy", Bearer scope="read", error="insufficient_scope", Bearer scope="write"'
191- )
192- },
193- request = httpx .Request ("GET" , "https://example.com" ),
194- )
184+ def test_scope_uses_first_bearer_challenge_when_multiple_are_present () :
185+ """RFC 6750 fields come from the first Bearer challenge, not another scheme or later challenge."""
186+ response = httpx .Response (
187+ 401 ,
188+ headers = {
189+ "WWW-Authenticate" : (
190+ 'Basic scope ="legacy", Bearer scope="read", error="insufficient_scope", Bearer scope="write"'
191+ )
192+ },
193+ request = httpx .Request ("GET" , "https://example.com" ),
194+ )
195195
196- assert extract_scope_from_www_auth (response ) == "read"
196+ assert extract_scope_from_www_auth (response ) == "read"
197197
198- def test_supports_optional_whitespace_around_equals (self ):
199- response = httpx .Response (
200- 401 ,
201- headers = {
202- "WWW-Authenticate" : (
203- 'Bearer error="insufficient_scope", scope = "read write", '
204- 'resource_metadata = "https://example.com/.well-known/oauth-protected-resource"'
205- )
206- },
207- request = httpx .Request ("GET" , "https://example.com" ),
208- )
209198
210- assert extract_scope_from_www_auth (response ) == "read write"
211- assert (
212- extract_resource_metadata_from_www_auth (response )
213- == "https://example.com/.well-known/oauth-protected-resource"
214- )
199+ def test_bearer_fields_support_optional_whitespace_around_equals ():
200+ """Bearer auth-params allow optional whitespace around the equals sign."""
201+ response = httpx .Response (
202+ 401 ,
203+ headers = {
204+ "WWW-Authenticate" : (
205+ 'Bearer error="insufficient_scope", scope = "read write", '
206+ 'resource_metadata = "https://example.com/.well-known/oauth-protected-resource"'
207+ )
208+ },
209+ request = httpx .Request ("GET" , "https://example.com" ),
210+ )
211+
212+ assert extract_scope_from_www_auth (response ) == "read write"
213+ assert (
214+ extract_resource_metadata_from_www_auth (response ) == "https://example.com/.well-known/oauth-protected-resource"
215+ )
216+
217+
218+ def test_generic_field_lookup_preserves_non_bearer_challenges ():
219+ """The generic helper keeps its pre-existing ability to read fields from other auth schemes."""
220+ response = httpx .Response (
221+ 401 ,
222+ headers = {"WWW-Authenticate" : 'Newauth realm="apps"' },
223+ request = httpx .Request ("GET" , "https://example.com" ),
224+ )
225+
226+ assert extract_field_from_www_auth (response , "realm" ) == "apps"
227+ assert extract_scope_from_www_auth (response ) is None
228+
229+
230+ def test_quoted_auth_params_handle_escaped_quotes_and_commas ():
231+ """RFC quoted-pairs do not terminate a quoted value or split its embedded comma."""
232+ response = httpx .Response (
233+ 401 ,
234+ headers = {
235+ "WWW-Authenticate" : (
236+ 'Newauth realm="apps \\ "beta\\ ", east", '
237+ 'Bearer error_description="try \\ "again\\ ", later", scope="read write"'
238+ )
239+ },
240+ request = httpx .Request ("GET" , "https://example.com" ),
241+ )
242+
243+ assert extract_field_from_www_auth (response , "realm" ) == 'apps "beta", east'
244+ assert extract_scope_from_www_auth (response ) == "read write"
245+
246+
247+ def test_bearer_parser_ignores_empty_segments_and_stops_at_next_challenge ():
248+ """The first Bearer challenge ends when another authentication scheme begins."""
249+ response = httpx .Response (
250+ 401 ,
251+ headers = {"WWW-Authenticate" : ', Bearer scope="read", Basic realm="legacy",' },
252+ request = httpx .Request ("GET" , "https://example.com" ),
253+ )
254+
255+ assert extract_scope_from_www_auth (response ) == "read"
256+
257+
258+ def test_empty_quoted_auth_param_returns_none ():
259+ """An empty quoted auth-param has the same missing-value result as an unquoted empty parameter."""
260+ response = httpx .Response (
261+ 401 ,
262+ headers = {"WWW-Authenticate" : 'Bearer scope=""' },
263+ request = httpx .Request ("GET" , "https://example.com" ),
264+ )
265+
266+ assert extract_scope_from_www_auth (response ) is None
215267
216268
217269class TestOAuthContext :
0 commit comments