Checking Azure Active Directory group membership via MSAL in a SPA + Web APIs - azure-active-directory

I am building an application which has a front-end (a SPA built with Vue.js) which interfaces to a couple json-based Web APIs in the back end (hosted in Azure). The Web APIs need to be secured via Azure Active Directory and users must be a member of a security group. Furthermore, the SPA should simply try to force the user to sign into an approved account if they are not signed in as one (i.e. just auto-redirect).
I actually have all this working. The AAD application has Group.Read.All, the user signs in via the SPA and gives consent, and the SPA calls getMemberGroups. Furthermore, the Web APIs can check the SPA-provided access token, and the Web APIs unfortunately must also call getMemberGroups.
And I think that is my concern. The Web APIs keep having to call getMemberGroups to lock it down. If I did the auth on the service, I could potentially only return an access token once membership groups has been verified. But then I lose the easy MSAL sign-in model in the SPA - the Web APIs don't actually provide any front end, the SPA is statically hosted.
As far as I can tell, I cannot get Azure Active Directory to create a token guaranteed to have certain group claims in it. I think this would solve my problem.
Can somebody offer some advice on the best way to design an auth model around a SPA + Web API environment? Or is the method I have taken the only way to do it?
Thanks!

You can include Groups claim in your token as instructed here. You just need to modify the "groupMembershipClaims" field in application manifest:
"groupMembershipClaims": "SecurityGroup"
Then the token will contain the Ids of the groups that the use belongs to like below :
{
"groups": ["1ce9c55a-9826-4e32-871c-a8488144bb32"]
}
You can also leverage Role along with Groups to control access of your application. You can define some applciation roles and assign the roles to the groups. Then the users in the group will have the claim like below:
{
"roles": ["admin"]
}
Then you can implement your authorization logic based on the roles of the user.
Refer to https://joonasw.net/view/using-groups-vs-using-app-roles-in-azure-ad-apps and https://learn.microsoft.com/en-us/azure/active-directory/develop/howto-add-app-roles-in-azure-ad-apps for more details

Related

Validating tenant in multitenant React apps using MSAL

We're working on moving some apps from Razor Pages to React, and we'd like to use Microsoft Identity Platform for authentication via MSAL.
Some of these apps are multi-tenant, and we want to be able to validate that a given tenant is set up and authorized when a user logs in. Today, we do that in .NET via the OnTokenValidated event by pulling the email domain or tenant ID from the token claims and comparing it to our app's list of authorized tenants in our databases.
In MSAL, I'm not entirely clear how to accomplish that. The MS docs say, "If you allow multi-tenant authentication, and you do not wish to allow all Microsoft account users to use your application, you must provide your own method of filtering the token issuers to only those tenants who are allowed to login" (in https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-angular/docs/multi-tenant.md#multi-tenant).
Where in the React login or token acquisition process can I inspect the claims in order to perform this filtering? How are others handling these kinds of checks with MSAL on a SPA front-end framework like React?

Inviting User from one app for another app?

Our current system contains two web applications with OAuth2 centralized user management. Application A is an OAuth client and application B is the OAuth provider. And application A is for internal users and application B is for external users as well as internal users.
 
To integrate with CIAM for external user onboarding, our system needs to call the user invitation API. That only can be done by application A due to some restriction. Is that doable as an external user will only have access to application B. To invoke CIAM APIs, the client needs to be registered with Azure application ID. That won’t be a problem if the same Azure app ID can be shared between two applications or the invitation could be for another application with a different Azure app ID.
• As you have said CIAM here, thus considering Azure AD B2C as the IdP and authorization provider, the application B that you have stated here which will act as an OAuth provider for application A thus resulting in it being a client and the other application being a provider. Thus, as a matter of fact, you cannot share tokens between the apps for inviting a user from one app to another app. Also, sharing the same application ID between two different applications registered in different tenants is also not possible.
• But you can acquire a token interactively on the second application, i.e., application B and once the silent call fails, then the interactive flow will rely on the Azure AD B2C session cookies to give the user Single sign-on. You can achieve the above said through configuring the Azure AD B2C session behaviour with regards to single sign-on on an application. This setting allows you to maintain a user session exclusively for an application, independent of other applications. For example, you can use this setting if you want the user to sign into Application B regardless of whether the user is already signed into Application A.
Thus, in this way, you can share a sign-in between two applications. For more information and details regarding this, kindly refer to the below documentation below: -
https://learn.microsoft.com/en-us/azure/active-directory-b2c/session-behavior?pivots=b2c-custom-policy#configure-azure-ad-b2c-session-behavior
ADB2C How to share user token between two different applications?

Why do I need two AAD applications just to add roles into an access token?

As shown by many samples I have two AAD application registrations, one for my javascript-based front end, and one for my JSON-only web APIs.
If I fully trust my client AAD application, why does AAD require me to create a second AAD application for my web APIs?
For example, assuming I add specific roles to my client AAD application, if client signs in with AAD and gets an id token and access token containing my roles, it only needs to send the access token to my APIs. The API only needs to crack the JWT, validate the audience, issuer, tenant, roles permissions, and signature. In this world, no client secret is needed in the web APIs, a second AAD application registration not needed, and still no call to AAD from my APIs. Unfortunately, without two AAD applications, I cannot figure out a way to have AAD include roles into my access token.
If I didn't fully trust the issuer from mucking with claims, I can see why I would need two AAD applications and a client secret. But since I do trust my AAD application and the signature of the JWT, why the extra complexity? Or maybe there is a way to do this that I haven't found?
Thanks!
Responding to Marc here because just not enough characters in the comments field -- The sample you referenced is an excellent sample, specifically the JavaScript one calling the Web API. It is what I am doing right now in fact. However, the problem is that Web API in the sample is open to anybody who has authenticated on the tenant. I need to secure the Web API down to certain individuals in the tenant, and simply checking the client/app id is not sufficient as anybody who can create an AAD app can fake it.
So what I need to do is have roles added to the the access token so I know that my application authenticated the user, and that user has been granted the required roles. For example, here is a Microsoft sample. And even here a Microsoft video walking through the process.
If I don't have two AAD applications w/client secret, the roles claims is never provided in the access token. It is always provided in the id token, but not the access token.
I feel like I am missing something obvious here. If AAD would just put the roles I requested into the JWT when I authenticated against it, and I validated its signature, audience, issuer, and roles, I wouldn't need any of this extra complexity?
Ah, I think I understand where you are going: you would like to control which users can access an API, no matter what client app they are using to access the API with. That's a function of the API - you cannot control that through AAD. In AAD you can control which users can access which applications (UI) using either user access restrictions (enterprise tab) or role-based access. However, access to an API is controlled in AAD at the calling application level via scopes. APIs are never accessed directly by users but only by other apps so controlling access permissions at user level would cause admin havoc. So, you can control what permissions a user has in the app they are using and you can control what permissions that application (client) has in other applications (APIs, resource servers) it is using.
In other words: role is about user access to UI, scope is about one apps' access to another.
App secrets provide added security for getting tokens - they have no bearing on what permissions are included in the token.
Can you provide a link showing that two apps are needed? That should only be the case if the API you want to call is not provided by the web app which served the JS to the browser. None of the 'official' samples require you to register two apps (Graph API, used in some of these samples is a separate API and it is already registered). A problem with tokens passed from the browser is that they were acquired by a public client, not using any secrets apart from user creds. Therefore, they are easier to steal and re-use. Your own back-end app may want to use a secret to get its own token (extension grant) to call yet another API using a token that does not reside in a public client.

Multi-Tenancy in a Single Azure Active Directory Application

I have dozens of Azure Active Directory API's and SPA's that talk to each other. Here is an example:
User - Has roles necessary to use SPA and API 1
SPA - Talks to API 1 using Delegated Permissions
API 1 - Talks to API 2 using Application Permissions
API 2
These SPA's and API's each have a single Application and Client ID in Azure Active Directory but they are multi-tenant, in that they serve internal users in multiple countries using Role Based Access Control (RBAC).
All of the above applications run internally but I have a new requirement that we need to hand over the SPA application to users external to the company and that they should not be able to see parts of the SPA for other tenants and also they must not be able to call API's for other tenants. How can this be achieved?
For your scenario, I think you can use Azure AD App roles for it.
For example:
You can create two roles in the Azure AD applicaiton for the SPA. One is Admin,who can access whole SPA site and API 1. One is User, who can only access part SPA and cannot access the API 1. Then you can assign roles to users.If you have AAD basic or Premuim , you can assign roles to groups.
After finishing this, you will get the roles information in id_token. So that you can give them different access to your SPA. The rest work should be built in your SPA to deliver different access to different users.
You can also read this blog written by joonas for more detials.
Addtional, this answer is just a solution as I thought, it may be a little different from your realtic scenario which I cannot test.
Hope this helps!

Multi-tenant ADAL JS SPA along with an Azure AD web application back-end

I'm currently trying to implement a multi-tenant Azure AD application that will use Microsoft Graph API's to monitor and analyze Office 365 "metadata" for members of the tenant domain. For example, the application might monitor One Drive user space over time. The architecture of the application will include an AngularJS SPA client along with a web application back-end. The idea is that the web application allows for both local registration (e.g. traditional sign up using an email address and password) in addition to Azure AD authentication. In the case of local registration, the user might be able to associate an Azure AD tenancy with the local account in the future, for example.
I'm struggling to understand how various authentication mechanisms should work. For example, I think that there should be two levels of authentication in the case of Azure AD: one authentication for the users of the client SPA, and another authentication used by the back-end for making continuous calls to the Microsoft API's, requesting refresh tokens, etc.
How might this architecture be implemented using the various Azure AD authentication scenarios Microsoft has already provided examples for?
If my initial inclination that I will have two applications registered with Azure AD (for example, the SPA registered as a native application, say, and the web application registered by itself), how will users allow access to both of them, and what would this workflow look like? In addition, what would the flow of user requests look like? The SPA would make a request to the back-end using its Azure AD token, but what will the back-end do to receive its authentication token and make calls to the Microsoft API's?
How might I best incorporate Azure AD authentication along with local registration into my application?
Generally speaking, you can associate your each user to his entity in Azure AD tenant in your backend server / database. As every user in Azure AD has several unique properties in the entity object. You can use the user's email or objectId as mentioned at Claims in Azure AD Security Tokens as the external column in your user table.
When your user authenticate your site via ADAL.JS, you can grab the access token in your backend server via the Authentication header. You can use the access token to request for the resources protected by Azure AD. And the access token is a JWT token, which you can decode directly to get the user basic claims as we mentioned before. You can retrieve the claim which you stored in your user table and match the special user registered in your server for requesting the resource protected by your self.

Resources