Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 3be0846

Browse files
azmeuklepture
authored andcommitted
fix: redirecting to unvalidated redirect_uri on UnsupportedResponseTypeError
1 parent 9266eaa commit 3be0846

3 files changed

Lines changed: 87 additions & 1 deletion

File tree

authlib/oauth2/rfc6749/authorization_server.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,10 +241,21 @@ def get_authorization_grant(self, request):
241241
if grant_cls.check_authorization_endpoint(request):
242242
return _create_grant(grant_cls, extensions, request, self)
243243

244+
# Per RFC 6749 §4.1.2.1, only redirect with the error if the client
245+
# exists and the redirect_uri has been validated against it.
246+
redirect_uri = None
247+
if client_id := request.payload.client_id:
248+
if client := self.query_client(client_id):
249+
if requested_uri := request.payload.redirect_uri:
250+
if client.check_redirect_uri(requested_uri):
251+
redirect_uri = requested_uri
252+
else:
253+
redirect_uri = client.get_default_redirect_uri()
254+
244255
raise UnsupportedResponseTypeError(
245256
f"The response type '{request.payload.response_type}' is not supported by the server.",
246257
request.payload.response_type,
247-
redirect_uri=request.payload.redirect_uri,
258+
redirect_uri=redirect_uri,
248259
)
249260

250261
def get_consent_grant(self, request=None, end_user=None):

docs/changelog.rst

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,37 @@ Changelog
66

77
Here you can see the full list of changes between each Authlib release.
88

9+
Version 1.6.10
10+
--------------
11+
12+
**Unreleased**
13+
14+
- Fix redirecting to unvalidated ``redirect_uri`` on ``UnsupportedResponseTypeError``.
15+
16+
Version 1.6.9
17+
-------------
18+
19+
**Released on Mar 2, 2026**
20+
21+
- Not using header's ``jwk`` automatically.
22+
- Add ``ES256K`` into default jwt algorithms.
23+
- Remove deprecated algorithm from default registry.
24+
- Generate random ``cek`` when ``cek`` length doesn't match.
25+
26+
Version 1.6.8
27+
-------------
28+
29+
**Released on Feb 17, 2026**
30+
31+
- Add ``EdDSA`` to default ``jwt`` instance.
32+
33+
Version 1.6.7
34+
-------------
35+
36+
**Released on Feb 6, 2026**
37+
38+
- Set supported algorithms for the default ``jwt`` instance.
39+
940
Version 1.6.6
1041
-------------
1142

tests/flask/test_oauth2/test_authorization_code_grant.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,3 +352,47 @@ def test_token_generator(app, test_client, client, server):
352352
resp = json.loads(rv.data)
353353
assert "access_token" in resp
354354
assert "c-authorization_code.1." in resp["access_token"]
355+
356+
357+
def test_missing_scope_empty_default(test_client, client, monkeypatch):
358+
"""When client.get_allowed_scope() returns empty string for missing scope,
359+
the authorization should proceed without a scope.
360+
"""
361+
362+
def get_allowed_scope_empty(scope):
363+
if scope is None:
364+
return ""
365+
return scope
366+
367+
monkeypatch.setattr(client, "get_allowed_scope", get_allowed_scope_empty)
368+
369+
rv = test_client.post(authorize_url, data={"user_id": "1"})
370+
assert "code=" in rv.location
371+
372+
params = dict(url_decode(urlparse.urlparse(rv.location).query))
373+
code = params["code"]
374+
headers = create_basic_header("client-id", "client-secret")
375+
rv = test_client.post(
376+
"/oauth/token",
377+
data={
378+
"grant_type": "authorization_code",
379+
"code": code,
380+
},
381+
headers=headers,
382+
)
383+
resp = json.loads(rv.data)
384+
assert "access_token" in resp
385+
assert resp.get("scope", "") == ""
386+
387+
388+
def test_unsupported_response_type_does_not_redirect(test_client):
389+
"""Regression test for open redirect via unsupported response_type."""
390+
url = (
391+
"/oauth/authorize"
392+
"?response_type=totally-unsupported"
393+
"&redirect_uri=https%3A%2F%2Fevil.example%2Flanding"
394+
"&state=s1"
395+
)
396+
rv = test_client.get(url)
397+
assert rv.status_code == 400
398+
assert rv.headers.get("Location") is None

0 commit comments

Comments
 (0)