Microsoft Graph to access and modify application object in Azure AD - microsoft-graph-api

I would like to know if it is possible to use Microsoft Graph instead of Azure AD Graph APIs to create and modify Application objects in AAD.
In particular I'm interested in updating permissions to the newly created app. Currently I'm using the following powershell script to add a permission to the app object
$url = "https://graph.windows.net/$tentant_id/applications/$($ad_app.ObjectID)?api-version=1.6"
$postData = "{`"requiredResourceAccess`":[{`"resourceAppId`":`"00000002-0000-0000-c000-000000000000`",`"resourceAccess`":[{`"id`":`"311a71cc-e848-46a1-bdf8-97ff7156d8e6`",`"type`":`"Scope`"}]}]}"
$result = Invoke-RestMethod -Uri $url -Method "PATCH" -Headers $authHeader -Body $postData
How do I achieve the same with "https://graph.microsoft.com" endpoint?

The beta endpoint has the application resource type with which you can create new applications, and modify them.

Related

Listing PrincipleIDs eligible for Global Admin role with Graph API

I know that this will give me active role assignments
$uri = "https://graph.microsoft.com/v1.0/directoryRoles/62e90394-69f5-4237-9190-012177145e10/members"
$Role = Invoke-RestMethod -Uri $Uri -Headers $Header -Method get -ContentType "application/json"
$Role.value.displayname
but how do I get eligible role assignments? the only thing I can find is requests to PIM-up but nothing that shows me what users have the ability to PIM-up for a specific role.
Here is the API to get the List the directory roles that are activated in the tenant
GET https://graph.microsoft.com/v1.0/directoryRoles
This operation only returns roles that have been activated. A role becomes activated when an admin activates the role using the Activate directoryRole API. Not all built-in roles are initially activated.
When assigning a role using the Azure portal, the role activation step is implicitly done on the admin's behalf. To get the full list of roles that are available in Azure AD, use List directoryRoleTemplates.
For more information: https://learn.microsoft.com/en-us/graph/api/directoryrole-list?view=graph-rest-1.0&tabs=http#example
Graph API has Privileged Identity Management API. I'm not familiar with this API but you can retrieve the requests for role eligibilities for principals:
https://learn.microsoft.com/en-us/graph/api/rbacapplication-list-roleeligibilityschedulerequests?view=graph-rest-1.0&tabs=http
Documentation
Privileged Identity Management

401 on OData call to D365FO

I'm trying to make an OData call to retrieve a D365FO data entity.
https://[root_URL]/data/CostGroups
When logged into D365FO in my browser, this call works.
I'm working in PHP.
I've registered my app in Azure Active Directory.
I've provided my app the https://erp.dynamics.com/Connector.FullAccess API permission.
I've registered my app in D365FO with a user that has admin privileges (the same user used for the successful browser call).
I am able to acquire an authentication token.
Its "aud" field is "https://erp.dynamics.com"
Its "appid" field matches that of the app's Azure AD registration
Its "roles" field includes only "Connector.FullAccess"
I'm using curl in PHP to make the OData GET request. I use the URL listed above and my headers are
curl_setopt($curl, CURLOPT_HTTPHEADER, [
'Accept: application/json',
'OData-MaxVersion: 4.0',
'OData-Version: 4.0',
'Authorization: Bearer ' . $this->accessToken
]);
Response is "401 Unauthorized"
Does anyone know what's going wrong or how I can find more information about the failure? Is there anywhere in D365FO I can look for logs of my attempts?
The resource seems to be incorrect. It should be the base URL of the instance without the trailing '/'.
Your "aud" field is https://erp.dynamics.com. In this case, it should be your [root URL]. Like this:
Check your resource when you post a request to https://login.microsoftonline.com/[tenant ID]/oauth2/token.

microsoft graph rest api beta: application created by api in azure ad b2c is not valid

i'm trying to create ad application using beta api by following this document:
https://learn.microsoft.com/en-us/graph/api/application-post-applications?view=graph-rest-beta&tabs=http
the application can be successfully created in Azure AD B2C (not Azure Active Directory) as expected. the issue is when i'm trying to open this app from portal, the page just keeps loading while the app information never shows. i can see there's an error from browser dev tool:
The following request returns 404 error:
https://main.b2cadmin.ext.azure.com/api/ApplicationV2/GetApplication?tenantId=mytestb2ctenant.onmicrosoft.com&applicationId=560df329-47f5-497b-a1d3-08e9e8208062
I can verify the applicationId is indeed the appid of my newly created ad app. not sure why getting the notfound error.
Then I manually created another app in my b2c ad. I compared the returned schema from get-application rest api for these two apps. the only difference is the manually created one has a default user_impersonation api scope, while other one does not. maybe this causes the error.
here's my complete powershell script to created ad app:
$b2cDomain = "mytestb2ctenant.onmicrosoft.com"
$applications = "https://graph.microsoft.com/beta/applications"
$headers = #{
"Authorization" = $accessToken;
}
#app = "mytestapp"
$request = #{
displayName = $app
identifierUris = #("https://$b2cDomain/api")
signInAudience = "AzureADandPersonalMicrosoftAccount"
web = #{
redirectUris = #("https://any.valid.url")
implicitGrantSettings = #{
enableIdTokenIssuance = $false
enableAccessTokenIssuance = $true
}
}
isFallbackPublicClient= $false
}
$body = $request | ConvertTo-Json
Log "creating ad app: $app"
$appResponse = Invoke-RestMethod `
-Uri $applications `
-Method Post `
-Headers $headers `
-ContentType "application/json" `
-Body $body
did I miss anything for the request schema? how can i create a valid app from rest api just like i manually create it?
guess i found the root.
the application created from api did not have a service principle associated. need to create a sp for it. i could not find the rest api for creating sp from here. ended up using AzueAD powershell commands:
Connect-AzureAD -Credential $credential -TenantId $b2cTenantId
New-AzureADApplication -DisplayName "myapp"
$app = Get-AzureADApplication -SearchString "myapp"
New-AzureADServicePrincipal -AppId $app.AppId
everything seems working now.
btw, the Application in Azure AD B2C and in Azure Active Directory should be the same thing only showing different places. i got confused before.
Please remember not to use Microsoft Graph beta apis in production since they are subject to change.
For an application to successfully work in AAD B2C(get a token), it has following requirements
A service principal
Consent to openid and offline_access scope on
Microsoft Graph service principal in the tenant
The service principal apis are in Beta right now. The OAuth2Permissions api are in beta as well.
The algorithm is
Create an app using application api
Create a Service principal for it (lets call it clientSP).
Find service principal corresponding to Microsoft Graph app (AppId # 00000003-0000-0000-c000-000000000000) in tenant using service principal apis. This service principal is always created by Azure AD in the directory so you just need to search for it. Lets call is ResourceSP
Use OAUTH2Permissions api to create and grant consent to clientSP on ResourceSP for openid and offline_access scopes.
The sample here should help - https://github.com/valnav/Azure-AD-B2C-App-Graph.

How do I authenticate against the Dynamics 365 Data Export Service API?

I've set up something called the Data Export Service for Dynamics 365 so that it replicates into an Azure SQL database. This is working as expected.
I'm trying to find a way to be proactively notified if this service encounters any errors. There does not appear to be a native way to do this through the setup in CRM itself, but they do provide an API. The Swagger page outlining all methods can be found here.
I'm trying to call the GetProfilesByOrganizationId method using Postman:
https://discovery.crmreplication.azure.net/crm/exporter/profiles?organizationId=4ef7XXXX-XXXX-XXXX-XXXX-XXXXXX8a98f&status=true
I'm having issues with authentication and always receive the following error:
"Message": "Received unauthenticated requestRequest Url https://discovery.crmreplication.azure.net/crm/exporter/profiles?organizationId=4ef7XXXX-XXXX-XXXX-XXXX-XXXXXX8a98f&status=true"
I have registered an application in Azure that has permission to access Dynamics 365 on behalf of the authenticated user which in this case is me, the administrator.
I have set the Type to OAuth 2.0 on the Authorization tab of Postman. I have requested an Access Token using the Grant Type of Authorization Code against the above application successfully. This has added a header to the request:
Key: Authorization
Value: Bearer BIGLONGACCESSTOKEN
Despite this header being present I still get the error mentioned above.
The API documentation implies the authentication is OAuth2 Implicit Grant Flow (click on any red exclamation mark in the documentation) but I can't get this to work in Postman. When I try to request a token with this method I get the error:
unsupported_response_type
... in the Postman console.
Any ideas how to authenticate (with Implicit Grant?) against this API in Postman?
(I'd accept C# examples if they're more appropriate, but I'd be surprised if Postman can't show me what I need)
It looks like the code sample shown by Microsoft can work if updated with newer methods and with some extra configuration in Azure that's not documented.
Azure configuration
By installing the Data Export service (and assuming it's all working) you'll have a new Enterprise Application listed in Azure AD as Crm Exporter.
To take advantage of this application and authenticate with the Data Export API you must configure an app of your own.
Go to the App registrations tab in Azure AD and add a new application registration.
Give it a name and set the Application type to Native. The redirect URI doesn't typically matter as long as it's valid.
Click the Manifest button to edit the manifest, change the property oauth2AllowImplicitFlow to true and save the changes.
The only other important configuration is Required permissions which should be set as below:
Windows Azure Active Directory
Delegated permissions
Sign in and read user profile
Data Export Service for Microsoft Dynamics 365 (Crm Exporter)
Delegated permissions
Have access to Data Export Service for Microsoft Dynamics 365 API
You will then need to click Grant Permissions.
C# changes
The updated method looks like this:
using Microsoft.IdentityModel.Clients.ActiveDirectory;
string clientId = "11cfXXXX-XXXX-XXXX-XXXX-XXXXXXXXd020";
string user = "my.username#domain.com";
string password = "PASSWORD";
var authParam= await AuthenticationParameters.CreateFromResourceUrlAsync(
new Uri("https://discovery.crmreplication.azure.net/crm/exporter/aad/challenge")
);
var context = new AuthenticationContext(authParam.Authority, false);
var credentials = new UserPasswordCredential(user, password);
var token = await context.AcquireTokenAsync(authParam.Resource, clientId, credentials).AccessToken;
You can now query the Data Export API by providing the token as a header:
Authorization : Bearer eJ0y........Hgzk
curl -X GET --header 'Accept: application/json' 'https://discovery.crmreplication.azure.net/crm/exporter/profiles?organizationId=MyOrgId&status=true'

Microsoft Graph API returning 403 to any request

I'm working on an application that, in this point, will retrieve the Office Groups that the logged in user is included and perform actions based on that info.
I'm using oAuth2.0 and the v2.0 token endpoint to get access without a user, and with the code below, I can provide administrator consent to the permissions (which were applied to the application permissions on the new Application Registration Portal https://apps.dev.microsoft.com/ and appear on the Enterprise Applications section on Azure), request the token to Azure and receive it, but even with the permissions applied and that token, I get a 403 response code (Insufficient privileges) from the Graph API to any request I try to perform.
The code for those actions is the following:
// Request Admin Consent
HttpRequestMessage adminConsentRequest = new HttpRequestMessage(HttpMethod.Get, "https://login.microsoftonline.com/" + TenantId + "/adminconsent?client_id="+ClientId+"&redirect_uri=https%3A%2F%2Flocalhost%3A44369%2FHome%2F");
var adminConsentResponse = await client.SendAsync(adminConsentRequest);
// Request Token
HttpRequestMessage tokenRequest = new HttpRequestMessage(HttpMethod.Post, "https://login.microsoftonline.com/"+TenantId+"/oauth2/v2.0/token") { Content = new FormUrlEncodedContent(tokenRequestPairs) };
var tokenResponse = await client.SendAsync(tokenRequest);
string tokenResponseBody = await tokenResponse.Content.ReadAsStringAsync();
var deserializedTokenResponse = (JObject)JsonConvert.DeserializeObject(tokenResponseBody);
string accessToken = deserializedTokenResponse["access_token"].Value<string>();
// Call Microsoft Graph API
HttpRequestMessage graphRequest = new HttpRequestMessage(HttpMethod.Get, "https://graph.microsoft.com/v1.0/me/memberOf");
graphRequest.Headers.Add("Authorization", "Bearer "+accessToken);
var graphResponse = await client.SendAsync(graphRequest);
string graphResponseBody = await graphResponse.Content.ReadAsStringAsync();
var deserializedGraphResponse = (JObject)JsonConvert.DeserializeObject(graphResponseBody);
Enterprise Application permissions on Azure
APP Registration Portal permissions
Can someone guide to any kind of mistake I'm making?
With the authorization token and the permissions applied, I can't see why would I get an AccessDenied response.
It's been more than 48 hours since I applied the permissions, so it's not a sync problem.
Update: So thanks to #juunas I managed to reapply the permissions and the token now shows all the permissions applied on the Application Portal (User.Read.All, Directory.Read.All and Group.Read.All), but the API still returns 403 status code (Authorization_RequestDenied).
I've tried another endpoint without the /me just to make sure that is not a reference problem, but it also returns 403 status code.
One thing that is funny is that the App was registered on the new app portal as I said, and it appears on Enterprise Applications on Azure, but not on my App Registrations, so I can only alter permissions on the new App Portal. It should be like this, since I'm using a new registration portal?
After a discussion in the comments, the problem was fixed by re-consenting the permissions similarly as shown in my blog post: https://joonasw.net/view/the-grant-requires-admin-permission (though it is written for v1).
To run admin consent again, you need to add prompt=admin_consent to the authorize URL.
Okay, so a few minutes after the update on the original post, the token was accepted by the endpoints.
The only problem is that the graph API does not recognize the ID of the user logged in to use the /me endpoints, but I bypassed that using the /{group-id}/members endpoint (in my case, it's not how I wanted but solves my problem).
Thanks #juunas for the help!

Resources