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

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

Azure API Management Policies and Custom Authentication Flows

Part 3: Custom Authentication Flows Implementation

Building custom authentication flows allows you to implement sophisticated security patterns that meet your specific business requirements. This part covers practical implementations of multi-step authentication, external identity providers, and custom token validation.

Multi-Step Authentication Flow

<!-- Multi-step authentication implementation -->
<inbound>
    <!-- Step 1: Validate primary authentication -->
    <validate-jwt header-name="Authorization" failed-validation-httpcode="401">
        <openid-config url="https://login.microsoftonline.com/{tenant}/.well-known/openid_configuration" />
    </validate-jwt>
    
    <!-- Step 2: Check for additional authentication requirements -->
    <set-variable name="requiresDeviceAuth" value="@{
        var path = context.Request.Url.Path.ToLower();
        return path.Contains("/admin/") || path.Contains("/sensitive/");
    }" />
    
    <choose>
        <when condition="@((bool)context.Variables["requiresDeviceAuth"])">
            <set-variable name="deviceToken" value="@(context.Request.Headers.GetValueOrDefault("X-Device-Token", ""))" />
            
            <choose>
                <when condition="@(string.IsNullOrEmpty((string)context.Variables["deviceToken"]))">
                    <return-response>
                        <set-status code="428" reason="Precondition Required" />
                        <set-header name="X-Auth-Challenge" exists-action="override">
                            <value>device-registration</value>
                        </set-header>
                        <set-body>{"error": "device_registration_required"}</set-body>
                    </return-response>
                </when>
            </choose>
        </when>
    </choose>
</inbound>

External Identity Provider Integration

<!-- External IdP integration -->
<inbound>
    <set-variable name="customToken" value="@(context.Request.Headers.GetValueOrDefault("X-Custom-Auth", ""))" />
    
    <choose>
        <when condition="@(!string.IsNullOrEmpty((string)context.Variables["customToken"]))">
            <send-request mode="new" response-variable-name="externalAuth" timeout="10">
                <set-url>https://external-idp.partner.com/validate</set-url>
                <set-method>POST</set-method>
                <set-body>@{
                    return new JObject(
                        new JProperty("token", context.Variables["customToken"])
                    ).ToString();
                }</set-body>
            </send-request>
            
            <choose>
                <when condition="@(((IResponse)context.Variables["externalAuth"]).StatusCode != 200)">
                    <return-response>
                        <set-status code="401" reason="Unauthorized" />
                        <set-body>{"error": "external_auth_failed"}</set-body>
                    </return-response>
                </when>
            </choose>
        </when>
        <otherwise>
            <validate-jwt header-name="Authorization" failed-validation-httpcode="401">
                <openid-config url="https://login.microsoftonline.com/{tenant}/.well-known/openid_configuration" />
            </validate-jwt>
        </otherwise>
    </choose>
</inbound>

Claims Transformation

<!-- Transform and enrich claims -->
<inbound>
    <set-variable name="userClaims" value="@{
        var authHeader = context.Request.Headers.GetValueOrDefault("Authorization", "");
        if (!authHeader.StartsWith("Bearer ")) return null;
        
        var token = authHeader.Substring(7);
        var parts = token.Split('.');
        if (parts.Length != 3) return null;
        
        var payload = parts[1] + new string('=', (4 - parts[1].Length % 4) % 4);
        var decoded = Convert.FromBase64String(payload);
        var json = Encoding.UTF8.GetString(decoded);
        return JObject.Parse(json);
    }" />
    
    <choose>
        <when condition="@(context.Variables["userClaims"] != null)">
            <set-variable name="userId" value="@(((JObject)context.Variables["userClaims"])["sub"]?.ToString())" />
            
            <!-- Set enriched headers for backend -->
            <set-header name="X-User-ID" exists-action="override">
                <value>@((string)context.Variables["userId"])</value>
            </set-header>
        </when>
    </choose>
</inbound>

Coming Up Next

In Part 4, we’ll explore advanced scenarios including B2B authentication, policy testing frameworks, and enterprise security best practices.


Custom authentication flows provide the flexibility to implement sophisticated security patterns tailored to your specific requirements.

Navigate<< Azure API Management Policies and Custom Authentication Flows – Part 2: Authentication & Authorization Deep DiveAzure API Management Policies and Custom Authentication Flows – Part 4: Advanced Scenarios & Best Practices >>

Written by:

265 Posts

View All Posts
Follow Me :