authentik.providers.oauth2.views.token_revoke

Token revocation endpoint

 1"""Token revocation endpoint"""
 2
 3from dataclasses import dataclass
 4
 5from django.http import Http404, HttpRequest, HttpResponse
 6from django.utils.decorators import method_decorator
 7from django.views import View
 8from django.views.decorators.csrf import csrf_exempt
 9from structlog.stdlib import get_logger
10
11from authentik.providers.oauth2.errors import TokenRevocationError
12from authentik.providers.oauth2.models import AccessToken, ClientTypes, OAuth2Provider, RefreshToken
13from authentik.providers.oauth2.utils import (
14    TokenResponse,
15    authenticate_provider,
16    provider_from_request,
17)
18
19LOGGER = get_logger()
20
21
22@dataclass(slots=True)
23class TokenRevocationParams:
24    """Parameters for Token Revocation"""
25
26    token: RefreshToken | AccessToken
27    provider: OAuth2Provider
28
29    @staticmethod
30    def from_request(request: HttpRequest) -> TokenRevocationParams:
31        """Extract required Parameters from HTTP Request"""
32        raw_token = request.POST.get("token")
33
34        provider, _, _ = provider_from_request(request)
35        if provider and provider.client_type == ClientTypes.CONFIDENTIAL:
36            provider = authenticate_provider(request)
37        if not provider:
38            raise TokenRevocationError("invalid_client")
39
40        access_token = AccessToken.objects.filter(token=raw_token).first()
41        if access_token:
42            return TokenRevocationParams(access_token, provider)
43        refresh_token = RefreshToken.objects.filter(token=raw_token).first()
44        if refresh_token:
45            return TokenRevocationParams(refresh_token, provider)
46        LOGGER.debug("Token does not exist", token=raw_token)
47        raise Http404
48
49
50@method_decorator(csrf_exempt, name="dispatch")
51class TokenRevokeView(View):
52    """Token revoke endpoint
53    https://datatracker.ietf.org/doc/html/rfc7009"""
54
55    token: RefreshToken
56    params: TokenRevocationParams
57    provider: OAuth2Provider
58
59    def post(self, request: HttpRequest) -> HttpResponse:
60        """Revocation handler"""
61        try:
62            self.params = TokenRevocationParams.from_request(request)
63
64            self.params.token.delete()
65
66            return TokenResponse(data={}, status=200)
67        except TokenRevocationError as exc:
68            return TokenResponse(exc.create_dict(request), status=401)
69        except Http404:
70            # Token not found should return a HTTP 200
71            # https://datatracker.ietf.org/doc/html/rfc7009#section-2.2
72            return TokenResponse(data={}, status=200)
LOGGER = <BoundLoggerLazyProxy(logger=None, wrapper_class=None, processors=None, context_class=None, initial_values={}, logger_factory_args=())>
@dataclass(slots=True)
class TokenRevocationParams:
23@dataclass(slots=True)
24class TokenRevocationParams:
25    """Parameters for Token Revocation"""
26
27    token: RefreshToken | AccessToken
28    provider: OAuth2Provider
29
30    @staticmethod
31    def from_request(request: HttpRequest) -> TokenRevocationParams:
32        """Extract required Parameters from HTTP Request"""
33        raw_token = request.POST.get("token")
34
35        provider, _, _ = provider_from_request(request)
36        if provider and provider.client_type == ClientTypes.CONFIDENTIAL:
37            provider = authenticate_provider(request)
38        if not provider:
39            raise TokenRevocationError("invalid_client")
40
41        access_token = AccessToken.objects.filter(token=raw_token).first()
42        if access_token:
43            return TokenRevocationParams(access_token, provider)
44        refresh_token = RefreshToken.objects.filter(token=raw_token).first()
45        if refresh_token:
46            return TokenRevocationParams(refresh_token, provider)
47        LOGGER.debug("Token does not exist", token=raw_token)
48        raise Http404

Parameters for Token Revocation

@staticmethod
def from_request( request: django.http.request.HttpRequest) -> TokenRevocationParams:
30    @staticmethod
31    def from_request(request: HttpRequest) -> TokenRevocationParams:
32        """Extract required Parameters from HTTP Request"""
33        raw_token = request.POST.get("token")
34
35        provider, _, _ = provider_from_request(request)
36        if provider and provider.client_type == ClientTypes.CONFIDENTIAL:
37            provider = authenticate_provider(request)
38        if not provider:
39            raise TokenRevocationError("invalid_client")
40
41        access_token = AccessToken.objects.filter(token=raw_token).first()
42        if access_token:
43            return TokenRevocationParams(access_token, provider)
44        refresh_token = RefreshToken.objects.filter(token=raw_token).first()
45        if refresh_token:
46            return TokenRevocationParams(refresh_token, provider)
47        LOGGER.debug("Token does not exist", token=raw_token)
48        raise Http404

Extract required Parameters from HTTP Request

@method_decorator(csrf_exempt, name='dispatch')
class TokenRevokeView(django.views.generic.base.View):
51@method_decorator(csrf_exempt, name="dispatch")
52class TokenRevokeView(View):
53    """Token revoke endpoint
54    https://datatracker.ietf.org/doc/html/rfc7009"""
55
56    token: RefreshToken
57    params: TokenRevocationParams
58    provider: OAuth2Provider
59
60    def post(self, request: HttpRequest) -> HttpResponse:
61        """Revocation handler"""
62        try:
63            self.params = TokenRevocationParams.from_request(request)
64
65            self.params.token.delete()
66
67            return TokenResponse(data={}, status=200)
68        except TokenRevocationError as exc:
69            return TokenResponse(exc.create_dict(request), status=401)
70        except Http404:
71            # Token not found should return a HTTP 200
72            # https://datatracker.ietf.org/doc/html/rfc7009#section-2.2
73            return TokenResponse(data={}, status=200)
def post( self, request: django.http.request.HttpRequest) -> django.http.response.HttpResponse:
60    def post(self, request: HttpRequest) -> HttpResponse:
61        """Revocation handler"""
62        try:
63            self.params = TokenRevocationParams.from_request(request)
64
65            self.params.token.delete()
66
67            return TokenResponse(data={}, status=200)
68        except TokenRevocationError as exc:
69            return TokenResponse(exc.create_dict(request), status=401)
70        except Http404:
71            # Token not found should return a HTTP 200
72            # https://datatracker.ietf.org/doc/html/rfc7009#section-2.2
73            return TokenResponse(data={}, status=200)

Revocation handler

def dispatch(self, request, *args, **kwargs):
135    def dispatch(self, request, *args, **kwargs):
136        # Try to dispatch to the right method; if a method doesn't exist,
137        # defer to the error handler. Also defer to the error handler if the
138        # request method isn't on the approved list.
139        if request.method.lower() in self.http_method_names:
140            handler = getattr(
141                self, request.method.lower(), self.http_method_not_allowed
142            )
143        else:
144            handler = self.http_method_not_allowed
145        return handler(request, *args, **kwargs)