According to RFC6750 3.1 Error codes there are different response codes for invalid access token and for valid access token, but insufficient scope:
invalid_token
The access token provided is expired, revoked, malformed, or
invalid for other reasons. The resource SHOULD respond with
the HTTP 401 (Unauthorized) status code. The client MAY
request a new access token and retry the protected resource
request.
insufficient_scope
The request requires higher privileges than provided by the
access token. The resource server SHOULD respond with the HTTP
403 (Forbidden) status code and MAY include the "scope"
attribute with the scope necessary to access the protected
resource.
As for now there is no possibility to differentiate whether it is an invalid access token or insufficient scope. It is validated in one method: AccessToken.is_valid().
Are there any reasons of not-following the RFC?
This is #367 isnt it?
I'll take a PR that fixes it :)
@jleclanche I'm not sure. As I understand #367 it is about differentiating the requests with 1. invalid token and 2. without token. The case I've described is about differentiating the requests with 1. invalid token and 2. invalid scope (while token is valid).
Are there any reasons of not-following the RFC?
I'll note that it says _SHOULD_ instead of _MUST_, so technically it's following the RFC.
You may find that this is actually because of how DRF handles returning a 401 or a 403 for authentication and authorization errors. This is something outside of Django OAuth Toolkit's control, because it is based on how you defined your settings.
http://www.django-rest-framework.org/api-guide/authentication/#unauthorized-and-forbidden-responses
I just ran into this issue while using IsAuthenticatedOrTokenHasScope where all requests were returning 403 Forbidden.
I found out through tracing that DRF only uses the first authentication class when determining whether to coerce 401 responses to 403 responses, and I had specified my SessionAuthentication class before my OAuth2Authentication class.
Turns out I could have saved myself quite a bit of time by just reading the docs so for anyone having this issue, here's the relevant part from the link kevin-brown posted:
The kind of response that will be used depends on the authentication scheme. Although multiple authentication schemes may be in use, only one scheme may be used to determine the type of response. The first authentication class set on the view is used when determining the type of response.
im having the same problem, my view is returning 403 everytime. I defined my view like: class AuthenticatedGraphQLView(ProtectedResourceView, GraphQLView)
Im not sure how is this related to DRF authentication scheme, since my api is using graphene.
Thanks @Pear0
It work for me. OAuth2Authentication must be before SessionAuthentication
'DEFAULT_AUTHENTICATION_CLASSES': (
'oauth2_provider.contrib.rest_framework.OAuth2Authentication',
'rest_framework.authentication.SessionAuthentication',
),
For those of you who are still looking for a solution, I've figured out a workaround for when using the protected_resource decorator from the django-oauth-toolkit package. You can modify the decorator code (or write your own based on this):
def protected_resource(scopes=None, validator_cls=OAuth2Validator, server_cls=Server):
_scopes = scopes or []
def decorator(view_func):
@wraps(view_func)
def _validate(request, *args, **kwargs):
validator = validator_cls()
core = OAuthLibCore(server_cls(validator))
valid, oauthlib_req = core.verify_request(request, scopes=_scopes)
if valid:
request.resource_owner = oauthlib_req.user
return view_func(request, *args, **kwargs)
if oauthlib_req.oauth2_error['error'] == 'invalid_token':
if 'application/json' in oauthlib_req.headers['HTTP_ACCEPT']:
data = json.dumps({'errors': [{'message': 'You do not have authorisation to access this resource.'}]})
return HttpResponse(data, status=401, content_type='application/json; charset=utf-8')
else:
return HttpResponse('Unauthorized', status=401)
return HttpResponseForbidden()
return _validate
return decorator
Most helpful comment
I just ran into this issue while using
IsAuthenticatedOrTokenHasScopewhere all requests were returning 403 Forbidden.I found out through tracing that DRF only uses the first authentication class when determining whether to coerce 401 responses to 403 responses, and I had specified my
SessionAuthenticationclass before myOAuth2Authenticationclass.Turns out I could have saved myself quite a bit of time by just reading the docs so for anyone having this issue, here's the relevant part from the link kevin-brown posted: