Description
Hi. I am not entirely sure if this is a bug or I am misunderstanding something about OAuth2, I'd like to apologize in advance if it's the latter.
Describe the bug
I followed the tutorial to create an access token and tried using the IntrospectTokenView
with that token. This view is a ClientProtectedScopedResourceView
that includes required_scopes = ["introspection"]
. My understanding of the documentation around these made me believe that if I use a bearer token without the appropriate scope, my request will fail. To my surprise, the call succeeds regardless of the scopes in the token I use.
To Reproduce
- Set up a basic OAuth2 provider as suggested by the tutorial.
- Use these steps to create an access token.
- Try accessing the
introspect
endpoint like so:curl -X POST -H "Authorization: Basic ${CREDENTIAL}" -H "Cache-Control: no-cache" -H "Content-Type: application/x-www-form-urlencoded" "http://127.0.0.1:8000/o/introspect/" -d "token=..."
Expected behavior
Even when using the client-credentials flow, I expect a token that doesn't have the introspection
scope to be rejected when calling an endpoint declaring required_scopes = ["introspection"]
.
Version
2.4.0
- I have tested with the latest published release and it's still a problem.
- I have tested with the master branch and it's still a problem.
Additional context
I googled around and found this Auth0 thread for a similar question. There it is suggested that scopes in a token are not considered at all if using client-credentials. However, in that example the client itself has associated scopes. This isn't the case for the default setup of DOT, as far as I can see.
As it stands, when using client-credentials, any token can be inspected by any client. If this is the desired behavior that's fine with me. If not, however, you might consider a small change to IntrospectTokenView.get_token_response
that uses cls.required_scopes
:
@classmethod
def get_token_response(cls, token_value=None):
try:
...
except ObjectDoesNotExist:
return JsonResponse({"active": False}, status=200)
else:
if token.is_valid(cls.required_scopes):
...