5
votes

I get a 403 Forbidden response from Azure AD when trying to create an application using the Graph API:

private static void CreateApplicationViaPost(string tenantId, string clientId, string clientSecret)
{
    var authContext = new AuthenticationContext(
        string.Format("https://login.windows.net/{0}",
        tenantId));

    ClientCredential clientCred = new ClientCredential(clientId, clientSecret);

    AuthenticationResult result = authContext.AcquireToken(
        "https://graph.windows.net",
        clientCred);

    HttpClient client = new HttpClient();
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);

    const string json = @"{ displayName: ""My test app"", logoutUrl: ""http://logout.net"", identifierUris: [ ""http://identifier1.com"" ], replyUrls: [ ""http://replyUrl.net"" ] }";
    HttpResponseMessage response = client.PostAsync(
        string.Format("https://graph.windows.net/{0}/applications?api-version=1.6", tenantId),
        new StringContent(json, Encoding.UTF8, "application/json")).Result;

    Console.WriteLine(response.ToString());
}

The client registered in Azure AD has all the permissions: Permissions in Azure AD

What am I missing?

EDIT: I registered a native client in Azure AD and gave it permissions to write to Windows Azure Active Directory. This code create an application in Azure AD:

private static void CreateApplicationViaPost(string tenantId, string clientId, string redirectUri)
        {
            var authContext = new AuthenticationContext(
                string.Format("https://login.windows.net/{0}",
                tenantId));

            AuthenticationResult result = authContext.AcquireToken("https://graph.windows.net", clientId, new Uri(redirectUri), PromptBehavior.Auto);

            HttpClient client = new HttpClient();
            client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);

            const string json = @"{ displayName: ""My test app1"", homepage: ""http://homepage.com"", logoutUrl: ""http://logout1.net"", identifierUris: [ ""http://identifier11.com"" ], replyUrls: [ ""http://replyUrl1.net"" ] }";
            HttpResponseMessage response = client.PostAsync(
                string.Format("https://graph.windows.net/{0}/applications?api-version=1.6", tenantId),
                new StringContent(json, Encoding.UTF8, "application/json")).Result;

            Console.WriteLine(response.ToString());
        }
3

3 Answers

5
votes

Modifying the directory requires consent from an admin user. So you'll need to acquire an access token from an user, e.g. through OAuth, instead of a token for the client.

There are quite a few of samples at GitHub that show the authorisation flow, e.g. https://github.com/AzureADSamples/WebApp-GraphAPI-DotNet.

3
votes

Adding to @MrBrink's answer - you need to make sure the person adding the permissions in the Azure Active Directory UI is actually an administrator. If you have access to Azure Active Directory and are not an administrator it WILL still let you assign permissions - however they will only apply at a user scope.

2
votes

An alternative would be to use the ActiveDirectoryClient from the Microsoft.Azure.ActiveDirectory.GraphClient NuGet package.

private static async Task CreateApplication(string tenantId, string clientId,
    string redirectUri)
{
    var graphUri = new Uri("https://graph.windows.net");
    var serviceRoot = new Uri(graphUri, tenantId);
    var activeDirectoryClient = new ActiveDirectoryClient(serviceRoot,
        async () => AcquireTokenAsyncForUser("https://login.microsoftonline.com/" + tenantId,
            clientId, redirectUri));

    var app = new Application
        {
            Homepage = "https://localhost",
            DisplayName = "My Application",
            LogoutUrl = "https://localhost",
            IdentifierUris = new List<string> { "https://tenant.onmicrosoft.com/MyApp" },
            ReplyUrls = new List<string> { "https://localhost" }
        };

    await activeDirectoryClient.Applications.AddApplicationAsync(app);

    Console.WriteLine(app.ObjectId);
}

private static string AcquireTokenAsyncForUser(string authority, string clientId,
    string redirectUri)
{
    var authContext = new AuthenticationContext(authority, false);
    var result = authContext.AcquireToken("https://graph.windows.net",
        clientId, new Uri(redirectUri), PromptBehavior.Auto);

    return result.AccessToken;
}