Last active
January 25, 2023 08:42
-
-
Save cb109/c81bb35ed3dcfe093d5a5775f31e2ea2 to your computer and use it in GitHub Desktop.
Setting up DRF Token authentication with basic expiration
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
REST_FRAMEWORK = { | |
'DEFAULT_AUTHENTICATION_CLASSES': ( | |
'myproject.authentication.ExpiringTokenAuthentication', | |
) | |
} |
@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
@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
@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.