from django.conf import settings from django.core import signing from django.core.exceptions import ValidationError from rest_framework import authentication, exceptions from . import models from .oauth import scopes as available_scopes def generate_scoped_token(user_id, user_secret, scopes): if set(scopes) & set(available_scopes.SCOPES_BY_ID) != set(scopes): raise ValueError(f"{scopes} contains invalid scopes") return signing.dumps( { "user_id": user_id, "user_secret": str(user_secret), "scopes": list(sorted(scopes)), }, salt="scoped_tokens", ) def authenticate_scoped_token(token): try: payload = signing.loads( token, salt="scoped_tokens", max_age=settings.SCOPED_TOKENS_MAX_AGE, ) except signing.BadSignature: raise exceptions.AuthenticationFailed("Invalid token signature") try: user_id = int(payload["user_id"]) user_secret = str(payload["user_secret"]) scopes = list(payload["scopes"]) except (KeyError, ValueError, TypeError): raise exceptions.AuthenticationFailed("Invalid scoped token payload") try: user = ( models.User.objects.all() .for_auth() .get(pk=user_id, secret_key=user_secret, is_active=True) ) except (models.User.DoesNotExist, ValidationError): raise exceptions.AuthenticationFailed("Invalid user") return user, scopes class ScopedTokenAuthentication(authentication.BaseAuthentication): """ Used when signed token returned by generate_scoped_token are provided via token= in GET requests. Mostly for