How to get scope list from service for specifying with client authentication request - azure-active-directory

I have a UWP app that uses WebAccountManager for AAD authentication. I also have a service, hosted in Azure, used by the UWP app. That service uses the token the UWP app sends to get another on-behalf-of token (I think that's what it's called) to then call other service APIs as the user (e.g. Microsoft Graph and Outlook REST API). In other words, UWP app calls WebAuthenticationCoreManager.RequestTokenAsync to get a token, sends it to my service, my service calls AuthenticationContext.AcquireTokenAsync to get an on-behalf-of token to use when calling the Outlook REST API, for example.
In the AAD registration for my service, the "Required Permissions" list all the services and permissions/API calls it might make on behalf of the user (E.g. "Microsoft Graph"-> "Have full access to user calendars")
When my UWP app creates the WebTokenRequest to pass into the RequestTokenAsync function, it currently passes an empty string as the value for "scope." What should it be passing for the scope parameter? Should it be passing the full and exact list of permissions that the service declares are required? If so, how do I get that permission list to the client? Just hard-code and update the list whenever the service required permissions list changes?

In Azure Active Directory, there are two fundamentally different ways to specify the permissions your app requires when authenticating.
Static Consent
Dynamic Consent
Back in the Azure Active Directory V1 endpoint, you would set "Required Permissions" to other APIs when registering your client application. This is setting up Static Consent. These permissions are fixed, and when you trigger the user to consent to these permissions, the user has to consent to them all at once. Additionally, if at some point your app wants to add new permissions to other APIs, you will need to force the user to go through the full consent experience again, which may even require special logic on your application.
This is why in the V2 endpoint, Microsoft developed Incremental and dynamic consent.
With the v2.0 endpoint, you can specify the permissions your app needs dynamically, at runtime, during regular usage of your app. To do so, you can specify the scopes your app needs at any given point in time by including them in the scope parameter of an authorization request.
Here, you can specify only the permissions your app needs to complete the flows it is trying to accomplish at that time. If you need more access, you can simply add it during your authentication experience, and it will prompt the user only for those new permissions.
Now let's return to your question. If you are using the V2 endpoint, you should be using Dynamic Consent, which means that the settings in "Required Permissions" do not really matter to you. You should be keeping the list of scopes your app requires in your app settings.
Some situations in the V2 endpoint still require Static Consent, like service to service calls with direct application permissions. For those situations you would pass the scope <resource>/.default as noted here. This might also work for delegated tokens, but it is better to just use Dynamic Consent.

Related

Azure AD OBO Reconsent

I'm currently developing an application which consists of a frontend SPA which makes request to a Node backend. The Node backend makes requests to MS Graph. For this usecase I set up the OBO flow which works fine.
The SPA uses MSAL.js to request a token for middle tier API with /.default scope. The middle tier API knows the client as 'knownclient' in its Manifest. On very first login the application wants the user to consent to the combined scopes from client and middle tier. (If the user never used the app before)
The problem now is the following: By going further in the development process, new scopes are added for MS Graph in the middle tier API. However the client doesn't show the consent prompt to the user for giving his consent to use the new backend scope although using the /.default scope in the client.
The first approach I had was settings prompt='consent' to the MSAL setting in the frontend. This approach works but results in asking the user for consent every time he logs in.
The intended behaviour would be to just ask for consent if the middle tier API changes its scopes.
How do I have to set up my applications to get this result?
As I said in the comments, if you just add new permissions, don't use prompt='consent', because this will cause the administrator consent page to be triggered every time you log in as a user.
When you add a new permission, you only need to grant the administrator's consent, and there is no need to request the user's consent again. So, you only need to grant the administrator consent in the Azure portal. Or, use the url that the administrator consent to: https://login.microsoftonline.com/{tenant-id}/adminconsent?client_id={client-id}.

Application does not have sufficient permissions against this web resource to perform the operation in Azure AD B2C

I have created Azure AD B2C Application and tried to integrate with React JS using MSAL Library , When i tried to get access token I am getting following error.
AADB2C90205: This application does not have sufficient permissions against this web resource to perform the operation
Any Help would highly appreciated.
The link provided by #Jas Suri is correct, but I need to add some more:
You need to create two applications, one representing the client application and the other representing the api application, and then use the client application to call the api application.
Next, you need to expose the api of the back-end application and record the scope name, then go to the client application to add the scope to the API permissions (you need to find it in My APIs), and grant the admin consent to the permission.
Finally, when you get the access token, you must add the scope.
You didn’t grant admin consent. Follow this:
https://learn.microsoft.com/en-us/azure/active-directory-b2c/add-web-api-application?tabs=app-reg-ga
Specifically the Grant Permissions section.

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.

Why do i need to create a Multi-Tenant App?

I have been doing some R&D on using the MicrosoftGraphAPI to fetch the skus subscribed by my organization.
I have created an app as described in the documentation. I did all the steps in the above link except 'Assign application to role'.
Using postman am able to get the oauth2 token by sending a post request using the link
https://login.microsoftonline.com/<mytenantid>/oauth2/token
with the client_id, client_secret, resource(https://graph.microsoft.com) and grant_type(client_credentials) parameters.
After this token is obtained I can fire a get request https://graph.microsoft.com/v1.0/subscribedSkus with the Authorization header set as Bearer {token} which will return the SKUs subscribed by my organization.
So far so good. :-)
Now the requirement is I need to fetch the subscribed SKUs by one of the client (let's say having the azure ad tenant id 'ABCDEFG') of my organization.
I can successfully do that by registering an app in the client's tenant 'ABCDEFG' with the same steps as above.
This approach is fine if my organization has say 1 or 2 clients.
However, if the client numbers are more than say 30 this approach of registering an application in each Azure AD instance is not feasible.
If the application that I registered in my organizations AAD was multi-tenant then how should it help me?
What will be the steps needed to obtain the access token for each tenant?
Can somebody assist with some detailed explanation?
Since you need application-level access, you would assign one of the Application permissions listed in the documentation for getting SKUs: https://developer.microsoft.com/en-us/graph/docs/api-reference/v1.0/api/subscribedsku_list.
Directory.Read.All, Directory.ReadWrite.All
In this case you should require the Read Directory Data (Directory.Read.All) application permission.
Then you mark your app as multi-tenanted.
Now then in order for another org to use your app, they will have to be on-boarded.
You will need some kind of page where their administrator can click a button/link to start using your app.
This should redirect the admin to:
https://login.microsoftonline.com/common/oauth2/authorize?client_id=your-client-id&prompt=admin_consent&response_type=code+id_token&redirect_uri=url-where-to-send-user-back
Once they sign in, they will be presented with a consent screen, where they can approve the permissions that your app requires.
If and when they do that, they will be redirected back to your app (to the URL you specified) and you can use the Id token to know which Azure AD tenant registered.
During this process a service principal for your app is created in their tenant, and the required permission is granted to it.
This means you can then get an access token for their tenant from: (using the same credentials)
https://login.microsoftonline.com/their-tenant-id/oauth2/token
Remember that access tokens are specific to an Azure AD tenant, so you will have to get an access token for each tenant.
One thing I would like to point out is that you should instead try to use delegated permissions if possible.
The application permission given here gives quite large access to your app, and some admins might not use your service for that reason alone.
Delegated permissions are more complex to handle, but allow your app to act on behalf of a user instead of purely as itself.

Gmail API Access Single User Without Domain Wide Delegation

We have a bit of a dilemma that we are running into with a couple applications that are trying to read a given users email without user interaction to authorize. The key to this approach is that we want no user interaction, and want to load the client server application with the proper JSON credentials downloaded from the Google Developer Console.
I have this approach working for programs where we create a service account in the Developer Console, and then delegate domain wide authority to that account with the proper scope access. However what we are hoping is that we don't have to delegate domain wide authority, and just read the users email who created this developer console project. I have tried many different types of solutions for this, but always run into the same limitation that I have to grant domain wide access.
What I am wondering is if there is any way to gain access to a single users mailbox using a server to server type approach and not have to grant domain wide access?
I appreciate your help with this issue!
There is no supported authorization flow for what you want to do. You must either use a service account that has been delegated domain-wide authority, or you must use a 3LO flow that involves user consent.
It seems you're looking for OAuth for Server to Server Application. You will also be using a service account. But, granting of domain-wide authority for service accounts is an optional thing. You don't have to enable it if you don't want to.
To support server-to-server interactions, first create a service
account for your project in the Developers Console. If you want to
access user data for users in your Google Apps domain, then delegate
domain-wide access to the service account.
Then, your application prepares to make authorized API calls by using
the service account's credentials to request an access token from the
OAuth 2.0 auth server.
Finally, your application can use the access token to call Google
APIs.

Resources