I am building a system where a SPA can call an API. The SPA as well as the API are represented in Azure AD using app registrations that require users to be assigned to it.
During the assignment, the user is also assigned to a Role that the app registration exposes. The available roles are Developer
and User
in both the SPA and the API app registration, and I assign the user the same role in both registrations.
The API registration also exposes a scope that the SPA registration uses to request access tokens.
The role from the SPA is used to render different UI elements depending on if the user is assigned Developer
or User
.
Once the user has approved the scope requested by the SPA to the API, it is also possible to call the API. The aud
claim for this access token is the id of the app registration for the API, and it also contains the role Developer
that was assigned in the on-boarding step.
I think this diagram properly represents what is happening:
I have a couple of questions regarding this that I have a difficult time figuring out just be by reading documentation.
Managing roles in chain of calls (SPA -> API)
What is the proper way of propagating a role through a system? Do all app registrations need to have the same roles, and users assigned manually to roles in each registration?
Or can I propagate the role received by the user when they first sign in to the SPA, or does this break the security of JWT? I'm guessing this needs to be handled in each app registration because nothing would stop my modifying an outgoing request and set the role to Admin
instead.
Roles and scopes
I found this answer that partly explains the concepts to me. I am building an internal system and don't really need any other user data than the OIDC User.Read
provides (email, oid and so on). This scope is requested by the SPA to display the signed in users name.
My APIs will never require any other information than that from the user. Do I even need scopes in this case?
Do consent only apply to scopes?
Is knownClientApplications
and preAuthorizedApplications
only applicable when using scopes?
I apologize if this is rambling, I've been reading so much documentation that I can't keep my head straight.
I totally forgot about this, but the problem is solved and here's some info that hopefully clears things up a bit for others.
If your API is requesting data owned by the user, use scopes. If your API needs to handle role based access, e.g. users can be regular users, administrators or whatever, you use roles.
We went ahead with roles, so that is what I will talk about. We have one app registration for our SPA and one for our API. The roles needed to be defined on each app registration, roles are not propagated. Just because you are admin in the SPA does not mean you are admin in every API backing the SPA.
You create roles in the app registration under the App roles blade. Roles by themselves won't do anything, unless you assign users or groups to them. Users and groups are assigned to roles in the enterprise application corresponding to your app registration. You modify this under the Users and groups blade in the enterprise application.
In the above described chain of on-behalf-of calls there are four (4) app registrations:
API Z does not care (and should not care) what roles and permissions does the user have in any other system.
Roles and claims only follow the resource for which they are defined and will never be included in access tokens for other resources.
If you define app roles for your SPA client registered app, these will only be present in the id token obtained for the SPA client and in no other token.
It is debatable whether one should register multiple OAuth resource servers (app registrations) or just a single one and work with different roles and scopes within same app registration. Take MS Graph for example - really just a single resource server, but hundreds when not thousands of scopes and app roles. And even there, the fact that User A has
Directory.Read.All
permission, does not necessarily mean they should be able to read mail messages in exchange.