How do I add users to tenant via the Graph API? - azure

I've utilized the Partner Center REST API to provision tenants with orders/subscriptions. Now I want to start configuring the domains and users for the tenant I just created. My first step was to get a list of users using the Graph API https://msdn.microsoft.com/en-us/library/azure/ad/graph/api/users-operations as a test expecting to see the admin account. If I pass in the domain of the reseller account in the request URL, it shows me the reseller users. But when I put in the domain of the account I just provisioned, I get Invalid domain name in the request url. I'm using the resellers AD token to do this. I'm confused as it gives me the option to specify a domain, but I can only access my own.
What credentials am I supposed to be using here? I tried to use the user/pass that was generated for the admin account from the provision, but I get unauthorized_client when trying to get an AD token from the Graph API.

It is hard to directly address your issues here since they are a little broad, and I would need more specific details about the various tenants you are working with, how your app is provisioned, permissions your app has etc...
However I think there a few principals you can follow which may help you debug your issues.
All AAD Authentication happens within the context of a specific tenant. This means whenever you get an access token for a resource, the scope of that token is limited to the boundaries of the tenant.
To authenticate with a client application in the context of a tenant, you must have the app registered in the tenant you are trying to access (line of business application / single tenant) or you have to make the app multi-tenant, in which case your app should be able to function in the context of any tenant... if the right provisioning has occurred.
Every tenant where your app is trying to function must have a service principal for the application provisioned in the tenant. This service principal represents your application's identity in the context of that tenant, and acts as a place to store the permission your application has in the context of that tenant. Most normally, this service principal gets provisioned into a tenant after a user from that tenant has consented to use the app as a part of the login experience.
If you are trying to use user context (authorization code grant flow) to retrieve details about a tenant, you must ensure that that user is present in the directory you are trying to query. For example a user U can exist in their home tenant T1. If you try to query another tenant T2 using that user account, you will get any number of errors describing that the user account does not exist etc. You can remedy this by creating a guest account for U in T2, in which case there will be a brand new user object created in T2 which links to the original user object in T1. None the less, the user object should always be present in the tenant you are trying to query.
If you are trying to sign into an application with a user account that is in T1 and T2, you need to be sure to specify the tenant you want to actually get the token for. By default, if you use the common endpoint, you will get a token for the users home tenant. However, it is perfectly valid to get a token for the secondary tenant, as long as you specify that to our Token Service when making the request.
Finally the client application you use to make these requests needs to have the right permissions to the Graph API if you want to make specific calls to the Graph API. Every tenant needs to individually consent to the application in their tenant context in order to provision the correct permissions to their application.
With those principals in mind:
The error you are getting with "unauthorized_client" seems to be an issue with application provisioning in the secondary tenant. Please make sure to first login to the application with a user from the secondary tenant, and make sure that user has the correct permissions to consent to your app (a tenant admin is best here).
For the second issue with "Invalid domain name in the request url" please try using some hints here.
Specifically this:
By using the myOrganization alias. This alias is only available when using OAuth Authorization Code Grant type (3-legged) authentication; that is, when using a delegated permission scope. The alias is not case sensitive. It replaces the object ID or tenant domain in the URL. When the alias is used, Graph API derives the tenant from the claims presented in the token attached to the request. The following URL shows how to address the users resource collection of a tenant using this alias:
https://graph.windows.net/myorganization/users?api-version=1.6.
I hope this puts you on the correct path to resolve most of your issues.

There are issues with sandbox accounts and Azure. Access to the Azure Management Portal for the sandbox isn't straightforward and at this time does not work properly. I had to create a free Azure account with my hotmail account, then link AD from the new account to my sandbox AD to bypass the bug. When adding a new directory to the new Azure account, select "Use existing directory", sign out, then sign into the sandbox account you want to link it to. Then create your app from the new account.
After getting my app setup properly and new credentials, I had to enable pre-consent with the instructions listed at the end of: https://github.com/Microsoft/Partner-Center-Explorer
Lastly, I had to login to the Graph API with the customers ID, but with the resellers credentials.

The scenarios on the Partner Center SDK website include a section "Manage user accounts and assign licenses" under the "Manage customer accounts" section.
These samples include creating users and assigning licenses and a link to a console test app.
As an aside, a new version of the Partner Center SDK has just become available here. It was released on July 5th. While there is no official change history that I can find, I can see that it includes some new classes such as CustomerUser. You may find it easier to use that library rather than hitting the REST API (depending on how much work you've already done).

Related

Difference between an application role and scope in Azure AD app registrations

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.

Interactive Browser Credential "You can't sign in here with a personal account. Use your work or school account instead."

I am attempting to implement Interactive Browser Credential with Azure Identity (JS) in my app so that users can authenticate to their own Azure accounts for my dev tool. I got advice that app registration in Azure AD would be required on a Reddit thread (https://www.reddit.com/r/AZURE/comments/smcl15/azure_identity_sdk_js_how_to_authenticate_to/). I have now done so.
I have registered localhost:8083 and localhost:8085 as redirect URIs and selected the option to allow Account in any organizational directory. However, I am still getting the error "You can't sign in here with a personal account. Use your work or school account instead." Every answer(Access with personal account to multi-tenant application AAD) I have read on the topic says that I need to set "signInAudience": "AzureADandPersonalMicrosoftAccount" in the manifest. However, that is how my manifest already is and has been since the beginning. How do I fix the error?
This error may occur in one of the below two scenarios.
1. Resource being different from client application
Please ensure the request resource is added to the applications required API permissions and the resource API has been consented to .Resource for which you want an access token, you can pass either the Resource URI of a Web APP, or the client Id of the target Web API. It's important to note that the token contains the resource as requested (audience).
If you have a permission something like user_impersonation, try by giving scope as https://management.azure.com/user_impersonation
Please check if you need to add api version as query string as per Azure REST API reference documentation | Microsoft Docs.
Make sure you see the app in the app registrations >all applications blade while Searching for the appId present in the error provided.
2: Resource and client is the same app registration
In app registrations ,after exposing the api and adding permissions and scope, Ensure the app has been consented to permission.
For example:

Identical Azure apps do not work in different tenants

I use Azure apps to sign users in to a web app and a desktop app. I also query for user information via Microsoft Graphs /user/ endpoint.
So we have to apps registered in Azure; one is a web app / api with permissions to sign users in and read all user profiles from graph. The other is a native app with permissions to the first app, and permissions to sign users in.
In one tenant, this works fine. However in the other tenant the web api har permissions to sign users in, but Graph declines access to the /users/ endpoint due to insufficient privileges. The error is: Authorization_RequestDenied, Insufficient privileges to complete the operation.
However the exact same privileges work fine in another tenant. In the faulty tenant we get a token from graph but when we use the token on the user endpoint it throws the insufficient priv. error.
Signing in users via the desktop app (we use owin) works in one tenant but in the faulty one it sais that app tenant.onmicrosoft.com/guid does not exist in tenant.onmicrosoft.com
The app uri is correct in the settings and the app has the same privileges in both tenants.
We tried recreating the apps since this has solved similiar issues when developing things like this before. This time it doesnt seem to work however. Now I'm at my wits end here. Could there be some other issue blocking here?
The faulty tenant is part of a multi-tenant. However we only poll for users in one tenant as of now.
The apps have also been given consent by an admin via the azure portal. What am I missing here? How should i proceed with trying to fix this error?
Edit: I added a new directory in my tenant and it does not work in this new directory. Same error as with our clients tenant.
Working token for directory A:
eyJ0eXAiOiJKV1QiLCJub25jZSI6IkFRQUJBQUFBQUFDNXVuYTBFVUZnVElGOEVsYXh0V2pUQkVOV21GUUgtZjRGS0VjYlIwU3Y1NndrdzhvSjhjbDIwX3JtZEJBc2h6eDhKT2VNZjFEbVFjNm1GUUdxZ2VSRFJZMTEzNXE3ZXJkTjlHTFZ6T3NycnlBQSIsImFsZyI6IlJTMjU2IiwieDV0IjoiaTZsR2szRlp6eFJjVWIyQzNuRVE3c3lISmxZIiwia2lkIjoiaTZsR2szRlp6eFJjVWIyQzNuRVE3c3lISmxZIn0.eyJhdWQiOiJodHRwczovL2dyYXBoLm1pY3Jvc29mdC5jb20iLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC83NTYzNTY2OC03OGNlLTQzNDMtODMzYy0xOWM5ODkzNTRkZWYvIiwiaWF0IjoxNTM5NjExMjk2LCJuYmYiOjE1Mzk2MTEyOTYsImV4cCI6MTUzOTYxNTE5NiwiYWlvIjoiNDJSZ1lNaWExaldMdTJqUmkvWjlQenU4bHZkUEJRQT0iLCJhcHBfZGlzcGxheW5hbWUiOiJLRVlPMzY1IiwiYXBwaWQiOiI1MmQwMTdmZi1lY2ZjLTQ2NjgtYjZkZi0zZDNlZGYwZDFjNjIiLCJhcHBpZGFjciI6IjEiLCJpZHAiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC83NTYzNTY2OC03OGNlLTQzNDMtODMzYy0xOWM5ODkzNTRkZWYvIiwib2lkIjoiMjM0ZDhmZTctNmYwZC00NmEwLWI1YmYtNzg1MWY0ZmFmNmMyIiwic3ViIjoiMjM0ZDhmZTctNmYwZC00NmEwLWI1YmYtNzg1MWY0ZmFmNmMyIiwidGlkIjoiNzU2MzU2NjgtNzhjZS00MzQzLTgzM2MtMTljOTg5MzU0ZGVmIiwidXRpIjoiUDNvc0hHdHQyMFdRTXhkLVFxcWNBQSIsInZlciI6IjEuMCIsInhtc190Y2R0IjoxNDQ3MDYyNTMyfQ.prmIaq8PzXfeovQPeIYS20xvZqpjPH-DvZNwQ3v08KOhTnfFaiCkxtw2wh1B37QQDbOveYqCWRi2CE6Uwpb6zg3-tFh1ma852HDqnJHYCKPajxeW9oIewAnCagB5FzOLQRT_EbX-lEREQVcPUHSZpRNmAWEM2MOZjDnkWun_aqohf_1op7Cy40Ol_PkRzoEgmA7pbXeI28IMPW3S4a5M_hBo_MZzRbVdxuG8YQKkVMWX0wAhpLHAYbdF1Rv5sITEpBP-KHdgJkTswLs3xvIRLyXxrXobG1aVQihr7LHFoCIU0NAcCUQLS2xkePuYGRB09k7hFQsbSNxoJSywBZWk7w
non working token for directory B:
eyJ0eXAiOiJKV1QiLCJub25jZSI6IkFRQUJBQUFBQUFDNXVuYTBFVUZnVElGOEVsYXh0V2pUUS1NMnBUdmVjYTgzUXFuVmlBWWpJX0dLNHZrMTBMYVF2dGF5SGQ0WmZDVlRySm0wSmtOVDU2UlJSU0NuUlFPU0k0aVNHdXZZZ1cxelpaTE9KTkJTVHlBQSIsImFsZyI6IlJTMjU2IiwieDV0IjoiaTZsR2szRlp6eFJjVWIyQzNuRVE3c3lISmxZIiwia2lkIjoiaTZsR2szRlp6eFJjVWIyQzNuRVE3c3lISmxZIn0.eyJhdWQiOiJodHRwczovL2dyYXBoLm1pY3Jvc29mdC5jb20iLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC84MTFjNjA2OS1kZDE4LTRmN2UtOTlhMy1lNjA2YzMyYjhhMjAvIiwiaWF0IjoxNTM5NjExMjI1LCJuYmYiOjE1Mzk2MTEyMjUsImV4cCI6MTUzOTYxNTEyNSwiYWlvIjoiNDJSZ1lPZzlraUZYR3BxNCtVMko1NHAvL2N2M0FRQT0iLCJhcHBfZGlzcGxheW5hbWUiOiJGZXRjaGluZ1VzZXJzQXBwIiwiYXBwaWQiOiJiNDAyZjI5Ni05OTAxLTRjNmMtYjA2MC1hNGI1M2VjNmMzMDQiLCJhcHBpZGFjciI6IjEiLCJpZHAiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC84MTFjNjA2OS1kZDE4LTRmN2UtOTlhMy1lNjA2YzMyYjhhMjAvIiwib2lkIjoiYzIyZWJmNmEtZDNkYS00ZGRjLWIzZTYtOWFhY2VmZWY3MmE4Iiwic3ViIjoiYzIyZWJmNmEtZDNkYS00ZGRjLWIzZTYtOWFhY2VmZWY3MmE4IiwidGlkIjoiODExYzYwNjktZGQxOC00ZjdlLTk5YTMtZTYwNmMzMmI4YTIwIiwidXRpIjoiNk4xRnBkRVZEMGFvRnM0UndVRGZBQSIsInZlciI6IjEuMCIsInhtc190Y2R0IjoxNTM5MTU0MTkxfQ.l_7qgXkco5FWR7pbX5rQzAtvnrb1e6xOr5byrvkYDcyNa85KmCu5b6ArfjxTmeDR82XTmYw51n2YAbWl2q8R58dqELOguddwnKkBBCiMwKsD_UvG2oX_M9ZMy-Lc8lERduolyST7D0BZSoYCNe9f0j85AXIOgXr_yMA5MrVz7qSVFKZ1if2BR9YvvMCphW2uQCrebEJAnchyxHiCb5refnhm2sfsDBRJqd5NWwK0-a956a6dC2zg59JbW55-3wezQOfXKYzC5ybzO7l1hV41EnJ4atBW6EvR2er7WyCAFb1Y1hSB_wgZSo7pC4LnQRRm9KXq-x2aSRKiUSg265K0RQ
You need to receive Admin Consent for an administrator of the tenant. I'm assuming that because this happens when hitting /users, you've requested either User.Read.All or User.ReadWrite.All. Both of these require Admin Consent before a normal user can authenticate and provide User Consent.
I wrote an article a while back that you might find this helpful here: User vs Admin Consent. The examples target the v2 Endpoint while it sounds like you're using v1. That said, the same consent models and workflow apply to both v1 and v2.

Azure Active Directory Invitation Manager, register user in another tenant

What I am trying to do is to automate the process of adding a new user to an Azure Active Directory of a tenant (the tenant is supplied as a parameter).
For this, I understood that I must use Azure AD B2B collaboration. The official sample for automating this process is provided by Microsoft at this link:
https://github.com/Azure/active-directory-dotnet-graphapi-b2bportal-web
So, using the Invitation API (which is available here: https://developer.microsoft.com/en-us/graph/docs/api-reference/v1.0/api/invitation_post), I programatically send an invitation mail to an email that I want to register.
The problem is that the user which will be registered with that email, will be registered within the tenant in which the application was configured.
For example I am using the tenant name X, to configure my application in the Azure Active Directory Portal. What I see is that I can only invite emails to register within my tenant named X.
What if I want to register an email within another tenant, tenant which I know beforehand?
Can the invitation Api specify in which tenant I want to register an email, without having the application registered in that tenant?
Because if I can't, I would have to register the application in all the tenants, and then apply logic in the code to link the Client ID and Client Secret to the correct tenant.
If I have understood your question correctly, you need a multi-tenant app.
When you get an access token for Microsoft Graph API, it will always target a specific tenant.
In order to get an access token which targets another tenant, you must:
Make your app multi-tenant: https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-devhowto-multi-tenant-overview
An admin from the other tenant must perform a sign up, which asks them for consent to the permissions your app requires
This usually means a redirect to the login page with prompt=admin_consent in the query
After they consent, a service principal will be created in their tenant, and they are redirected back to your app as usual
Now you can get an access token targeting their tenant and use it to call Graph API

B2B with Microsoft Graph

As you probably know, I am creating a multi-tenant azure application, which is using the B2B functionallity.
I am testing the B2B functionality and after some research I got a working sample.
Small summary: User authenticates against common authority, first token is acquired via common authority with the authorization code and from then, everytime I need a service client, I try to obtain those tokens from the 'current tenants' authority.
When I request 'Me', it only works against the home tenant. When I request me with a trusted tenant, I got an error that my user identifier does not exist in the directory. Probably because user does not actually exist in the trusted tenant.
When I request Users, it works fine. I can get both, home tenant users and trusted tenant users.
Is this normal behaviour?
Is this something I need to handle programmatically or would this been solved by using the AD graph?
(So when I know I need user info, just query the home tenant?)
Or is this a bug?
Any thoughts on this would be greatly appreciated!
Guests added to a directory via the B2B Collaboration feature will not work correctly on multi-tenant apps or the Microsoft Graph if you're using the common endpoint.
The common endpoint will always authenticate the user against his/her home tenant, not against any tenant where (s)he is a guest.
In order to successfully query /me for a guest, you'll need to have them sign-in through the tenant specific endpoint for the tenant where they're a guest.
See my answer to this other post for a more in-depth explanation / context:
Can users from an unmanaged Azure AD directory, sign into an Azure AD multi-tenant application which resides in a different directory?
I have noticed that when you want to switch between tenants, you need to re-authorize against the current tenant.
I got it working this way:
1. First sign-in needs to be done against the common endpoint.
2. Every time I need a token for certain resource, I try to get the token silently.
=> This can throw 2 different AdalSilentTokenAcquisitionException
Nothing found in cache, also no refresh token found
=> In this case, I redirect the user to the login page again.
When you switch between tenants, and it is the first time you want to login using a tenant where you've been trusted, you can get a error like: User or admin should be given consent for this application. Although the admin from his home tenant has added the application in the directory for the home tenant. Anyone who knows why this consent is needed? So tenant A and tenant B admins have both been given consent. Why does a trusted user from B in A still needs to consent someway?
I was able to trigger the consent flow by redirecting the user to the authorization request URL.
So when I got an AdalSilentTokenAcquisitionException, and the error code is "failed_to_acquire_token_silently" then I had to redirect the user to the URL generated by the authContext (authenticationContext.GetAuthorizationRequestUrlAsync) when the cache had been cleared, no refresh token will be found, then redirect the user to resign.

Resources