Hi, I am trying to implement RBAC with Okta. I can see some examples showing RBAC by having Users==> Groups, then adding the groups to the token claims and filter your APIs based on the groups.
However I need one more layer, so it will be something like this:
Users ==> Groups ==> Permissions
Some suggest to implement the Users==> Groups part in Okta and the Groups ==> Permissions part at app level, but this does not suit us as we will have to provide a custom UI to manage the Groups==> Permissions.
One way to achieve what I want is benefiting from the scopes, so we can define custom scopes and make them default in Okta and then create some access policy rules that define which scopes are assigned for each group.
However, that does not work directly as if we send ?scp=openid we will only get openid in the scp claims and we will not get the default claims that we’ve defined. The default claims, will only be used if we send an empty scopes query param in authorization request, but if we do that we will loose OIDC as it needs the openid scope.
Question
Finally my questions are:
Why can’t any base scope be defaulted in Okta authorization server. For example if I was able to make openid a default scope then it would’ve solved my problem.
Is there any expression to return the default scopes for a certain group?
For example I have create the following:
group: “books_admin”
custom scopes: “books.read” and “books.write” I make both scopes default in Okta
access policy rules: Assign “books.read” and “books.write” to anyone in group “books_admin”
Is there an expression to add a claim that outputs the scopes for the user groups regardless what the client have sent in the authorization request.
What is the best way to achieve a 3 layer RBAC (Users ==> Groups ==> Permissions) without having Groups ==> Permissions defined at app level.
Does anyone have an answer to any of the questions? Thanks
Hi @saidsaifi ,
I may be missing something, but if you default the scopes then they’re available for anyone who gets a token from your auth server and you won’t be able to apply role-based access control.
Is the challenge you’re trying to solve that you don’t know ahead of time what role the user has and therefore you can’t specify a scope in advance? If so, I haven’t found a native way to do this in Okta (hopefully others can chime in).
2 possible workarounds:
add a groups claim to the token where the group names are meaningful roles in your application. Only groups your user is a member of will be added.
inline token hook to patch the scp claim in an access token (I haven’t tried this myself). The doco here says you can’t patch scopes in an ID_Token.
Generally, I’ve seen (and advocated) a preference to keep access control fairly coarse at the IdP / API gateway (can this role get/post/put this URI or does this user have a specific scope) and leave finer-grained permissions management to the app itself. Okta isn’t that great (yet) for managing fine-grained permissions. You may want to look into something like Open Poliy Agent (OPA) to express fine-graned policies in a consistent format.
@abole thanks for your swift response.
First regarding default scopes, as mentioned by Okta:
“A default scope will be returned in an access token when the client omits the scope parameter in a token request, provided this scope is allowed as part of the access policy rule.”
So the default scope will be only returned if we define that in access policy rule. So the access policy rules acts as a mapping between groups and scopes.
As for the workarounds, the first one is kind of what we are trying to avoid, because it may not be that clear from Okta level what a certain group can do. For example if I have a Marketing group I can’t guess which endpoints exactly does it allow you to access.
As for the second suggestion, I’ll try to look into that, it can be useful. Thanks you.
A workaround that I was able to use is to get rid of the OIDC, so we can get our custom scopes that we’ve defined.
Hey @saidsaifi The access policy rule page can require the user to be a member of a group and require a scope to be requested. If its not requested, you wouldn’t have it in the policy. Perhaps configure it up and have a play (if you haven’t already?). I’ve been surprised when my interpretation of the documentation/UI messages is sometimes different from how it actually works.
I’d try to find a mechanism that works within an open standards protocol (OpenID, OAuth, SAML) - don’t try for something custom as you could introduce security vulnerabilities and not be able to use standard toolkits/libraries.