Azure APIs to Windows-Authenticated Services
Modern Azure applications commonly use Microsoft Entra ID to obtain OAuth 2.0 access tokens for calling APIs, while older on-premises applications may expect Kerberos or NTLM.
Bridging the two isn't simply a networking problem. Even after Azure can reach the on-premises service over VPN or ExpressRoute, the caller still needs an identity that the legacy service understands.
About this article
This is my personal blog content, not a Quorum case study. It grew out of a question a client posed to us during discussions about prospective work involving proxying between cloud and on-premises services. It documents the analysis we carried out before proposing a solution that was subsequently implemented successfully for that client. The patterns and recommendations described here do not necessarily represent the specific solution delivered to them.
A typical scenario looks like this:
flowchart TB
subgraph Cloud["Azure"]
Workload["Modern workload"]
Gateway["API Management"]
Workload -->|"HTTPS + access token"| Gateway
end
subgraph OnPremises["On-premises"]
Bridge["Authentication boundary<br/>to design"]
Backend["Legacy API"]
Bridge -->|"Kerberos or NTLM"| Backend
end
Gateway -->|"VPN or ExpressRoute"| Bridge The key question is:
Whose Windows identity does the legacy application actually need?
Service identity or user identity?¶
For many machine-to-machine integrations, the backend doesn't need to know which individual user initiated the request. It only needs to know that the request came from an authorised application.
In this case, an intermediary can call the legacy API using a dedicated Active Directory service identity:
flowchart TB
Application["Modern application"] -->|"Access token"| Gateway["API Management"]
Gateway -->|"HTTPS + mTLS"| Facade["Windows facade"]
Facade -->|"Kerberos as DOMAIN/service-account"| Backend["Legacy API"]
Backend --> Permissions["Service-account permissions<br/>not end-user permissions"] This is usually much simpler than trying to propagate the user's identity through the entire chain.
If the legacy application performs authorisation as the original user, however, a service identity isn't equivalent. That's where Kerberos delegation may be required.
Why can't API Management translate the identity?¶
An OAuth access token and a Kerberos ticket are fundamentally different credentials.
A Microsoft Entra access token contains claims about an identity and is issued for a particular audience. A Kerberos service ticket is issued by Active Directory for a particular service, identified through a Service Principal Name (SPN).
API Management doesn't provide a built-in OAuth-to-Kerberos token-conversion policy. A deliberately configured intermediary can bridge the two security models, but that requires its own identity, trust configuration and, for user impersonation, identity mapping and delegation permissions.
This distinction also matters when considering the Azure API Management self-hosted gateway. Running the gateway on-premises can bring API policy enforcement closer to the backend, but it doesn't automatically give the gateway a Windows identity or enable it to impersonate a user.
Option 1: Modernise the backend¶
The cleanest solution is to make the legacy API accept modern authentication directly:
flowchart TB
Application["Application"] -->|"Access token"| Gateway["API Management"]
Gateway -->|"Token valid for the backend"| Backend["Modernised backend API"]
Gateway -.-> GatewayChecks["Validate caller<br/>and authorise operation"]
Backend -.-> BackendChecks["Validate backend audience<br/>and permissions"] This removes the authentication-translation problem and allows modern application or managed identities to be used end to end.
That doesn't necessarily mean forwarding the same token through every hop. Each receiving API must validate the intended audience and permissions. Depending on the design, API Management can forward a suitable caller token or obtain a backend token using its own identity; those choices produce different authorisation contexts.
Unfortunately, these integration problems often exist precisely because upgrading or modifying the legacy application isn't practical.
Option 2: Introduce a small Windows facade¶
For service-to-service integration, a pragmatic alternative is a small Windows-hosted facade:
---
config:
sequence:
useMaxWidth: false
---
sequenceDiagram
autonumber
participant Workload as Azure workload
participant Gateway as API Management
participant Facade as Windows facade
participant Backend as Legacy API
Workload->>Gateway: HTTPS request<br/>+ access token
Gateway->>Gateway: Validate token<br/>and authorise operation
Gateway->>Facade: HTTPS request<br/>using client certificate
Facade->>Facade: Validate certificate identity<br/>and permitted operation
Facade->>Backend: Request with service identity's<br/>Kerberos ticket
Backend-->>Facade: Response under<br/>service-account permissions
Facade-->>Gateway: Response
Gateway-->>Workload: Response The facade provides a deliberate boundary between the modern and legacy security models.
It can:
- expose a small modern API;
- accept calls only from the trusted API layer;
- run under a dedicated, least-privilege domain identity;
- authenticate to the legacy service using Kerberos;
- translate between modern and legacy API contracts; and
- provide logging and auditing around the transition.
Keep authentication and authorisation separate¶
mTLS authenticates the connecting API layer to the facade. It doesn't establish the original user's Windows identity, and it doesn't prove that every caller admitted by API Management may perform every backend operation.
For this pattern to be safe:
- API Management must validate the access token's signature, issuer, audience and lifetime, then enforce the required application roles or delegated scopes for each operation.
- The facade must validate the authorised client-certificate identity, not merely accept any certificate from a trusted issuer. Validate the server certificate on the APIM-to-facade connection too; don't disable TLS checks to make the connection work.
- Restrict network access to the intended API layer and close alternative routes that could bypass those checks. Private connectivity alone isn't authentication.
- Expose a narrow set of operations and fixed backend destinations, rather than a general-purpose proxy that can use the service identity against arbitrary URLs.
- Give the domain service identity only the backend permissions it needs. Where supported, consider a group Managed Service Account (gMSA), and protect any credentials the design still requires.
- Plan certificate rotation and expiry monitoring. Log the verified modern caller and the effective Windows identity for correlation, without logging access tokens, tickets or credentials.
Microsoft describes the separation between caller validation and backend authentication in its API Management authentication and authorisation guidance.
The important architectural benefit is that the legacy authentication mechanism doesn't leak into the modern application.
The facade can eventually be removed when the legacy system is modernised or replaced.
What if the backend supports only NTLM?¶
The Kerberos examples in this article assume the backend actually supports Kerberos. Integrated Windows Authentication and the Negotiate scheme shouldn't be treated as proof that Kerberos was used: negotiation can fall back to NTLM.
An NTLM-only backend needs separate assessment. A Windows facade may be able to authenticate using its own service identity if its HTTP client and the backend support NTLM, but this isn't the Kerberos flow shown above. NTLM also has connection-oriented authentication behaviour that affects proxying and connection reuse.
KCD obtains Kerberos tickets for the backend; it doesn't turn an NTLM-only backend into a Kerberos service or automatically preserve the original user's identity through NTLM. Prefer enabling Kerberos or modernising authentication where possible, and verify the protocol actually negotiated rather than relying on a successful response alone.
Option 3: Use Kerberos Constrained Delegation¶
Things become more complicated if the backend genuinely needs the original user's Windows identity.
Kerberos Constrained Delegation allows a trusted service to act on behalf of a user when accessing explicitly permitted backend services.
Conceptually:
---
config:
sequence:
useMaxWidth: false
---
sequenceDiagram
autonumber
participant Client as User / client
participant Bridge as Trusted Windows intermediary
participant Directory as Active Directory
participant Backend as Legacy API
Client->>Bridge: HTTPS request<br/>with modern credentials
Bridge->>Bridge: Validate and authorise caller<br/>then map to AD user
Bridge->>Directory: Configured protocol transition<br/>and constrained delegation
Directory-->>Bridge: User's ticket for<br/>permitted backend SPN
Bridge->>Backend: Request with user's<br/>Kerberos service ticket
Backend->>Backend: Apply user-level<br/>authorisation
Backend-->>Bridge: Response
Bridge-->>Client: Response This is a conceptual flow, not an automatic token exchange. When the incoming authentication isn't Kerberos, the intermediary needs a supported protocol-transition design, commonly using the Kerberos Service for User (S4U) extensions, as well as permission to delegate to the specific backend service.
The design also needs:
- a securely validated modern identity mapped to the correct user account in on-premises Active Directory; an Entra-only account without a corresponding AD identity isn't enough;
- a domain identity for the intermediary, appropriate domain trust and connectivity to domain controllers;
- correct backend SPNs and narrowly scoped classic or resource-based constrained delegation, as appropriate to the environment;
- confirmation that the relevant user accounts are eligible for delegation; protected accounts or accounts marked as non-delegable can prevent the flow; and
- a Kerberos-capable backend that applies authorisation to the delegated user.
Never let an untrusted request header choose an arbitrary Windows username for impersonation. The identity used for delegation must come from the validated authentication context and an explicitly controlled mapping.
Microsoft's Application Proxy KCD configuration guidance provides a concrete example of these prerequisites and the cloud-to-AD identity mapping.
This can preserve user-level authorisation, but it introduces additional complexity around:
- SPNs;
- service identities;
- delegation permissions;
- Active Directory domains;
- DNS; and
- the trust placed in the intermediary.
It's therefore worth asking whether the legacy application really needs the user's Windows identity before introducing delegation.
Don't forget SPNs¶
Kerberos identifies network services using Service Principal Names.
For an HTTP API, an SPN might look like this:
HTTP/api.internal.example
The hostname used by the client, the DNS configuration, the SPN and the account running the service all need to agree.
Some useful diagnostic commands are:
setspn.exe -Q HTTP/api.internal.example
setspn.exe -L DOMAIN\ServiceAccount
Incorrect or duplicate SPNs are a common cause of Kerberos authentication failures. They can also result in unexpected NTLM fallback, which may make the integration appear to work while preventing delegation.
What about Microsoft Entra Application Proxy?¶
For interactive access to an on-premises web application, Microsoft Entra Application Proxy is worth considering.
It can authenticate a user with Microsoft Entra ID and use Kerberos Constrained Delegation through an on-premises private network connector to provide single sign-on to an application that uses Integrated Windows Authentication and supports Kerberos.
The connector needs the appropriate AD delegation permissions, backend SPN and user identity mapping. This is a supported authentication bridge with specific prerequisites, not a feature obtained merely by placing a proxy on the network.
It's less obviously the answer for machine-to-machine API integration, where API Management and a narrowly scoped facade may provide a clearer separation of responsibilities. Assess the supported client and authentication flow rather than assuming an interactive SSO design also covers app-only access.
My preferred pattern¶
For a machine-to-machine integration where the backend doesn't genuinely require end-user impersonation, I'd favour:
flowchart TB
subgraph Azure["Azure: modern caller identity"]
Workload["Azure workload<br/>Managed or application identity"]
Gateway["API Management<br/>Token validation + operation authorisation"]
Workload -->|"HTTPS + access token"| Gateway
end
subgraph OnPremises["On-premises: Windows service identity"]
Facade["Windows facade<br/>Authorised client certificate + narrow API"]
Backend["Legacy API<br/>Least-privilege service-account permissions"]
Facade -->|"Kerberos service ticket"| Backend
end
Gateway -->|"Private connectivity + HTTPS / mTLS"| Facade Each component then has a clear responsibility.
Azure workload¶
Uses modern identity and knows nothing about Kerberos.
Azure API Management¶
Authenticates and authorises the modern caller and provides the API boundary.
Windows facade¶
Enforces the trusted inbound connection and permitted operations, translates API contracts, and calls the backend using the dedicated Windows service identity. It doesn't impersonate an end user in this pattern.
Legacy API¶
Continues using its existing authentication model until it can be modernised or replaced.
Conclusion¶
Connecting Azure to an older Windows-authenticated API isn't really about finding a clever way to make API Management speak Kerberos.
The more useful question is:
Where should the boundary between modern and legacy authentication live?
Where possible, modernise the backend and remove the boundary altogether.
Where that isn't practical, a small Windows-hosted facade using a dedicated service identity provides a relatively simple transition pattern. Introduce user impersonation and Kerberos Constrained Delegation only where the backend genuinely requires the original user's Windows identity.
Most importantly, keep the workaround at the edge of the legacy system rather than allowing its authentication model to spread into the modern architecture.
Further reading¶
- Microsoft Entra identity platform
- API Management authentication and authorisation
- API Management backend client-certificate authentication
- API Management self-hosted gateway
- Kerberos Constrained Delegation overview
- Microsoft Entra Application Proxy
- Application Proxy KCD prerequisites and configuration
- Windows authentication with KCD and Microsoft Entra ID