Quantcast
Channel: damienbod – Software Engineering
Viewing all articles
Browse latest Browse all 357

Microsoft Entra ID App-to-App security architecture

$
0
0

This article looks at the different setups when using App-to-App security with Microsoft Entra ID (OAuth client credentials). Microsoft Entra App registrations are used to configure the OAuth clients and resources. For each tenant, an Enterprise application is created for the client App registration when the consent is granted. The claims in the access token are validated as much as possible to prevent unauthorized clients from using the resource.

Code: https://github.com/damienbod/GrpcAzureAppServiceAppAuth

Use a single ME-ID App registration for client and resource

A single Microsoft Entra ID App registration can be used for both the client and the resource specification. The aud and the azp claims in the access token will have the same value in this setup. The roles claims are of no benefit. This could be considered a bad architecture because the ME-ID App registration is used for two separate intentions, the client requesting the access token and the resource providing the service. Deployment is simplified as only one App registration is required. The setup cannot be used for multiple clients.

The access token created for this setup will have the same value for the aud claim and the azp claim as the client and the resource are the same. Both of the claims should be validated to prevent other clients accessing the resource.

{
  "aud": "19893e32-3f4d-4c5a-b5ca-27891cf75666",
  "iss": "https://login.microsoftonline.com/7ff95b15-dc21-4ba6-bc92-824856578fc1/v2.0",
  "iat": 1727688828,
  "nbf": 1727688828,
  "exp": 1727692728,
  "aio": "k2BgYDD6x3jLSW9uSapm1it3vtdnC66c40v83qzsVLhQga//6EsA",
  "azp": "19893e32-3f4d-4c5a-b5ca-27891cf75666",
  "azpacr": "1",
  "oid": "a517247c-86ba-43d9-8e02-7cf7918c15f4",
  "rh": "0.AR8AFVv5fyHcpku8koJIVlePwTI-iRlNP1pMtconiRz3VmaFAAA.",
  "roles": [
    "access_as_app"
  ],
  "sub": "a517247c-86ba-43d9-8e02-7cf7918c15f4",
  "tid": "7ff95b15-dc21-4ba6-bc92-824856578fc1",
  "uti": "DBleEOFcqk-rcld809IQAA",
  "ver": "2.0"
}

In the Azure portal, the Microsoft Entra ID App registration is configured to add an application App Role. This role is returned in the access token as shown above.. It is not required in this setup.

The access token can be validated using Microsoft.Identity.Web in a Web API.

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("ValidateAccessTokenPolicy", validateAccessTokenPolicy =>
    {
        // Validate id of application for which the token was created
        // In this case the CC client application 
        validateAccessTokenPolicy.RequireClaim("azp", "19893e32-3f4d-4c5a-b5ca-27891cf75666");

        // only allow tokens which used "Private key JWT Client authentication"
        // // https://docs.microsoft.com/en-us/azure/active-directory/develop/access-tokens
        // Indicates how the client was authenticated. For a public client, the value is "0". 
        // If client ID and client secret are used, the value is "1". 
        // If a client certificate was used for authentication, the value is "2".
        validateAccessTokenPolicy.RequireClaim("azpacr", "1");
    });
});

Use separate ME-ID App registrations for client and resource

This architecture allows for separation of clients and is required if more than one client can use the resource. The different clients can be identified in the application using the azp claim or the oid claim. The aud claim has the resource value and must be validated. The separate clients allows you to distribute different client certificates or secrets for each client. Audit logs can also be per client. The application can also implement separate business logic or authorization based on the client_id, object ID. (azp or oid)

The aud claim returns the resource App registration client_id and the azp returns the client App registration client_id. As two App registrations are used, the claims have different values. The roles claim is also returned in the access token. The roles permission is required to setup the client and resource relationship in the portal, but not required for authorization, if the other claims are validated correctly. It must be validated that only the allowed client acquired the access token for the resource and not any application access token from the same tenant.

{
  "aud": "1a03257f-18a2-4cfa-81c1-d3cfaba6b09e",
  "iss": "https://login.microsoftonline.com/7ff95b15-dc21-4ba6-bc92-824856578fc1/v2.0",
  "iat": 1727685006,
  "nbf": 1727685006,
  "exp": 1727688906,
  "aio": "k2BgYFCeXa1fbNX34Odf08MOyzuu8k5eIO5xfYJi0rL41gkxx9QB",
  "azp": "912584f0-442c-41e3-87b3-3232edd82940",
  "azpacr": "1",
  "oid": "eb11b352-b9cc-489b-9e50-5eae9ee92e09",
  "rh": "0.AR8AFVv5fyHcpku8koJIVlePwX8lAxqiGPpMgcHTz6umsJ6FAAA.",
  "roles": [
    "SharedAppRoleForAppToAppClients"
  ],
  "sub": "eb11b352-b9cc-489b-9e50-5eae9ee92e09",
  "tid": "7ff95b15-dc21-4ba6-bc92-824856578fc1",
  "uti": "Poa-FXigHkWg2mrtySMPAA",
  "ver": "2.0"
}

Claim values returned in the access token:

aud

This MUST be validated and has the client_id from the resource ME-ID App registration.

roles: SharedAppRoleForAppToAppClients

This can be used to validate the access token, if multiple clients can be used to access the resource. This is not required, if the aud is validated. When using OAuth client credentials and an App-to-App client (no delegated user), the default scope is used to access the resource and all roles from the App registration are included in the access token.

azp

The azp can be used to lock down the resource to intended clients. This is different for each client. If you validate this, only the allowed clients can use the resource.

tid

The tid claim can be used to validate the tenant which requested the resource. It is important to validate this when using multi-tenant App registrations, if the resource is not for “All” Microsoft tenants. Only allow the tenants intended for the resource.

oid

The oid claim is the Microsoft Entra ID Enterprise application object ID created for the client App registration. If you are using only a single client and validate the OID, then you can prevent other Enterprise applications using the resource.

Application implementation in ASP.NET Core

The resource can be implemented using Microsoft.Identity.Web, if it is an ASP.NET Core Web API application.

// Add services to the container.
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("ValidateAccessTokenPolicy", validateAccessTokenPolicy =>
    {
        // Validate id of application for which the token was created
        // In this case the CC client application 
        // Works with multi-tenant App registrations
        validateAccessTokenPolicy.RequireClaim("azp", builder.Configuration["AzureAd:ClientId"]!);

        // Value of Azure App registration where role is defined (resource)
        validateAccessTokenPolicy.RequireClaim("aud", builder.Configuration["AzureAd:Audience"]!);

        // Single tenant Enterprise application object ID
        // Only validate if locking down to a single Enterprise application.
        validateAccessTokenPolicy.RequireClaim("oid", builder.Configuration["AzureAd:Oid"]!);

        // only allow tokens which used "Private key JWT Client authentication"
        // https://docs.microsoft.com/en-us/azure/active-directory/develop/access-tokens
        // Indicates how the client was authenticated. For a public client, the value is "0". 
        // If client ID and client secret are used, the value is "1". 
        // If a client certificate was used for authentication, the value is "2".
        validateAccessTokenPolicy.RequireClaim("azpacr", "1");
    });
});

The application configuration would look like this with your tenant ids.

  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "Domain": "damienbodhotmail.onmicrosoft.com",
    "TenantId": "7ff95b15-dc21-4ba6-bc92-824856578fc1",
    "ClientId": "912584f0-442c-41e3-87b3-3232edd82940",
    // aud claim in the access token, Azure App registration client ID
    "Audience": "1a03257f-18a2-4cfa-81c1-d3cfaba6b09e",
    "Oid": "eb11b352-b9cc-489b-9e50-5eae9ee92e09"
  },

Is the App Role required?

In no setup, is the App role required in the application implementation as the aud claim can be used to validate the resource. As the default scope is used, all roles in the resource App registration are included in the access token.

The role is required to add a permission in the client ME-ID App registration for a separate App registration resource specification. The role is required in the Microsoft Entra ID portal, if you have different clients App registrations and resources App registrations.

Multi client, Multiple resources

In more complex architectures, the solution might have multiple services. A single client can used multiple resources.

The Azure App roles are required to assign the resources to the clients. The application requesting the access token for the resource must specify the default scope of the Microsoft Entra App registration resource. This means that in Microsoft Entra ID, a separate access token is used for each resource. A client can request an access token for any resource where the role has been assigned. In the resource implementation, i.e. the API access token validation, the App roles can be used to authorize the request. The aud claim can also be used and the roles are not required.

Notes

If you are using multiple clients, separate the client and the resource specifications. If you only have a single client for an API, then you can just deploy the single Azure App registration for both client and resource. If you are a purist and require that the App registrations match the implementations and are architectural correct, use only one App registration for each application, one the client and one for the resource. If requirements are changed, you can always split this later without complication. Less is more.

Links

https://github.com/AzureAD/microsoft-identity-web/wiki

https://learn.microsoft.com/en-us/entra/identity-platform/


Viewing all articles
Browse latest Browse all 357

Trending Articles