Protecting SPA and API using Azure AD and app roles

1.1k views Asked by At

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: enter image description here

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.

1

There are 1 answers

0
jokarl On

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.

  • App Roles are defined for each resource server (API)
  • App Roles are assigned explicitly to each resource server (API) and User / Group
  • App Roles relevant (defined by) for a resource (identified by aud claim) are issued in the respective token
  • The fact that User A is administrator in API X does not mean this user is automatically administrator in API Y. It is a bad design to consider otherwise.
  • If User A is administrator Z in API Z this will be correctly reflected in the token obtained via on-behalf-of flow in the following (sample / illustrative) chain:
    • Client B (e.g. SPA) requires authorization via PKCE for User A -> this way Client B gets access token for API X (no roles in this token) -> API X uses on-behalf-of flow to obtain access token for API Y (no roles in this token) -> (repeat this step as much as your design requires) API Y obtains access token for API Z using on-behalf-of flow -> The access token for API Z will have the administrator Z role for User A.

In the above described chain of on-behalf-of calls there are four (4) app registrations:

  1. Client B (SPA Client)
  2. API X
  3. API Y
  4. API Z

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.