My application uses Azure AD and OpenID Connect to sign-in users (see https://github.com/Azure-Samples/active-directory-dotnet-webapp-openidconnect).
I want to be able to list users' Azure subscriptions when they've signed-in. I cannot figure what I need to do after a user has successfully signed-in and they've been redirected back to my app, i.e. how/where I get a hold of the necessary access token or credentials, and, to be honest, which is the correct API to call with said token/credentials. Can this be done? Is an entirely different approach necessary?
Look through the code in the example for an instance of AuthenticationResult. The access token can be accessed at AuthenticationResult.AccessToken and you can decide what you want to do based off that.
One of the notification events (raised as part of the sign-in flow) receives an authorization code. With the code, I was able to acquire an access token (using AuthenticationContext.AcquireTokenByAuthorizationCode) and, with that, I was able retrieve the subscriptions using this API https://management.azure.com/subscriptions. Note: ensure your AD application delegates permissions to the Service Management API.
Related
I have created an API that is protected by OAuth using an app registration in Azure.
My app registration does not require assignment, but it exposes a number of roles that the underlying API verifies. To my understanding, this accomplishes almost the same thing as requiring approval.
So far I've only had user/group roles but now I've added an application role intended for integrators, and I want other application owners to be able to request permission to my API. I, as the API owner, would like to review these and either reject or consent to the request. E.g. I don't want everyone to be able to access my API within the tenant without my knowledge, just like all users/groups don't have access with me assigning them to a role.
The Role-based access control for application developers documentation makes it very clear who manages access:
...an application developer defines roles rather than authorizing individual users or groups. An administrator can then assign roles to different users and groups to control who has access to content and functionality.
However, if you create a role with allowed member types set to application, things are not quite as clear and it seems to behave more like a scope, where I give up any access management. Also from my limited understanding, a scope is used when the API needs to request data from the user (e.g. wanting to read their username), whereas a role is used for the application developer to control access to what they are developing.
This is what it looks like when I request access to my API from another app:
This same page mentions the following information:
The "Admin consent required" column shows the default value for an organization. However, user consent can be customized per permission, user, or app. This column may not reflect the value in your organization, or in organizations where this app will be used.
As well as:
Applications are authorized to call APIs when they are granted permissions by users/admins as part of the consent process
However, from my reading, it sounds like this never gives me, as the API owner, any insight into who has access to the API I own. I want to control application access the same way I'd assign a group or user to a role in the enterprise application.
Can this be achieved when it's an application on the other end, not a user? If not, how would I allow applications to integrate in a controlled manner?
I want to explain the feature Azure ad provided to protect web api here.
As you know, we usually use a token in the request header to let the api check if the request had correct permission to visit the api. Such as if the request from an allowed user role, right? So to whole progress should be authentication and authorization. Users sign in first then try to generate an access token to visit an api. Azure AD has similar architecture.
If you had a web application(e.g. web mvc app) you can integrate Azure AD into it then you can allow users use their user1#xx.onmicrosoft.com account to sign in. If you had a web api project, you can also integrate Azure ad and add [Authorize] attribute above the controller so that the incoming request should contain a correct Bearer token which we call it access token.
For Azure AD, we usually have 2 options, verification scopes or app roles. That results from the different flows we used to generate the access token. For example, we use auth code flow to sign in users and generate access token containing scp claim which is granted delegated api permissions. And we use client credential flow to let an application to generate access token containg roles claim which representing it's granted application api permissions. In short, when we set [Authorize] + [RequiredScope(scopeRequiredByApi)] in the controller, it allows requests from a user(user sign in the app and call api), when we set [Authorize(Roles = "roleRequiredByApi")], it allows requests from the application(no user signed in and the app call api by itself).
Here scopeRequiredByApi and roleRequiredByApi is what you exposed and then added to App Registration > Permissions. Just like Integrator you marked in the screenshot, it can be recognized as roleRequiredByApi because its type is Application.
And I'm afraid the roles is not what you want but to be honest what I said is what AAD can do for you... And I think the document I mentioned above about verification scopes or app roles will be a good sample for you.
The App Registration > Permissions section has a great feature for reviewing and limiting the access provided for your app registration:
enter link description here
In addition you should always define the scope of your permissions and limit it to the least required for your app. eg. NEVER set scope at the subscription level! Always set it at the resource group or lower.
Also note that Microsoft now provides Defender for APIs and you can use Sentinel to monitor a lot of the activities related to your app registration. Always always enable logging wherever possible and configure some method of alerting/reporting so you can better understand the activities for your app.
From the documentation it seems that using an application that is in the B2C tenant and thus hosts user accounts that there is no way to directly access Microsoft Graph API via a logged in user per their own context.
I want to establish the use case properly so that the solution is that which makes the most sense.
The use case is that if a user wants to edit claims for example such as permissions they would be able to do so while logged in through Azure B2C.
The flow would be. Logged in user -> can change certain claims information such as address, surname, and other custom policy fields (SEO contact permissions.)
Is the proper way to do this is to build a proxy that will take the application's AD application permissions which are allowed to call out to Microsoft Graph and pass along user context so that the scope will be limited to that user only?
For example. User logs into the app.
The app has AD permissions that are granted admin consent
Create a client secret to prove application identity upon request of a token
Now can access Microsoft Graph api
Ref of Registering an app with Microsoft Graph api
What's not clear here exactly is the next part. My user is logged in with Azure B2C. Should I just pass along their id token which has their claims to the application? How do I put in scope/context of the logged in user of the app permissioned access to Microsoft Graph?
This part is not clear in any documentation.
I don't want a logged in user to have access to everything.
Is a proxy the only way to do this?
If a proxy is the only way to do this what identifier or id is what should be used to pass along to the query to assure only that user is in context?
Am I thinking of this incorrectly and or is there a better way to do this other than a proxy?
The documentation says this.
Apps that have a signed-in user but also call Microsoft Graph with their own identity. For example, to use functionality that requires more elevated privileges than the user has.
That doesn't fit exactly into my use case above or address it really but I think it is related. The functionality should be considered to be an elevated permission but to the scope of the user. This user can change this claim via their own logged in entity. What do you call that and what is the best way to solution this?
Lastly, is there anything that should be known in the MSAL library including Angular and React that would be useful in this process? It seems like I will have to converge the 2 to obtain the access token of the app and of the person and proxy those out to a backend service (the proxy) to then do a body of work.
Am I thinking of this correctly?
This Stack is the closest to relevance but doesn't ask or solution the entire use case as I have here. But is useful for illustrating the confusion.
"Logged in user -> can change certain claims information such as address, surname, and other custom policy fields (SEO contact permissions.)"
Why can't you use the Profile Edit user flow? You can configure what attributes the user can change.
I am using an Azure ADB2C tenant to sign-up/in users with custom policies and rest api claims exchanges. This works fine.
Now I would like to start a service (daemon) that runs in a cloud environment for each user that signs-up with my service. This background service will access resources on other servers. Accessing these resources require a token and the service should only have access to the resources that the user has (i.e.: the access token used by the background service should also include the custom REST API claims). For the common users, this is taken care of by my REST API claims server, which enriches the token in such a way that it gives users' access only to the allowed resources.
I have found this page describing how to get access without a user. But this page assumes that the background service is a single instance that has access to all users' data that it needs. My background service is a 1-to-1 mapping to the signed up user.
Ideally this is how I see it working:
A new user signs up.
My REST API claims exchange gets called for this user.
Call Azure ADB2C to create a token for the background service. (Token should also contain my custom claims)
Start a new instance of the background service using the token created at step 3.
Return the custom claims for the new user.
This will happen for every new user, so every user in my system will have a corresponding background service running in the cloud.
Is this possible with Azure ADB2C? If yes, how?
The link you provide to get access without a user is only suitable for calling ms graph api and not for calling custom api.
If you are calling ms graph api, then you can indeed use the daemon-based client credential flow to obtain an access token (that is, without user involvement). This flow is usually used in Azure AD, but if it is used to call ms graph api, then it is also applicable to Azure AD B2C.
But if you are calling a custom api, then you must use a user login flow. Azure AD B2C obtains tokens in a different way from Azure AD. To use Azure AD B2C, you must first create a policy to enable users to sign up and sign in to your application.
I want to develop a SaaS application on Azure and deploy to the Azure marketplace. This app will be able to obtain information about the user's network. (for instance VNET information). Ideally I would like to have a single-page application that would authenticate with the user who subscribed to the app, and then make calls on a backend API tier, which would make calls to Azure management API endpoints.
The Azure docs layout a number of scenarios of how apps could interface with AD. how-to guides
I believe what im trying to do most closely matches the "Build a web app that calls web APIs" flow, which is an example of OBO. My question is, is that really describing what im doing? Is "calls web APIs" really an example of invoking APIs on the microsoft azure platform?
So my understanding is that I would develop my own API app, that would accept requests from my client browser code, which would contain an oauth token, and then the API layer would derive another token to pass onto the Azure API layer?
Im trying to keep the architecture as simple as possible, but im afraid I may be misinterpreting the Azure docs.
OBO (On-Behalf-Of) allows you to exchange an access token that your API received for an access token to another API.
The important bit is that the access token must have been acquired in the context of the user and must contain user information.
The new access token will then also contain this user's info.
So it allows your back-end API to call Azure Management APIs on behalf of the current user.
This means your API can't do anything the current user can't do.
It is limited to the user's own access rights.
The other option for authentication is to use client credentials authentication,
where your back-end API uses only a client id + certificate/secret to authenticate.
In this case the token will not contain user information.
To enable this approach, the target organization's users would have to assign RBAC access rights to your app's service principal, so it can act by itself.
You could also build a flow in your app where you setup these RBAC accesses on behalf of the current user.
Personally, I would prefer to use delegated access (OBO) whenever possible, as it will block the user from doing things they cannot do.
Though on the other hand, service principal-based access allows the organization to control your app's access better.
We have a multi-tenant single page app (and backend) that uses Azure AD for authenticating users. We'd like do queries to customer's Azure AD for retrieving groups but make it an opt-in behavior for customers (tenants). The reasoning behind that is that not all customers necessary need the functionality and would rather not grant us access to their AAD unnecessarily.
Is there some way of implementing this with Azure AD?
I've been trying to test with different OAuth /authorize calls with resource IDs and scopes but mostly I end up with "AADSTS65001: The user or administrator has not consented to use the application with ID ''. Send an interactive authorization request for this user and resource." error. Configuring the web app or backend to require the permission would surely fix the error but that will also make the approval of it mandatory for all users of the app.
Is there a way of using the authorize/consent API to request access to a new application on-demand?
An ugly work-around that should work would be to have 2 client IDs and 2 backend IDs with different permissions but ADAL.js doesn't seem to be designed to work with multiple Client IDs (it's singleton, for starters). Also Application Permissions should of course work but I'm not sure how much of those are required to search for groups.
Is there a way of using the authorize/consent API to request access to
a new application on-demand?
Do take a look at Azure AD v2.0. With their incremental & dynamic consent model, it is possible to do so though I am not sure if this specific functionality (managing groups) is available there.
I had a discussion with Azure AD team member recently about this (as we are also facing the same problem) and he suggested that we take a look at this.
Essentially the way things work in Azure AD v2.0 is that you start with basic set of permissions (like sign in, read profile etc.). Then when some tenant need specific permission, you essentially ask them to grant those permissions to your application at that time only. What this means is that different users in your application have granted different permissions to your application.
If you are using MSAL, and looking for a way to dynamically change your scopes before authenticating, have a look at this: https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-angular/docs/v2-docs/configuration.md#msalguard---dynamic-auth-request
More here: https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-angular/docs/v2-docs/configuration.md#platformbrowserdynamic