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

Able to refresh a token after it has been revoked #1510

Open
1 of 2 tasks
dwaynelaforce opened this issue Sep 30, 2024 · 4 comments
Open
1 of 2 tasks

Able to refresh a token after it has been revoked #1510

dwaynelaforce opened this issue Sep 30, 2024 · 4 comments
Labels

Comments

@dwaynelaforce
Copy link

dwaynelaforce commented Sep 30, 2024

Describe the bug

I am able to exchange a refresh token for a new access token when the original access token was revoked. I had a test in my local django project that validated this did not happen (in version 2.3.0) but now it does (in version 3.0.1). I want to know if this is desired behavior or perhaps a regression has been introduced to the codebase.

To Reproduce

Create an Application with Authorization Code type.
Initiate the workflow from the external app, authenticate, and authorize.
Go to the authorized tokens page, select the new token, and delete.
In postman, make a refresh token request using the refresh token, the response is 200 OK and includes a new access token and refresh token.

Expected behavior

After revoking an access token, the corresponding refresh token would also be revoked and unusable by the external application.

Version

3.0.1

  • I have tested with the latest published release and it's still a problem.
  • I have tested with the master branch and it's still a problem.

Additional context

Sorry if this has been raised already- I did browse the open and closed issues for this release and did not see anything. Thanks for all your work on this package.

@n2ygk
Copy link
Member

n2ygk commented Oct 2, 2024

Related to #1452? @soerface can you please take a look at this?

@soerface
Copy link
Contributor

soerface commented Oct 2, 2024

@dwaynelaforce do you use the REFRESH_TOKEN_GRACE_PERIOD_SECONDS setting? If yes, I'm wondering if the refresh token is still valid for the specified amount of time?

@dwaynelaforce
Copy link
Author

@soerface sorry for taking so long to respond! priorities shifted at work for the last month but I am back on this now.

We are not using that setting but we do use REFRESH_TOKEN_EXPIRE_SECONDS which is set to 7 days.

Here is the django test code in our django app that was working in the prior version but is failing in this version:

    def test_refresh_token_cannot_be_used_on_a_manually_revoked_access_token(self):
        access_token = self._create_accesstoken(self.user)
        refreshtoken = self._create_refreshtoken(access_token)

        session_client = Client()
        session_client.force_login(self.user)
        resp = session_client.post(f"/o/authorized_tokens/{access_token.id}/delete/")
        self.assertEqual(resp.status_code, 302)
        self.assertFalse(AccessToken.objects.filter(token=access_token.token).exists())
        refreshtoken.refresh_from_db()
        self.assertIsNone(refreshtoken.access_token)

        self.assertRaises(
            AccessToken.DoesNotExist,
            Client().post,
            self.token_endpoint,
            data={
                "client_id": self.client_id,
                "client_secret": self.client_secret,
                "refresh_token": refreshtoken.token,
                "grant_type": "refresh_token",
            },
        )

I have verified that the response from that API call in the assertRaises is 200 OK and includes a new access token and refresh token.

@dwaynelaforce
Copy link
Author

After more closely reviewing oauth2_provider/models.py and oauth2_provider/views/token.py I notice that when a refresh token is revoked, it also revokes its related access token, while the reverse is not true- the access token simply deletes itself. The authorized-tokens and delete views are only for access tokens and appear to call delete() rather than revoke(). Not sure why my test was working in the previous version though.

I'm guessing then that this is intended behavior and the issue here is my expectation being different. Could you confirm?

If the case, it sounds like the correct way for a user to revoke third party access to their account is to revoke the refresh token if it exists rather than the access token. Is a new template needed, where a user's access tokens AND refresh tokens are provided with links to revoke?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants