Hey guys,
I want to have a custom scope required for some of my views and when a user requests an access token with that scope, check to see if the user is actually allowed to have that scope in my system. How can I achieve this?
Here's an example for clarifying the question: The users in my website are either students or are teachers. I want to add a teacher scope and when a user requests an access token with the teacher scope, check to see if the user is one of the teachers so that if he's not a teacher he won't be able to get an access token.
Thanks
I believe what you are asking for is documented here. However, the implementation happens at the point of introspecting the already-granted access token in the resource server, not at the point of granting it.
Thanks, But I think any user will be able to request the teacher scope when authenticating, so even if my view requires the teacher scope, I can't prevent users from accessing that endpoint and I have to check manually for the user's permission, right?
Yes. We are using an external OAuth2 AS here and just DOT for the
introspection portion and that AS allows us to configure clients (not
users) to a set of restricted scopes, but the OAuth2 concept of scopes is
really that the user is delegating to the 3rd-party client to act on their
behalf. Any scopes "belong" to the user intrinsically. I don't know if DOT
as the AS can "down-scope" a request based on a user's membership in
various groups. If so, it is one of the few AS's that implement that.
In our implementation, we use OIDC userinfo claims which are mapped from
our LDAP service to identify which user has a given set of permissions.
You'll probably want to do that and/or use standard django auth for
users....
I have some further documentation here (but it may just confuse things):
https://columbia-it-django-jsonapi-training.readthedocs.io/en/latest/oauth2.html
On Wed, Aug 14, 2019 at 11:54 AM Khashayar Mirsadeghi <
[email protected]> wrote:
Thanks, But I think any user will be able to request the teacher scope
when authenticating, so even if my view requires the teacher scope, I
can't prevent users from accessing that endpoint and I have to check
manually for the user's permission, right?—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/jazzband/django-oauth-toolkit/issues/731?email_source=notifications&email_token=ABBHS5ZVEGC4AOXM5GZNMPTQEQTDRA5CNFSM4ILBBSXKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD4JIBNY#issuecomment-521306295,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ABBHS52HFQC3PU5IN52DYFLQEQTDRANCNFSM4ILBBSXA
.
Although this issue is close, I faced the same issue and I spent 2 days figuring this out.
I hope others are helped by this.
In your urls, change the token url to point to a custom view.
path("authenticate/token/", CustomTokenView.as_view(), name="token"),
path("authenticate/", include("oauth2_provider.urls"), name="oauth2_provider")
Copy the TokenView from oauth2_provider.views.base from DOT and the required imports and add changes inside.
class CustomTokenView(TokenView):
"""
used by /authenticate/token/
appends scopes to the token based on uer roles
"""
@method_decorator(sensitive_post_parameters("password"))
def post(self, request, *args, **kwargs):
url, headers, body, status = self.create_token_response(request)
if status == 200:
access_token = json.loads(body).get("access_token")
if access_token is not None:
token = get_access_token_model().objects.get(
token=access_token
)
##################################################
# add role based scope in the token
role = token.user.get_role_display()
//change_your_scope_based_on_role_here//
# keep in mind, the default and api provided scopes
token.save()
##################################################
app_authorized.send(
sender=self, request=request,
token=token
)
response = HttpResponse(content=body, status=status)
for k, v in headers.items():
response[k] = v
return response
@Pkoiralap if I understand this correctly, you are implementing restricting scopes to specific clients. That would make a great documentation PR if not an actual PR for an extension to TokenView.
@Pkoiralap thanks very much. i have been looking for something just like this for some time.
It would be good if the documentation was more complete
@Pkoiralap Thanks as well!
For anybody having a similar issue in the future — hello, visitor from the future, has a vaccine been found yet? — here's my own naive variation to restrict the write scope to users with the is_staff or is_superuser flags:
class SmartScopesTokenView(TokenView):
""" A view to assign scopes to the OAuth2 token according to
the passed credentials.
Right now, the `read` scope is granted to any registered user
but the `write` scope requires the `is_staff` or `is_superuser`
flag to be `True` in their profile.
See: https://github.com/jazzband/django-oauth-toolkit/issues/731#issuecomment-601379927
"""
def post(self, request, *args, **kwargs):
url, headers, body, status = self.create_token_response(request)
if status == 200:
json_body = json.loads(body)
access_token = json_body.get('access_token')
if access_token is not None:
token = get_access_token_model().objects.get(
token=access_token)
# --- customization starts here
WRITE_SCOPE = 'write'
user = token.user
scopes = json_body.get('scope').split()
if (
WRITE_SCOPE in scopes
and not (
user.is_staff
or user.is_superuser
)
):
scopes.remove(WRITE_SCOPE)
scope = ' '.join(scopes)
token.scope = scope
token.save()
json_body['scope'] = scope
body = json.dumps(json_body)
# --- customization ends here
app_authorized.send(
sender=self, request=request,
token=token)
response = HttpResponse(content=body, status=status)
for k, v in headers.items():
response[k] = v
return response
Most helpful comment
Although this issue is close, I faced the same issue and I spent 2 days figuring this out.
I hope others are helped by this.
In your urls, change the token url to point to a custom view.
Copy the
TokenViewfromoauth2_provider.views.basefrom DOT and the required imports and add changes inside.