Azure API Management Policies and Custom Authentication Flows – Part 4: Advanced Scenarios & Best Practices

Azure API Management Policies and Custom Authentication Flows

Part 4: Advanced Scenarios & Production Best Practices

In this final part of our Azure API Management series, we’ll explore advanced enterprise scenarios, policy testing strategies, performance optimization techniques, and production-ready security best practices.

B2B Authentication Scenarios

<!-- B2B partner authentication with different trust levels -->
<inbound>
    <set-variable name="partnerType" value="@{
        var clientId = context.Request.Headers.GetValueOrDefault("X-Client-ID", "");
        var premiumPartners = new[] { "partner-A", "partner-B" };
        
        if (premiumPartners.Contains(clientId)) return "premium";
        return "standard";
    }" />
    
    <choose>
        <when condition="@((string)context.Variables["partnerType"] == "premium")">
            <!-- Premium partners: Certificate + JWT -->
            <choose>
                <when condition="@(context.Request.Certificate == null)">
                    <return-response>
                        <set-status code="401" reason="Unauthorized" />
                        <set-body>{"error": "certificate_required"}</set-body>
                    </return-response>
                </when>
            </choose>
            
            <validate-jwt header-name="Authorization" failed-validation-httpcode="401">
                <openid-config url="https://premium-partner.com/.well-known/openid_configuration" />
            </validate-jwt>
            
            <rate-limit-by-key calls="10000" renewal-period="3600" 
                counter-key="@("premium-" + context.Request.Headers["X-Client-ID"])" />
        </when>
        <otherwise>
            <!-- Standard partners: API Key -->
            <set-variable name="apiKey" value="@(context.Request.Headers.GetValueOrDefault("X-API-Key", ""))" />
            
            <choose>
                <when condition="@(string.IsNullOrEmpty((string)context.Variables["apiKey"]))">
                    <return-response>
                        <set-status code="401" reason="Unauthorized" />
                        <set-body>{"error": "api_key_required"}</set-body>
                    </return-response>
                </when>
            </choose>
            
            <rate-limit-by-key calls="1000" renewal-period="3600" 
                counter-key="@((string)context.Variables["apiKey"])" />
        </otherwise>
    </choose>
</inbound>

Performance Optimization

<!-- Optimized policy with caching -->
<inbound>
    <set-variable name="cacheKey" value="@("auth-" + context.Request.Headers.GetValueOrDefault("Authorization", "").GetHashCode())" />
    
    <cache-lookup-value key="@((string)context.Variables["cacheKey"])" variable-name="cachedAuth" />
    
    <choose>
        <when condition="@(!context.Variables.ContainsKey("cachedAuth"))">
            <validate-jwt header-name="Authorization" failed-validation-httpcode="401">
                <openid-config url="https://login.microsoftonline.com/{tenant}/.well-known/openid_configuration" />
            </validate-jwt>
            
            <cache-store-value key="@((string)context.Variables["cacheKey"])" 
                value="valid" duration="300" />
        </when>
    </choose>
</inbound>

Security Monitoring

<!-- Security event monitoring -->
<inbound>
    <set-variable name="suspiciousActivity" value="@{
        var userAgent = context.Request.Headers.GetValueOrDefault("User-Agent", "");
        var path = context.Request.Url.Path;
        
        if (userAgent.Contains("curl") || userAgent.Contains("python"))
            return true;
        if (path.Contains("..") || path.Contains("admin"))
            return true;
        
        return false;
    }" />
    
    <choose>
        <when condition="@((bool)context.Variables["suspiciousActivity"])">
            <send-request mode="new" response-variable-name="securityLog" timeout="2" ignore-error="true">
                <set-url>https://security.contoso.com/api/events</set-url>
                <set-method>POST</set-method>
                <set-body>@{
                    return new JObject(
                        new JProperty("eventType", "suspicious_activity"),
                        new JProperty("clientIp", context.Request.IpAddress),
                        new JProperty("timestamp", DateTime.UtcNow)
                    ).ToString();
                }</set-body>
            </send-request>
            
            <rate-limit-by-key calls="10" renewal-period="3600" 
                counter-key="@("suspicious-" + context.Request.IpAddress)" />
        </when>
    </choose>
</inbound>

Production Checklist

Security Configuration

  • ✅ Enable HTTPS only with proper TLS configuration
  • ✅ Implement proper CORS policies
  • ✅ Configure rate limiting for all endpoints
  • ✅ Set up comprehensive logging and monitoring
  • ✅ Configure proper error handling

Performance Optimization

  • ✅ Enable response caching where appropriate
  • ✅ Optimize policy expressions
  • ✅ Use caching for expensive operations
  • ✅ Configure proper timeouts

Final Recommendations

Start Simple: Begin with basic authentication patterns and gradually add complexity.

Security First: Always prioritize security over convenience.

Monitor Everything: Comprehensive monitoring is essential for production.


Azure API Management policies provide a powerful foundation for implementing sophisticated authentication and authorization schemes. The patterns covered in this series will help you build secure, scalable, and maintainable API gateways.

Navigate<< Azure API Management Policies and Custom Authentication Flows – Part 3: Custom Authentication Implementation

Written by:

265 Posts

View All Posts
Follow Me :