"""Authentication for scope-limited bearer tokens. `GreetingTokenAuthentication` understands the same header a normal API token uses (``Authorization: Token ``) but only resolves tokens issued for the random-image endpoint. It is registered per-view (currently only `RandomItemView`), so a greeting token is rejected everywhere else by the regular DRF token authentication. """ from rest_framework import authentication, exceptions from .models import GreetingToken class GreetingTokenAuthentication(authentication.BaseAuthentication): keyword = b"token" def authenticate_header(self, request): # DRF answers 401 (instead of 403) for AuthenticationFailed only when # the first authenticator can name the scheme. return "Token" def authenticate(self, request): header = authentication.get_authorization_header(request).split() if not header or header[0].lower() != self.keyword: return None if len(header) != 2: raise exceptions.AuthenticationFailed("Invalid token header.") try: key = header[1].decode() except UnicodeError: raise exceptions.AuthenticationFailed("Invalid token header.") # Not one of ours: let the regular token authentication handle it. if not key.startswith(GreetingToken.PREFIX): return None token = GreetingToken.resolve(key) if token is None: raise exceptions.AuthenticationFailed("Invalid token.") token.touch() return (token.user, token)