django-oauth-toolkit icon indicating copy to clipboard operation
django-oauth-toolkit copied to clipboard

Refreshing a revoked access token throws an error 500

Open Maximilien-R opened this issue 6 years ago • 14 comments

When you revoke an access token and try to refresh it afterwards, you end up with an error 500.

This seems to be related to the get_original_scopes method of oauth2_provider/oauth2_validators.py which tries to retrieve the access token related to the refresh token. However, since it was revoked, it no longer exists and Django throws a DoesNotExists error which isn't catch.

When we revoke an access token, maybe we should revoke refresh tokens too ? Or we could add a clause to the queryset on validate_refresh_token method to exclude refresh token without access_token.

Maximilien-R avatar Apr 21 '18 19:04 Maximilien-R

As a stopgap, could you do something like the following:

    token_model = oauth2_provider.models.get_refresh_token_model()
    tokens = oauth2_provider.models.RefreshToken.objects.all()
    for token in tokens:
        token.delete()

This would of course be for revoking every refresh token (I haven't tested it but it works for access tokens at least, if you replace the "refresh"s with "access")

cheenan avatar May 30 '18 07:05 cheenan

I've also ran into this. It looks like this cannot be mitigated without adding the scope to the RefreshToken model as well?

raphaelm avatar May 31 '18 21:05 raphaelm

We're mitigating like this on our access token model currently:

    def revoke(self):
        self.expires = now() - timedelta(hours=1)
        self.save(update_fields=['expires'])

raphaelm avatar Jun 04 '18 09:06 raphaelm

I've implemented a fix for this: https://github.com/jazzband/django-oauth-toolkit/pull/620

robrap avatar Jul 11 '18 13:07 robrap

FYI: My fix turned out to not be a fix, because I just replicated a bug in 0.12.0 that would return a 401.

I think the real fix would be to allow the refresh token, which itself was not revoked, to continue to work. I'm not sure of the correct fix, but it might be to store the refresh token's scope, and not rely on an associated access token to determine the original scope.

robrap avatar Jul 11 '18 17:07 robrap

I think the real fix would be to allow the refresh token, which itself was not revoked, to continue to work. I'm not sure of the correct fix, but it might be to store the refresh token's scope, and not rely on an associated access token to determine the original scope.

That would be option A, option B would be adding a revoked attribute to access tokens and revoke them by setting that instead of deleting them. Not sure which one is better.

raphaelm avatar Jul 12 '18 06:07 raphaelm

Agreed. Not sure which approach is better. I need to move on, but hopefully this is more clear for someone to pick up.

robrap avatar Jul 12 '18 16:07 robrap

Any progress on this? I have just run into this myself upgrading from 1.0.0 to 1.2.0. I'd be happy to try and make a PR if someone can point me in the right direction.

keattang avatar Jan 02 '20 02:01 keattang

No progress that I am aware of.

The options continue to be: Option A: Redundantly store the original scope with the revoke token and use this rather than trying to reference the related access token. Option B: Store "revoked" status with the access token and update its status, rather than deleting, when revoked.

See my previous PR if you want much more detail around the bug with code references: https://github.com/jazzband/django-oauth-toolkit/pull/620.

Good luck @keattang.

robrap avatar Jan 02 '20 14:01 robrap

@robrap Is there a consensus on which to go with? I'd prefer not to write something and then it be decided that it's not the correct approach

keattang avatar Jan 02 '20 22:01 keattang

Not sure if @jleclanche could give thumbs-up on an approach before you start. I agree with wanting to know which way to go first.

robrap avatar Jan 02 '20 22:01 robrap

I don't have an ultimate say on DOT, but option B sounds better to me.

jleclanche avatar Jan 02 '20 23:01 jleclanche

related to #839

MattBlack85 avatar Nov 18 '20 09:11 MattBlack85

I don't have an ultimate say on DOT, but option B sounds better to me.

Assuming option B is taken, can I take it that the cascade would be changed from null-on-cascade to delete-on-cascade?

ShaheedHaque avatar Mar 15 '21 22:03 ShaheedHaque