Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix access token 500 to properly handle expired or deleted refresh tokens #1337

Merged
merged 9 commits into from
Oct 28, 2023
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Antoine Laurent
Anvesh Agarwal
Aristóbulo Meneses
Aryan Iyappan
Asaf Klibansky
Ash Christopher
Asif Saif Uddin
Bart Merenda
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* #1273 Add caching of loading of OIDC private key.
* #1285 Add post_logout_redirect_uris field in application views.
* #1311 Add option to disable client_secret hashing to allow verifying JWTs' signatures.
* #1337 Gracefully handle expired or deleted refresh tokens, in `validate_user`.

- ### Fixed
* #1322 Instructions in documentation on how to create a code challenge and code verifier
Expand Down
6 changes: 4 additions & 2 deletions oauth2_provider/oauth2_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -725,8 +725,10 @@ def get_original_scopes(self, refresh_token, request, *args, **kwargs):
# validate_refresh_token.
rt = request.refresh_token_instance
if not rt.access_token_id:
return AccessToken.objects.get(source_refresh_token_id=rt.id).scope

try:
return AccessToken.objects.get(source_refresh_token_id=rt.id).scope
except AccessToken.DoesNotExist:
return []
return rt.access_token.scope

def validate_refresh_token(self, refresh_token, client, request, *args, **kwargs):
Expand Down
33 changes: 33 additions & 0 deletions tests/test_authorization_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -1002,6 +1002,39 @@ def test_refresh_repeating_requests_non_rotating_tokens(self):
response = self.client.post(reverse("oauth2_provider:token"), data=token_request_data, **auth_headers)
self.assertEqual(response.status_code, 200)

def test_refresh_with_deleted_token(self):
"""
Ensure that using a deleted refresh token returns 400
"""
self.client.login(username="test_user", password="123456")
authorization_code = self.get_auth()

token_request_data = {
"grant_type": "authorization_code",
"scope": "read write",
"code": authorization_code,
"redirect_uri": "http://example.org",
}
auth_headers = get_basic_auth_header(self.application.client_id, CLEARTEXT_SECRET)

# get a refresh token
response = self.client.post(reverse("oauth2_provider:token"), data=token_request_data, **auth_headers)

content = json.loads(response.content.decode("utf-8"))
rt = content["refresh_token"]

token_request_data = {
"grant_type": "refresh_token",
"refresh_token": rt,
"scope": "read write",
}

# delete the access token
AccessToken.objects.filter(token=content["access_token"]).delete()

response = self.client.post(reverse("oauth2_provider:token"), data=token_request_data, **auth_headers)
self.assertEqual(response.status_code, 400)

def test_basic_auth_bad_authcode(self):
"""
Request an access token using a bad authorization code
Expand Down
Loading