0

I am receiving StatusCode: 403, ReasonPhrase: 'Forbidden' for an HTTP Post:

URL: $"https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Web/sites/{appName}/functions/{functionName}/listkeys?api-version=2022-03-01";

StatusCode: 403, ReasonPhrase: 'Forbidden'

Client:

The following is my client code:

let tenantId = "<some_tenant_id>"
let clientId = "<some_client_id>"
let secret   = "<some_secret>"
let scope    = "<some_scope>"

let token = BearerToken.Create(tenantId, clientId, secret, scope).Result

let tokenRequestBody = Dictionary<string, string>() 
tokenRequestBody.Add("grant_type"   , "client_credentials")
tokenRequestBody.Add("client_id"    , clientId)
tokenRequestBody.Add("client_secret", secret)
tokenRequestBody.Add("scope"        , scope)

let content = new FormUrlEncodedContent(tokenRequestBody);

let httpKeysClient = new HttpClient();
httpKeysClient.DefaultRequestHeaders.Authorization <- new AuthenticationHeaderValue("Bearer", token);
httpKeysClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

let subscriptionId    = "<some_scubscription_id>"
let resourceGroupName = "<some_resource_group_name>"
let appName           = "<some_function_app_name>"
let functionName      = "<some_function_name>"

let apiKeyUrl = $"https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Web/sites/{appName}/functions/{functionName}/listkeys?api-version=2022-03-01";

let response = httpKeysClient.PostAsync(apiKeyUrl, content).Result;

response.IsSuccessStatusCode |> should equal true // ** StatusCode: 403, ReasonPhrase: 'Forbidden' **

Appendix:

The code for creating an authorization token works:

public static class BearerToken
{
    public async static Task<string> Create(string tenantId, string clientId, string clientSecret, string scope)
    {
        var tokenRequestBody = new Dictionary<string, string> {

            { "grant_type"   , "client_credentials" },
            { "client_id"    , clientId },
            { "client_secret", clientSecret },
            { "scope"        , scope }
            };

        var url      = $"https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token";
        var client   = new HttpClient() { BaseAddress = new Uri(url) };
        var content  = new FormUrlEncodedContent(tokenRequestBody);
        var response = await client.PostAsync("", content);

        if (response.IsSuccessStatusCode)
        {
            var tokenResponse = await response.Content.ReadAsStringAsync();
            var valueFor      = JsonConvert.DeserializeObject<JsonSupport.AccessToken.Root>(tokenResponse);

            return valueFor.access_token;
        }

        throw new Exception(response.ReasonPhrase);
    }
}
Sridevi
  • 10,599
  • 1
  • 4
  • 17
Scott Nimrod
  • 11,206
  • 11
  • 54
  • 118
  • The actual response body might contain more information about what is wrong (likely you dont have the correct permission to list keys, hence 403 instead of 401), try to deserialize it and log it. – arynaq Jan 03 '23 at 16:21
  • Could you include what RBAC roles your service principal/application have? – Sridevi Jan 03 '23 at 16:28
  • @Sridevi - The role for my service principal is listed as 'Reader' – Scott Nimrod Jan 03 '23 at 17:16
  • 1
    'Reader' role is not sufficient to do POST operations. Try assigning 'Contributor' role to it. – Sridevi Jan 03 '23 at 17:18
  • @arynaq - I didn't see any additional details. However, the principal's role is set to reader. – Scott Nimrod Jan 03 '23 at 17:19
  • @Sridevi - Under Active Directory | Roles and Administrators, it's not clear to me how to assign the principal a contributor role. Thoughts? – Scott Nimrod Jan 03 '23 at 17:29
  • You need to assign 'Contributor' role under subscription, not under Azure Active directory. – Sridevi Jan 03 '23 at 17:34
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/250814/discussion-between-sridevi-and-scott-nimrod). – Sridevi Jan 03 '23 at 17:38

1 Answers1

1

I tried to reproduce the same in my environment via Postman and got below results

I have one service principal having Reader role under my subscription like below:

enter image description here

Now I generated access token using client credentials flow with below parameters:

POST https://login.microsoftonline.com/<tenantID>/oauth2/v2.0/token

grant_type:client_credentials
client_id: <appID>
client_secret: <secret_value>
scope: https://management.azure.com/.default

Response:

enter image description here

When I used the above token to list keys, I got 403 Forbidden error like below:

POST https://management.azure.com/subscriptions/<subID>/resourceGroups/Sri/providers/Microsoft.Web/sites/<name>/functions/<functionname>/listkeys?api-version=2022-03-01
Authorization: Bearer <token>

Response:

enter image description here

To resolve the error, I assigned Contributor role to that service principal like below:

Go to Azure Portal -> Subscriptions -> Your Subscription -> Access control (IAM) -> Add role assignment

enter image description here

After assigning that role, I generated access token again and got the results successfully when I used that in below query:

POST https://management.azure.com/subscriptions/<subID>/resourceGroups/Sri/providers/Microsoft.Web/sites/<name>/functions/<functionname>/listkeys?api-version=2022-03-01
Authorization: Bearer <token>

Response:

enter image description here

In your case, make sure to assign Contributor role to your service principal that resolves the issue.

Sridevi
  • 10,599
  • 1
  • 4
  • 17
  • Not sure if there's a similar approach to this question as well: https://stackoverflow.com/questions/75190389/unable-to-access-a-pulumi-created-azure-storage-table-access-forbidden-403 – Scott Nimrod Jan 21 '23 at 00:26