Skip to content

Instantly share code, notes, and snippets.

@cb109
Last active January 25, 2023 08:42
Show Gist options
  • Save cb109/c81bb35ed3dcfe093d5a5775f31e2ea2 to your computer and use it in GitHub Desktop.
Save cb109/c81bb35ed3dcfe093d5a5775f31e2ea2 to your computer and use it in GitHub Desktop.
Setting up DRF Token authentication with basic expiration
from datetime import timedelta
from django.conf import settings
from django.utils import timezone
from rest_framework.authentication import TokenAuthentication
from rest_framework.authtoken.models import Token
from rest_framework.exceptions import AuthenticationFailed
def is_token_expired(token):
min_age = timezone.now() - timedelta(
seconds=settings.TOKEN_EXPIRED_AFTER_SECONDS)
expired = token.created < min_age
return expired
class ExpiringTokenAuthentication(TokenAuthentication):
"""Same as in DRF, but also handle Token expiration.
An expired Token will be removed and a new Token with a different
key is created that the User can obtain by logging in with his
credentials.
Raise AuthenticationFailed as needed, which translates
to a 401 status code automatically.
https://stackoverflow.com/questions/14567586
"""
def authenticate_credentials(self, key):
try:
token = Token.objects.get(key=key)
except Token.DoesNotExist:
raise AuthenticationFailed("Invalid token")
if not token.user.is_active:
raise AuthenticationFailed("User inactive or deleted")
expired = is_token_expired(token)
if expired:
token.delete()
Token.objects.create(user=token.user)
raise AuthenticationFailed("Token has expired")
return (token.user, token)
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'myproject.authentication.ExpiringTokenAuthentication',
)
}
@yerkbn
Copy link

yerkbn commented Oct 10, 2018

thank you

@ramsrib
Copy link

ramsrib commented Nov 4, 2018


        if expired:
            token.delete()
            Token.objects.create(user=token.user)
            raise AuthenticationFailed("Token has expired")

Why do you create a new token when it's expired?

@cb109
Copy link
Author

cb109 commented Mar 11, 2019

@ramsrib To ensure an expired Token can not be used to authenticate ever again. Of course that's not the way you have to do it, this gist is merely a starting point, you can implement your own logic, like refreshing the token.

@SoundWaveX81
Copy link

@cb109 you can rewrite the authenticate_credentials method to make short your code using the father class' autheticate_credentials method

def authenticate_credentials(self, key):
    user, token = super().authenticate_credentials(key)
    if self.is_token_expired(token):
        token.delete() # or whatever logic you want 
        raise AuthenticationFailed("Token has expired")
    return user, token

@cb109
Copy link
Author

cb109 commented Jan 25, 2023

@SoundWaveX81 That's indeed shorter, good point. Back then I copied the full method to see how I could extend it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment