Azure API Management Policy Snippets

repository·master·Indexed 19 days ago

https://github.com/azure/api-management-policy-snippets

A collection of Azure API Management (APIM) policy snippets, examples, and tools for authoring, testing, and managing policies. Includes implementations for OAuth Proxy, OIDC endpoints, and identity patterns. Provides guidance on using policy expressions to interact with HTTP headers, URI and query parameters, policy variables, JSON bodies, Bearer JWT claims, and client certificates.

Tokens
4.6K
Snippets
9
Records
15
Agent score
64%

What's inside azure-api-management-policy-snippets

  1. Browse Azure API Management Policy Snippets by Category

    master

    The examples/ directory contains a collection of XML policy snippets designed to solve common architectural and security patterns in Azure API Management (APIM). These snippets can be used to implement features such as Managed Identity authentication, OAuth2 flows, backend routing, and data transformation.

    Key categories of available snippets include:

    • Identity & Authentication: Managed Identity for Event Hub, Service Bus, and Storage; OAuth2 (AAD, SAP, SuccessFactors); JWT parsing and validation; Basic Authentication.
    • Backend Routing & Load Balancing: Redundancy/Failover, Random Load Balancing, Regional Routing, and Backend for Frontend (BFF) aggregation.
    • Azure Service Integration: Triggering Azure Data Factory pipelines, querying CosmosDB, interacting with Azure Storage (Blob CRUD), and Azure Event Grid forwarding.
    • Security & Transformation: HMAC SHA256 JWT creation, AES encryption, XML value extraction, and IP filtering.
    • Observability & Error Handling: Logging to Stackify, adding correlation IDs, and custom error messages for JWT validation.
  2. Understand OAuth Proxy Policy Fragments

    master

    The OAuth Proxy functionality is modularized into several fragments. Understanding their purpose and placement is critical for correct implementation:

    • oauth-proxy-token-endpoint-fragment: Sets the idpTokenEndpoint variable. Must be placed above oauth-proxy-session-fragment.
    • oauth-proxy-session-fragment: The core logic. Checks for a session cookie, fetches/decrypts tokens from Redis, renews tokens if necessary, and appends the Authorization: Bearer {access-token} header to the request.
    • oauth-proxy-validate-token-fragment: An optional step to perform additional JWT validation on the access token (e.g., using validate-azure-ad-token or validate-jwt). Place after oauth-proxy-session-fragment.
    • oauth-proxy-construct-authorization-redirect-fragment: Constructs the OIDC Authorize request URI and sets the oauth-proxy-redirect variable.
    • oauth-proxy-slide-session-fragment: An outbound fragment that issues a new session cookie to extend the session lifetime (sliding expiration).
  3. Use Azure API Management policy examples

    master

    The examples/ directory contains policy samples contributed by the product team and the community. These samples can be used verbatim, for inspiration, or as learning aids.

    Important Note on Parameterization: Some samples use Named Values (formerly Properties) for parameterization. These are represented by the syntax {{some-value}}. To use these samples, you must either:

    1. Define the corresponding Named Values in your Azure API Management instance.
    2. Manually replace the {{some-value}} placeholders with actual values in the XML code.
  4. Protect Web Applications with OAuth Proxy Policies

    master

    To protect a Web Application, you must include a specific sequence of policy fragments in your <inbound> and <outbound> sections.

    Policy Sequence Requirements

    1. Inbound:
      • oauth-proxy-token-endpoint-fragment (Must be first to set required variables).
      • oauth-proxy-session-fragment (Checks for session cookie or initiates sign-in).
      • oauth-proxy-validate-token-fragment (Optional: provides additional JWT validation).
    2. Outbound/On-Error:
      • oauth-proxy-slide-session-fragment (Slides the session cookie forward to extend the session).

    Implementation Example

    <policies>
        <inbound>
            <include-fragment fragment-id="oauth-proxy-token-endpoint-fragment" />
            <include-fragment fragment-id="oauth-proxy-session-fragment" />
            <include-fragment fragment-id="oauth-proxy-validate-token-fragment" />
            
            <!-- Adds the following headers to the downstream request: 
                Authorization: Bearer {access-token}
                x-proxy-id-token: {id-token} 
                x-proxy-id-token-name: {id-token name claim}
                x-proxy-id-token-preferred-username: {id-token preferred-username claim}
                -->
            <base />
        </inbound>
        <backend>
            <base />
        </backend>
        <outbound>
            <include-fragment fragment-id="oauth-proxy-slide-session-fragment" />
            <base />
        </outbound>
        <on-error>
            <include-fragment fragment-id="oauth-proxy-slide-session-fragment" />
            <base />
        </on-error>
    </policies>
    <policies>
        <inbound>
            <include-fragment fragment-id="oauth-proxy-token-endpoint-fragment" />
            <include-fragment fragment-id="oauth-proxy-session-fragment" />
            <include-fragment fragment-id="oauth-proxy-validate-token-fragment" />
            <base />
        </inbound>
        <backend>
            <base />
        </backend>
        <outbound>
            <include-fragment fragment-id="oauth-proxy-slide-session-fragment" />
            <base />
        </outbound>
        <on-error>
            <include-fragment fragment-id="oauth-proxy-slide-session-fragment" />
            <base />
        </on-error>
    </policies>
  5. Set up the OAuth Proxy in Azure API Management

    master

    To implement an OAuth Proxy similar to App Service Authentication, you must configure several Named Values in Azure API Management and include specific policy fragments in your API policies.

    1. Configure Required Named Values

    You need to define the following Named Values to handle encryption, identity, and session management:

    Named ValuePurpose
    AdditionalScopesSpace separated string of other scopes to request delegated consent for
    ClientIdAAD ClientId representing the application you are signing in against
    ClientSecretAAD Client Secret used to exchange codes for tokens
    CookiePrefixThe name used for the cookie to control the oauth-proxy
    CookieEncryptionKey1 or 2. Selects the key (CookieEncryptionKey1 or CookieEncryptionKey2) used to protect newly issued cookies
    CookieEncryptionKey1Base 64 Encoded 32-byte array. Used by AES 256 to encrypt cookies
    CookieEncryptionKey2Base 64 Encoded 32-byte array. Used by AES 256 to encrypt cookies
    TokenEncryptionKey1 or 2. Selects the key (TokenEncryptionKey1 or TokenEncryptionKey2) used to protect tokens
    TokenEncryptionKey1Base 64 Encoded 32-byte array. Used as the AES 256 key for encrypting tokens at rest
    TokenEncryptionKey2Base 64 Encoded 32-byte array. Used as the AES 256 key for encrypting tokens at rest
    SessionCookieExpirationInSecondsDuration for session cookies to stay active
    RefreshTokenExpirationInSecondsDuration to cache refresh tokens
    TenantIdAAD Tenant Id that owns the ClientId (required for Azure Active Directory)

    2. Generate Encryption Keys

    You can generate the required Base 64 encoded 32-byte strings using:

    In dotnet:

    Convert.ToBase64String(RandomNumberGenerator.GetBytes(32))

    In bash:

    openssl rand -base64 32
    openssl rand -base64 32
  6. Interact with JSON bodies in policy expressions

    master

    Use JObject and SelectToken to manipulate JSON payloads in requests or responses.

    • Get value from Request body: Cast the body to JObject using .As<JObject>(preserveContent: true) and use SelectToken with a JSONPath. Setting preserveContent: true is critical to ensure the body remains available for downstream processing.
    • Get value from Response variable: If a response was stored in a variable, cast the variable to IResponse, access its body as JObject, and use SelectToken.
    • Add property to JSON body: Convert the body to a JObject, use .Add(new JProperty(...)) to insert a new field, and return the stringified version.
    // Get value from JSON body
    (string)context.Request.Body.As<JObject>(preserveContent: true).SelectToken("root.child jsonpath")
    
    // Get value from JSON response variable
    (string)((IResponse)context.Variables["response-variable-name"]).Body.As<JObject>().SelectToken("root.child jsonpath")
    
    // Add property to JSON body
    JObject body = context.Request.Body.As<JObject>(); 
    body.Add(new JProperty("property-name", "property-value"));
    return body.ToString(); 
  7. Interact with client certificates in policy expressions

    master

    Use context.Request.Certificate to validate and inspect client certificates provided during the TLS handshake.

    • Check existence: Verify context.Request.Certificate != null.
    • Validation:
      • Use .Verify() for full validation including revocation checks.
      • Use .VerifyNoRevocation() to validate the certificate without checking revocation status.
    • Inspect Metadata:
      • Issuer: Compare .Issuer against a trusted string.
      • Subject: Compare .SubjectName.Name against an expected name.
      • Thumbprint: Compare .Thumbprint against an expected uppercase hex string.
    • Verify APIM Upload: Check if the client's certificate thumbprint matches any certificate uploaded to the Azure API Management instance using context.Deployment.Certificates.Any(...).
    context.Request.Certificate != null
    
    // Check if client certificate is valid, including a certificate revocation check
    context.Request.Certificate.Verify() == true
    
    // Check if client certificate is valid, excluding a certificate revocation check
    context.Request.Certificate.VerifyNoRevocation() == true
    
    // Check if client certificate issuer has expected value
    context.Request.Certificate.Issuer == "trusted-issuer"
    
    // Check if client certificate subject has expected value
    context.Request.Certificate.SubjectName.Name == "expected-subject-name"
    
    // Check if client certificate thumbprint has expected value
    context.Request.Certificate.Thumbprint == "EXPECTED-THUMBPRINT-IN-UPPER-CASE"
    
    // Check if client certificate is uploaded in API Management, based on thumbprint
    context.Deployment.Certificates.Any(c => c.Value.Thumbprint == context.Request.Certificate.Thumbprint) == true
  8. Read claims from a Bearer JWT token

    master

    To extract a specific claim from a JSON Web Token (JWT) passed in the Authorization header, use the following pattern:

    1. Retrieve the Authorization header.
    2. Split the string to isolate the token (the second part of the Bearer <token> string).
    3. Use the .AsJwt() extension method to parse the token.
    4. Access the Claims dictionary and use .FirstOrDefault() to retrieve the claim value.
    // Read claim from bearer token
    context.Request.Headers.GetValueOrDefault("Authorization")?.Split(' ')?[1].AsJwt()?.Claims["claim-name"].FirstOrDefault()
  9. Interact with policy variables in policy expressions

    master

    Use the context.Variables collection to manage and retrieve custom variables defined within the policy scope.

    • Get variable: Use GetValueOrDefault<T> to retrieve a variable. Note that you must specify the type (e.g., <string>) when using GetValueOrDefault for variables.
    • Check existence: Use ContainsKey to verify if a variable has been set.
    • Validate value: Use GetValueOrDefault<string> combined with .Equals() for case-insensitive string comparison.
    // Get policy variable (assuming type string)
    context.Variables.GetValueOrDefault<string>("variable-name","optional-default-value")
    
    // Check policy variable existence
    context.Variables.ContainsKey("variable-name") == true
    
    // Check if policy variable has expected value (assuming type string)
    context.Variables.GetValueOrDefault<string>("variable-name","").Equals("expected-value", StringComparison.OrdinalIgnoreCase)
  10. Interact with query string parameters in policy expressions

    master

    Use the context.Request.Url.Query collection to access parameters passed in the URL query string.

    • Get parameter: Use GetValueOrDefault to retrieve a query parameter value.
    • Check existence: Use ContainsKey to verify the parameter is present in the query string.
    • Validate value: Use GetValueOrDefault with .Equals() and StringComparison.OrdinalIgnoreCase for case-insensitive validation.
    // Get query string parameter
    context.Request.Url.Query.GetValueOrDefault("parameter-name", "optional-default-value")
    
    // Check query string parameter existence
    context.Request.Url.Query.ContainsKey("parameter-name") == true
    
    // Check if query string parameter has expected value
    context.Request.Url.Query.GetValueOrDefault("parameter-name", "").Equals("expected-value", StringComparison.OrdinalIgnoreCase) == true