Locking Down a Payment API: How We Combined Azure API Management and Azure AD for Enterprise-Grade Security

Anurag DakaliaAnurag Dakalia
4 min read

Introduction

A fintech startup processing $15M/month in transactions, migrated to Azure serverless, their top priority was securing public APIs against breaches and DDoS attacks. While Azure AD authentication for Functions provided a solid foundation, they needed enterprise-grade security for their public endpoints.

By combining Azure API Management (APIM) as a secure gateway and Azure AD for identity, they achieved compliance, scalability, and ironclad security. Here’s how you can replicate this architecture.


Architecture Overview

Key Layers:

  1. APIM: First line of defense (authentication, threat protection).

  2. Azure AD: Identity provider for clients and internal services.

  3. Azure Functions: Business logic with secondary validation.


Step 1: Securing the Gateway with Azure API Management

Why APIM?

  • WAF (Web Application Firewall): Blocks SQLi, XSS, and OWASP Top 10 attacks.

  • Rate Limiting: Throttles abusive clients.

  • Centralized Auth: Validate Azure AD tokens at the gateway level.

Implementation:

  1. Deploy APIM (Developer or Basic tier).

  2. Import Azure Functions as backend APIs.

  3. Enable Azure AD Authentication for the API:

    • In APIM’s Security tab, add an Azure AD app registration as an identity provider.

    • Configure OAuth 2.0 with required scopes (e.g., payment.process).

  4. Apply Policies:

<!-- Validate JWT at APIM level -->  
<validate-jwt header-name="Authorization" failed-validation-httpcode="401">  
  <openid-config url="https://login.microsoftonline.com/{tenant}/v2.0/.well-known/openid-configuration" />  
  <required-claims>  
    <claim name="aud" match="all">  
      <value>{api-client-id}</value>  
    </claim>  
  </required-claims>  
</validate-jwt>  

<!-- Rate limit: 100 calls/minute per client -->  
<rate-limit-by-key calls="100" renewal-period="60" counter-key="@(context.Subscription.Id)" />  

<!-- Block non-HTTPS requests -->  
<when condition="@(context.Request.Url.Scheme != "https")">  
  <return-response>  
    <set-status code="403" reason="HTTPS Required" />  
  </return-response>  
</when>

Result:

  • Blocked 12,000+ malicious requests in the first month.

  • Reduced unauthorized traffic to Functions by 95%.


Step 2: Azure AD Authentication for Clients

Setup:

  1. Register Clients (SPA/mobile apps) in Azure AD.

  2. Define Scopes: For e.g.,

    • Payment.Process: For submitting transactions.

    • Payment.Refund: For refund approvals.

  3. Clients Acquire Tokens:

// Example: SPA using MSAL.js  
const msalConfig = {  
  auth: {  
    clientId: "{client-id}",  
    authority: "https://login.microsoftonline.com/{tenant-id}",  
  },  
};  

const request = { scopes: ["api://fintech-api/payment.process"] };  
const token = await msal.acquireTokenSilent(request);

APIM Policy: Enforce scopes before forwarding requests:

<validate-jwt>  
  <!-- ... -->  
  <required-claims>  
    <claim name="scp" match="any">  
      <value>payment.process</value>  
    </claim>  
  </required-claims>  
</validate-jwt>

Step 3: Backend Validation in Azure Functions

Defense-in-Depth: Even if APIM is breached, Functions perform secondary validation.

[FunctionName("ProcessPayment")]  
public async Task<IActionResult> Run(  
    [HttpTrigger(AuthorizationLevel.Anonymous, "post")] HttpRequest req)  
{  
    // Extract token from header (validated by APIM, but verify again)  
    var token = req.Headers["Authorization"].ToString().Replace("Bearer ", "");  
    var principal = await ValidateTokenAndRolesAsync(token, new[] { "Payment.Admin" });  

    if (principal == null)  
        return new UnauthorizedResult();  

    // Access Key Vault securely via Managed Identity  
    var stripeKey = await _secretClient.GetSecretAsync("StripeApiKey");  
    // Process payment  
}

Why Double Validation?

  • Mitigates risks of misconfigured APIM policies.

  • Enforces role-based access at the business logic layer.


Step 4: Securing Backend Services with Managed Identities

Problem:
Functions needed access to Azure SQL (transactions) and Key Vault (Stripe keys).

Solution:

  1. Enable Managed Identity for the Function App.

  2. Grant the identity:

    • Key Vault Secrets User on the vault.
  3. SQL Contributor on the database.

// Access SQL without credentials  
var connection = new SqlConnection("Server=payflow-sql.database.windows.net; Authentication=Active Directory Managed Identity");  

// Access Key Vault  
var credential = new DefaultAzureCredential();  
var secretClient = new SecretClient(new Uri(keyVaultUrl), credential);

Step 5: Audit and Compliance

APIM Analytics:

  • Track API usage, errors, and latency.

  • Identify suspicious clients with Request/Response Logging.

Azure Monitor Alerts:

  • Trigger emails/SMS for:

    • TooManyRequests (APIM rate limits).

    • FailedFunctionExecutions (Application Insights).

PCI-DSS Compliance:

  • APIM WAF Logs: Prove protection against OWASP threats.

  • Azure AD Audit Logs: Track token issuance and admin changes.


Results

  • Blocked 10,000+ malicious requests/month via APIM’s WAF and rate limits.

  • Achieved PCI-DSS compliance with end-to-end encryption and audit trails.

  • Zero hardcoded secrets (Managed Identities + Key Vault).

  • 5x faster troubleshooting with centralized APIM and Application Insights logs.


Best Practices for APIM + Azure AD

  1. Least Privilege Access:

    • Assign minimal roles to APIM (e.g., only forward to Functions).

    • Use granular Azure AD scopes (e.g., payment.read, payment.write).

  2. Automate Policy Deployment:

    • Use Azure DevOps to version-control APIM policies.

Test Security:

  • Run penetration tests with tools like OWASP ZAP.

  • Audit logs monthly for suspicious patterns.


Conclusion

For high-stakes APIs, Azure API Management and Azure AD are a powerhouse combo. APIM acts as your armored gateway, while Azure AD ensures only trusted identities get through. Add Functions with Managed Identities and Key Vault, and you’ve got a PCI-ready, scalable system.

Next: "Scaling to 1M Requests/Day: Auto-Scaling Azure Functions with APIM and Redis."

👉 Follow Azure Elevate for more production-tested codes/architectures.

0
Subscribe to my newsletter

Read articles from Anurag Dakalia directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Anurag Dakalia
Anurag Dakalia