Background App Needs Access? Use Client Credentials Flow

Published on:

In enterprise systems, backend applications often communicate without user interaction.

This pattern is used when:

  • no user is present
  • systems call APIs directly
  • authentication is handled by Microsoft Entra ID

In this example:

  • Dynamics 365 (D365) is the caller application
  • Middleware API is the resource application

Authentication is done with OAuth 2.0 Client Credentials Flow. Authorization is controlled with App Roles.

Create Middleware API App

First, create the resource application.

Go to:

Entra ID > App registrations > New registration

Create an application:

Name: Middleware-API

This app registration represents the API that will receive and validate access tokens.

Microsoft Entra app registration creation screen showing Middleware-API being created

Expose API

Inside Middleware-API, open:

Expose an API

Set the Application ID URI:

api://<application-id>

Keep the Azure-generated format unchanged unless you have a clear naming standard for your tenant.

This identifier becomes the audience for tokens issued to the Middleware API.

Microsoft Entra Middleware API app registration showing Expose an API and Application ID URI configuration

Create App Role

Inside Middleware-API, create an application role:

App roles > Create role

Example:

Name: Middleware.Access
Value: middleware.access
Allowed member types: Applications

This defines application-level authorization. It is not user-based access.

The Middleware API can later check whether the incoming token contains the required role.

Microsoft Entra App Role creation screen showing Middleware.Access configured for application permissions

Create D365 Client App and Secret

Now create the caller application.

Go to:

Entra ID > App registrations > New registration

Create an application:

Name: D365-Integration-App

Then create a client secret:

Certificates & secrets > New client secret

Store the secret value securely. It is required when the client application authenticates against Entra ID.

In real projects, prefer managed identities or certificate-based credentials where possible. If a client secret is used, rotate it regularly and never store it in source control.

Microsoft Entra D365 app registration showing client secret creation screen

Assign App Role via API Permissions

Go to:

App registrations > D365-Integration-App > API permissions

Then select:

Add a permission

Choose:

My APIs > Middleware-API > Application permissions > Middleware.Access

Then click:

Grant admin consent

This grants the D365 client application permission to request tokens for the Middleware API with the middleware.access app role.

After admin consent is granted, Entra ID can issue application tokens that contain this role.

Microsoft Entra API Permissions tab showing Middleware API app role and Grant admin consent button

Client Credentials Flow at Runtime

At runtime, D365 requests a token from Entra ID:

POST https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/token

Request body:

client_id=D365_CLIENT_ID
client_secret=SECRET
grant_type=client_credentials
scope=api://<application-id>/.default

The .default scope tells Entra ID to issue a token containing the application permissions already granted to the client app.

Token Result

The access token contains:

  • app role: middleware.access
  • audience: Middleware API
  • no user identity

That last point matters: this is an application token, not a delegated user token.

Enterprise Note

Real enterprise environments usually have multiple stages:

  • DEV
  • TEST or STAGE
  • PROD

If these environments are separated into different Azure subscriptions within the same Entra ID tenant, best practice is to create separate App Registrations per environment.

Example:

D365-Integration-App-DEV
D365-Integration-App-TEST
D365-Integration-App-PROD

Middleware-API-DEV
Middleware-API-TEST
Middleware-API-PROD

This provides:

  • isolation of secrets and credentials
  • safer production boundaries
  • independent deployments
  • no cross-environment token reuse
  • clearer auditing and troubleshooting