# Table of Contents - [Upstream GCP Self-Signed JWT Policy - Zuplo Docs](#upstream-gcp-self-signed-jwt-policy-zuplo-docs) - [Upstream GCP Federated Auth Policy - Zuplo Docs](#upstream-gcp-federated-auth-policy-zuplo-docs) - [Upstream Firebase User Auth Policy - Zuplo Docs](#upstream-firebase-user-auth-policy-zuplo-docs) - [Upstream Azure AD Service Auth Policy - Zuplo Docs](#upstream-azure-ad-service-auth-policy-zuplo-docs) - [JSON Body Validation Policy - Zuplo Docs](#json-body-validation-policy-zuplo-docs) - [Stripe Webhook Auth Policy - Zuplo Docs](#stripe-webhook-auth-policy-zuplo-docs) - [Transform Response Body Policy - Zuplo Docs](#transform-response-body-policy-zuplo-docs) - [XML to JSON Outbound Policy - Zuplo Docs](#xml-to-json-outbound-policy-zuplo-docs) - [Transform Request Body Policy - Zuplo Docs](#transform-request-body-policy-zuplo-docs) - [Supabase JWT Auth Policy - Zuplo Docs](#supabase-jwt-auth-policy-zuplo-docs) - [Sleep / Delay Policy - Zuplo Docs](#sleep-delay-policy-zuplo-docs) - [Set Status Code Policy - Zuplo Docs](#set-status-code-policy-zuplo-docs) - [Upstream Firebase Admin Auth Policy - Zuplo Docs](#upstream-firebase-admin-auth-policy-zuplo-docs) - [Upstream GCP Service Auth Policy - Zuplo Docs](#upstream-gcp-service-auth-policy-zuplo-docs) - [Add or Set Query Parameters Policy - Zuplo Docs](#add-or-set-query-parameters-policy-zuplo-docs) - [Set Body Policy - Zuplo Docs](#set-body-policy-zuplo-docs) - [Set Headers Policy - Zuplo Docs](#set-headers-policy-zuplo-docs) - [Add or Set Request Headers Policy - Zuplo Docs](#add-or-set-request-headers-policy-zuplo-docs) - [Replace String in Response Body Policy - Zuplo Docs](#replace-string-in-response-body-policy-zuplo-docs) - [Remove Request Headers Policy - Zuplo Docs](#remove-request-headers-policy-zuplo-docs) - [Request Size Limit Policy - Zuplo Docs](#request-size-limit-policy-zuplo-docs) - [Require Origin Policy - Zuplo Docs](#require-origin-policy-zuplo-docs) - [Request Validation Policy - Zuplo Docs](#request-validation-policy-zuplo-docs) - [Remove Query Parameters Policy - Zuplo Docs](#remove-query-parameters-policy-zuplo-docs) - [RBAC Authorization Policy - Zuplo Docs](#rbac-authorization-policy-zuplo-docs) - [Remove Response Headers Policy - Zuplo Docs](#remove-response-headers-policy-zuplo-docs) - [Readme Metrics Policy - Zuplo Docs](#readme-metrics-policy-zuplo-docs) - [Quota Policy - Zuplo Docs](#quota-policy-zuplo-docs) - [Rate Limiting Policy - Zuplo Docs](#rate-limiting-policy-zuplo-docs) - [PropelAuth JWT Auth Policy - Zuplo Docs](#propelauth-jwt-auth-policy-zuplo-docs) - [Okta FGA Authorization Policy - Zuplo Docs](#okta-fga-authorization-policy-zuplo-docs) - [OpenFGA Authorization Policy - Zuplo Docs](#openfga-authorization-policy-zuplo-docs) - [JWT Auth Policy - Zuplo Docs](#jwt-auth-policy-zuplo-docs) - [Okta JWT Auth Policy - Zuplo Docs](#okta-jwt-auth-policy-zuplo-docs) - [Policy Catalog - Zuplo Docs](#policy-catalog-zuplo-docs) - [mTLS Auth Policy - Zuplo Docs](#mtls-auth-policy-zuplo-docs) - [LDAP Auth Policy - Zuplo Docs](#ldap-auth-policy-zuplo-docs) - [Monetization Policy - Zuplo Docs](#monetization-policy-zuplo-docs) - [Mock API Response Policy - Zuplo Docs](#mock-api-response-policy-zuplo-docs) - [Moesif Analytics & Billing Policy - Zuplo Docs](#moesif-analytics-billing-policy-zuplo-docs) - [IP Restriction Policy - Zuplo Docs](#ip-restriction-policy-zuplo-docs) - [JWT Scope Validation Policy - Zuplo Docs](#jwt-scope-validation-policy-zuplo-docs) - [HMAC Auth Policy - Zuplo Docs](#hmac-auth-policy-zuplo-docs) - [GraphQL Disable Introspection Policy - Zuplo Docs](#graphql-disable-introspection-policy-zuplo-docs) - [Geo-location filtering Policy - Zuplo Docs](#geo-location-filtering-policy-zuplo-docs) - [GraphQL Complexity Limit Policy - Zuplo Docs](#graphql-complexity-limit-policy-zuplo-docs) - [Firebase JWT Auth Policy - Zuplo Docs](#firebase-jwt-auth-policy-zuplo-docs) - [Custom Code Outbound Policy - Zuplo Docs](#custom-code-outbound-policy-zuplo-docs) - [Curity Phantom Token Auth Policy - Zuplo Docs](#curity-phantom-token-auth-policy-zuplo-docs) - [Composite Outbound (Group Policies) Policy - Zuplo Docs](#composite-outbound-group-policies-policy-zuplo-docs) - [Form Data to JSON Policy - Zuplo Docs](#form-data-to-json-policy-zuplo-docs) - [Composite Inbound (Group Policies) Policy - Zuplo Docs](#composite-inbound-group-policies-policy-zuplo-docs) - [Custom Code Inbound Policy - Zuplo Docs](#custom-code-inbound-policy-zuplo-docs) - [Clerk JWT Auth Policy - Zuplo Docs](#clerk-jwt-auth-policy-zuplo-docs) - [AWS Cognito JWT Auth Policy - Zuplo Docs](#aws-cognito-jwt-auth-policy-zuplo-docs) - [Clear Request Headers Policy - Zuplo Docs](#clear-request-headers-policy-zuplo-docs) - [Clear Response Headers Policy - Zuplo Docs](#clear-response-headers-policy-zuplo-docs) - [Change Method Policy - Zuplo Docs](#change-method-policy-zuplo-docs) - [Caching Policy - Zuplo Docs](#caching-policy-zuplo-docs) - [Brown Out Policy - Zuplo Docs](#brown-out-policy-zuplo-docs) - [Bot Detection Policy - Zuplo Docs](#bot-detection-policy-zuplo-docs) - [Basic Auth Policy - Zuplo Docs](#basic-auth-policy-zuplo-docs) - [AuthZEN Authorization Policy - Zuplo Docs](#authzen-authorization-policy-zuplo-docs) - [Axiomatics Authorization Policy - Zuplo Docs](#axiomatics-authorization-policy-zuplo-docs) - [Complex Rate Limiting Policy - Zuplo Docs](#complex-rate-limiting-policy-zuplo-docs) - [Auth0 JWT Auth Policy - Zuplo Docs](#auth0-jwt-auth-policy-zuplo-docs) - [Audit Logs Policy - Zuplo Docs](#audit-logs-policy-zuplo-docs) - [Archive Response to Azure Storage Policy - Zuplo Docs](#archive-response-to-azure-storage-policy-zuplo-docs) - [Aserto Authorization Policy - Zuplo Docs](#aserto-authorization-policy-zuplo-docs) - [API Key Authentication Policy - Zuplo Docs](#api-key-authentication-policy-zuplo-docs) - [Archive Response to AWS S3 Policy - Zuplo Docs](#archive-response-to-aws-s3-policy-zuplo-docs) - [Archive Request to AWS S3 Policy - Zuplo Docs](#archive-request-to-aws-s3-policy-zuplo-docs) - [Archive Request to GCP Storage Policy - Zuplo Docs](#archive-request-to-gcp-storage-policy-zuplo-docs) - [Archive Request to Azure Storage Policy - Zuplo Docs](#archive-request-to-azure-storage-policy-zuplo-docs) - [Amberflo Metering / Billing Policy - Zuplo Docs](#amberflo-metering-billing-policy-zuplo-docs) - [A/B Test Outbound Policy - Zuplo Docs](#a-b-test-outbound-policy-zuplo-docs) - [Access Control List Policy - Zuplo Docs](#access-control-list-policy-zuplo-docs) - [A/B Test Inbound Policy - Zuplo Docs](#a-b-test-inbound-policy-zuplo-docs) --- # Upstream GCP Self-Signed JWT Policy - Zuplo Docs Menu [​](#upstream-gcp-self-signed-jwt-policy) Upstream GCP Self-Signed JWT Policy ============================================================================= This policy adds a JWT token to the headers, ready for us in an outgoing request when calling a GCP service (e.g. Cloud Endpoints / ESPv2). We recommend reading the `serviceAccountJson` from environment variables (so it is not checked in to source control) using the `$env(ENV_VAR)` syntax. CAUTION: This policy only works with [certain Google APIs](https://developers.google.com/identity/protocols/oauth2/service-account#jwt-auth) . In most cases, the [Upstream GCP Service Auth](https://zuplo.com/docs/policies/upstream-gcp-service-auth-inbound) should be used. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-upstream-gcp-jwt-inbound-policy", "policyType": "upstream-gcp-jwt-inbound", "handler": { "export": "UpstreamGcpJwtInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "audience": "your\_gcp\_service.endpoint.com", "serviceAccountJson": "$env(SERVICE\_ACCOUNT\_JSON)" } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `upstream-gcp-jwt-inbound`. * `handler.export` `` - The name of the exported type. Value should be `UpstreamGcpJwtInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/upstream-gcp-jwt-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `audience` **(required)** `` - The audience for the minted JWT. See the document [AuthRequirement](https://cloud.google.com/endpoints/docs/grpc-service-config/reference/rpc/google.api#google.api.AuthRequirement) for details. * `serviceAccountJson` **(required)** `` - The Google Service Account key in JSON format. Note you can load this from environment variables using the $env(ENV\_VAR) syntax. [​](#using-the-policy) Using the Policy --------------------------------------- Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Upstream GCP Federated Auth Policy](/docs/policies/upstream-gcp-federated-auth-inbound "Upstream GCP Federated Auth Policy") [Next page →\ \ Upstream Firebase Admin Auth Policy](/docs/policies/upstream-firebase-admin-auth-inbound "Upstream Firebase Admin Auth Policy") --- # Upstream GCP Federated Auth Policy - Zuplo Docs Menu [​](#upstream-gcp-federated-auth-policy) Upstream GCP Federated Auth Policy =========================================================================== This policy allows you to delegate authentication and authorization to your gateway without writing any code on your origin service by adding an authentication token to outgoing header allowing the service to be secured with GCP IAM. The tokens are issued using Zuplo's internal OAuth services and exchanged with GCP using [Workflow Identity Federation](https://cloud.google.com/iam/docs/workload-identity-federation) . This allows you to authenticate your Zuplo API to your origin without saving any secrets in Zuplo. This is a useful means of securing your origin server so that only your Zuplo gateway can make requests against it. This policy works with [GCP Identity Aware Proxy](https://zuplo.com/docs/articles/gke-with-upstream-auth-policy) or services like [Cloud Run](https://cloud.google.com/iap/docs/managing-access) that natively support IAM authorization. For information on how Google's service based auth works see [Authenticating for invocation](https://cloud.google.com/functions/docs/securing/authenticating) ### Beta This policy is in beta. You can use it today, but it may change in non-backward compatible ways before the final release. ### Enterprise Feature This policy is only available as part of our enterprise plans. It's free to try only any plan for development only purposes. If you would like to use this in production reach out to us: [sales@zuplo.com](mailto:sales@zuplo.com) [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-upstream-gcp-federated-auth-inbound-policy", "policyType": "upstream-gcp-federated-auth-inbound", "handler": { "export": "UpstreamGcpFederatedAuthInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "audience": "https://hello-k7meruiynq-uc.a.run.app", "serviceAccountEmail": "zup-api@my-project.iam.gserviceaccount.com", "workloadIdentityProvider": "projects/932049231233/locations/global/workloadIdentityPools/my-pool/providers/my-provider" } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `upstream-gcp-federated-auth-inbound`. * `handler.export` `` - The name of the exported type. Value should be `UpstreamGcpFederatedAuthInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/upstream-gcp-federated-auth-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `audience` **(required)** `` - The audience for the minted JWT. This is typically the URL of your service. See the document [AuthRequirement](https://cloud.google.com/endpoints/docs/grpc-service-config/reference/rpc/google.api#google.api.AuthRequirement) for details. * `serviceAccountEmail` **(required)** `` - The Google Service Account email address. * `workloadIdentityProvider` **(required)** `` - No description available. * `tokenLifetime` `` - The lifetime in seconds of the issued token. Defaults to `3600`. * `tokenRetries` `` - The number of times to retry fetching the token in the event of a failure. Defaults to `3`. * `expirationOffsetSeconds` `` - The number of seconds less than the token expiration to cache the token. Defaults to `300`. * `useMemoryCacheOnly` `` - This is an advanced option that should only be used if you do not want to persist information in ZoneCache. [​](#using-the-policy) Using the Policy --------------------------------------- Before you can use this policy, you will need to have configured the following: * Setup Workload Identity Federation in your GCP project * Create a GCP service account with the appropriate permissions. ### [​](#setup-gcp-workload-identity-federation) Setup GCP Workload Identity Federation Setting up Workload Identity Federation for Zuplo follows the instructions for setting up a standard OIDC Identity Provider. Refer to [Google's Documentation for additional details](https://cloud.google.com/iam/docs/workload-identity-federation-with-other-providers#configure) . To begin, navigate to the [Workload Identity page of Google Cloud Console](https://console.cloud.google.com/iam-admin/workload-identity-pools) . You will find this in the **IAM** section on the menu. If you don't already have one, create a new Workload Identity Pool. Then create a new provider and select **OpenID Connect** as the provider type. Complete the following values in the form: * **Provider name**: Any Value * **Provider ID**: Any Value * **Issuer (URL)**: `https://dev.zuplo.com/v1/client-auth/auth_o8PUdhKxSTOiB794GWPwLQCD` * **JWK File**: Do not set this value, GCP will perform automatic discovery of the OAuth configuration. * **Audiences**: Select "Default Audience" Copy the URL value for the **Default Audience** and record it for later use. Click **Continue** and set the follow provider attribute mappings. * `google.subject` => `"zuplo::" + assertion.account + "::" + assertion.project + "::" + assertion.deployment` * `attributes.account` => `assertion.account` * `attributes.project` => `assertion.project` * `attributes.deployment` => `assertion.deployment` You can read about all the claims in the [Zuplo Identity Token](https://zuplo.com/docs/articles/zuplo-id-token) documentation. Set **Attribute Conditions** ### Important Security Step It is critical that you set at minimum the `attribute.account == "my-account"` attribute condition. Without this restriction ANY Zuplo API would be able to call your resources. Set the attribute conditions you want to use to restrict access to this Workload Identity Pool. Generally, you only need to set this to restrict the account. You will use IAM bindings to grant specific permissions in later steps. To set the account condition set the following value. attribute.account == "my-account" plain If you want to set further conditions, you can do so as desired, for example to restrict access to all environments in a project set the following. attribute.account == "my-account" && attribute.project == "my-project" txt ### [​](#create-a-service-account) Create a Service Account You Zuplo Identity Token will be granted access to act as if it where a service account in your Google project. As such, you will need to create a service account. You can do so in the Google console or using the Google CLI: gcloud iam service-accounts create zuplo-api \\ –-description="zuplo api sa" \\ –-display-name="zuplo-api" shell Next you need to create role binding for the Zuplo principal to impersonate the service account: * `SERVICE_ACCOUNT_EMAIL` is the email address of the service account. * `PROJECT_NUMBER` is your numeric Google project number. * `POOL_ID` is the id of the Workload Identity Pool you created earlier, for example `zuplo-pool`. * `SUBJECT` is the same the concatenated value we set to the value of `google.subject` earlier. For example, `zuplo::my-account::my-project::my-deployment-1235` gcloud iam service-accounts add-iam-policy-binding $SERVICE\_ACCOUNT\_EMAIL \\ --role roles/iam.workloadIdentityUser \\ --member "principal://iam.googleapis.com/projects/$PROJECT\_NUMBER/locations/global/workloadIdentityPools/$POOL\_ID/subject/$SUBJECT shell Finally, grant your service account the permissions desired. For example, to invoke Cloud Run services grant the `roles/run.invoker` * `SERVICE_ACCOUNT_EMAIL` is the email address of the service account. * `SERVICE_NAME` is the name of your Cloud Run service. gcloud run services add-iam-policy-binding $SERVICE\_NAME --member-"serviceAccount:$SERVICE\_ACCOUNT\_EMAIL" \\ --role="roles/run.invoker" shell ### [​](#set-the-policy-options) Set the Policy Options With GCP Workload Federation setup, you can add the policy to your Zuplo API. * `audience`: Set this to the resource you are planning to call, for example, the Cloud Run URL. * `serviceAccountEmail` - Set this value to the email address of the service account previously created. * `workloadIdentityProvider` - Set this to the value that was copied when setting up your Workload Identity Pool (called **Default Audience**). Remove the beginning `https://iam.googleapis.com/` part of the string. { "name": "gcp-federated-auth", "policyType": "upstream-gcp-federated-auth-inbound-policy", "handler": { "module": "$import(@zuplo/runtime)", "export": "UpstreamGcpFederatedAuthInboundPolicy", "options": { "audience": "https://test-basic-vhpkl3cvtq-uc.a.run.app", "serviceAccountEmail": "zup-api@my-project.iam.gserviceaccount.com", "workloadIdentityProvider": "projects/932049231233/locations/global/workloadIdentityPools/my-pool/providers/my-provider" } } } json Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Upstream GCP Service Auth Policy](/docs/policies/upstream-gcp-service-auth-inbound "Upstream GCP Service Auth Policy") [Next page →\ \ Upstream GCP Self-Signed JWT Policy](/docs/policies/upstream-gcp-jwt-inbound "Upstream GCP Self-Signed JWT Policy") --- # Upstream Firebase User Auth Policy - Zuplo Docs Menu [​](#upstream-firebase-user-auth-policy) Upstream Firebase User Auth Policy =========================================================================== This policy adds a Firebase user token to the outgoing `Authentication` header allowing requests to Firebase using the provided user's permissions. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-upstream-firebase-user-auth-inbound-policy", "policyType": "upstream-firebase-user-auth-inbound", "handler": { "export": "UpstreamFirebaseUserAuthInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "developerClaims": { "premium": true }, "expirationOffsetSeconds": 300, "serviceAccountJson": "$env(SERVICE\_ACCOUNT\_JSON)", "tokenRetries": 3, "userId": "1234", "webApiKey": "$env(WEB\_API\_KEY)" } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `upstream-firebase-user-auth-inbound`. * `handler.export` `` - The name of the exported type. Value should be `UpstreamFirebaseUserAuthInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/upstream-firebase-user-auth-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `serviceAccountJson` **(required)** `` - The Google Service Account key in JSON format. Note you can load this from environment variables using the $env(ENV\_VAR) syntax. * `userId` `` - The userId to use as the custom token's subject. * `userIdPropertyPath` `` - The property on the incoming request.user object to retrieve the value of the userId. * `developerClaims` `` - Additional claims to include in the custom token's payload. * `webApiKey` **(required)** `` - The Firebase Web API Key (found in project settings) * `tokenRetries` `` - The number of times to retry fetching the token in the event of a failure. Defaults to `3`. * `expirationOffsetSeconds` `` - The number of seconds less than the token expiration to cache the token. Defaults to `300`. [​](#using-the-policy) Using the Policy --------------------------------------- Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Upstream Firebase Admin Auth Policy](/docs/policies/upstream-firebase-admin-auth-inbound "Upstream Firebase Admin Auth Policy") [Next page →\ \ Archive Request to Azure Storage Policy](/docs/policies/archive-request-azure-storage-inbound "Archive Request to Azure Storage Policy") --- # Upstream Azure AD Service Auth Policy - Zuplo Docs Menu [​](#upstream-azure-ad-service-auth-policy) Upstream Azure AD Service Auth Policy ================================================================================= This policy adds a `Authorization` header to the upstream request that allows using Azure AD to authenticate requests to your origin server. This is a useful means of securing your origin server so that only your Zuplo gateway can make requests against it. Using this policy allows you to delegate authentication and authorization to your gateway without writing any code on your origin service. For instructions on how to configure Azure AD authentication see [Configure your App Service or Azure Functions app to use Azure AD login](https://learn.microsoft.com/en-us/azure/app-service/configure-authentication-provider-aad) . [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-upstream-azure-ad-service-auth-inbound-policy", "policyType": "upstream-azure-ad-service-auth-inbound", "handler": { "export": "UpstreamAzureAdServiceAuthInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "activeDirectoryClientId": "20edbb34-13e9-42d0-a63c-1b6a0a20d02d", "activeDirectoryClientSecret": "$env(ACTIVE\_DIRECTORY\_CLIENT\_SECRET)", "activeDirectoryTenantId": "b8e4141e-31f4-43e3-9a96-f97f3eba1eea", "expirationOffsetSeconds": 300, "tokenRetries": 3 } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `upstream-azure-ad-service-auth-inbound`. * `handler.export` `` - The name of the exported type. Value should be `UpstreamAzureAdServiceAuthInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/upstream-azure-ad-service-auth-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `activeDirectoryTenantId` **(required)** `` - Azure Active Directory Tenant ID. * `activeDirectoryClientId` **(required)** `` - The Application (client) ID of the Azure AD App Registration. * `activeDirectoryClientSecret` **(required)** `` - The client secret of the Azure AD App Registration. * `tokenRetries` `` - The number of times to retry fetching the token in the event of a failure.. Defaults to `3`. * `expirationOffsetSeconds` `` - The number of seconds less than the token expiration to cache the token. Defaults to `300`. [​](#using-the-policy) Using the Policy --------------------------------------- Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Replace String in Response Body Policy](/docs/policies/replace-string-outbound "Replace String in Response Body Policy") [Next page →\ \ Upstream GCP Service Auth Policy](/docs/policies/upstream-gcp-service-auth-inbound "Upstream GCP Service Auth Policy") --- # JSON Body Validation Policy - Zuplo Docs [​](#json-body-validation-policy) JSON Body Validation Policy ============================================================= This policy is deprecated. Use the new [Request Validation\ Policy](https://zuplo.com/docs/policies/request-validation-inbound) . The new policy validates JSON bodies like this policy, but also supports validation of parameters, query strings, etc. The Validate JSON Schema policy is used to validate the body of incoming requests. It works using JSON Schemas defined in the `Schemas` folder of your project. When configured, any requests that do not have a body conforming to your JSON schema will be rejected with a `400: Bad Request` response containing a detailed error message (in JSON) explaining why the body was not accepted. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-validate-json-schema-inbound-policy", "policyType": "validate-json-schema-inbound", "handler": { "export": "ValidateJsonSchemaInbound", "module": "$import(@zuplo/runtime)", "options": { "validator": "$import(./schemas/example-schema.json)" } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `validate-json-schema-inbound`. * `handler.export` `` - The name of the exported type. Value should be `ValidateJsonSchemaInbound`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/validate-json-schema-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `validator` **(required)** `` - The JSON schema to validate against. [​](#using-the-policy) Using the Policy --------------------------------------- Here's a simple, example JSON Schema { "title": "Car", "type": "object", "properties": { "make": { "type": "string" }, "model": { "type": "string" }, "maxSpeed": { "description": "Max Speed in Mile Per Hour (MPH)", "type": "integer", "minimum": 0 }, "color": { "enum": \["black", "brown", "blue", "red", "silver"\], "type": "string" } }, "additionalProperties": false, "required": \["make", "model"\] } json > Note - "title" is a required property of JSON schema This defines a body that should be of type object with required string properties `make` and `model`. It also defines two optional properties `maxSpeed` and `color`. The former must be an integer greater than or equal to zero and `color` can (in this silly example) can be one of "black", "brown", "red", "silver" or "blue". No other properties can be on this object. The schemas file should live in the `schemas` folder of your project - for the purposes of this example let's imagine it is called `car.json`. ### Create Project This sample is available on [GitHub](https://github.com/zuplo/samples-basic-auth) or click the button below to open the code directly in the portal. [![ZupIt](https://cdn.zuplo.com/www/zupit.svg)](https://portal.zuplo.com/clone?sourceRepoUrl=https://github.com/zuplo/samples-basic-auth) [​](#configuration-1) Configuration ----------------------------------- Here is an example configuration (this would go in `policies.json`). { "name": "validate-car-policy", "policyType": "validate-json-schema-inbound", "handler": { "export": "ValidateJsonSchemaInbound", "module": "$import(@zuplo/runtime)", "options": { "validator": "$import(./schemas/car.json)" } } } json * `name` the name of your policy instance, this is used to refer to your policy from your routes, see below. * `policyType` the identifier of the policy. This is used by the Zuplo UI. Value should be `validate-json-schema-inbound`. * `handler/export` The name of the exported type. Value should be `ValidateJsonSchemaInboundPolicy`. * `handler/module` the module containing the policy. Value should be `@zuplo/runtime`. * `handler/options` The options for this policy: * `validator` a '$import' reference to the schema - e.g. `$import(./schemas/car.json)` This policy is then referenced from each route where you want the policy to be enforced, for example: { "path": "/products/:123", "methods": \["POST"\], "handler": { "module": "$import(./modules/products)", "export": "postProducts" }, "corsPolicy": "None", "policies": { "inbound": \["validate-car-policy"\] } } json You can test this in the API Test Console with the following (correct) body { "make": "Alfa Romeo", "model": "156", "maxSpeed": 134, "color": "silver" } json [​](#errors) Errors ------------------- ### [​](#missing-fields) Missing fields If the request body is missing a required field, an error similar to the following will be returned. { "code": "SCHEMA\_VALIDATION\_FAILED", "help\_url": "https://zup.fail/SCHEMA\_VALIDATION\_FAILED", "message": "Incoming body did not pass schema validation", "errors": \["Body must have required property 'price'"\] } json ### [​](#invalid-field-type) Invalid Field Type If the request body contains a field that is not of the correct type, an error similar to the following will be returned. { "code": "SCHEMA\_VALIDATION\_FAILED", "help\_url": "https://zup.fail/SCHEMA\_VALIDATION\_FAILED", "message": "Incoming body did not pass schema validation", "errors": \["price must be number"\] } json Read more about [how policies work](/docs/articles/policies) * * * --- # Stripe Webhook Auth Policy - Zuplo Docs Menu [​](#stripe-webhook-auth-policy) Stripe Webhook Auth Policy =========================================================== The Stripe Webhook policy secures your incoming webhooks by validating that the request was sent by Stripe. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-stripe-webhook-verification-inbound-policy", "policyType": "stripe-webhook-verification-inbound", "handler": { "export": "StripeWebhookVerificationInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "tolerance": 300 } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `stripe-webhook-verification-inbound`. * `handler.export` `` - The name of the exported type. Value should be `StripeWebhookVerificationInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/stripe-webhook-verification-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `signingSecret` **(required)** `` - The signing secret for the webhook. * `tolerance` `` - The allowed clock skew in seconds between the time the webhook signature was crated and the current time. Defaults to `300`. [​](#using-the-policy) Using the Policy --------------------------------------- Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Request Size Limit Policy](/docs/policies/request-size-limit-inbound "Request Size Limit Policy") [Next page →\ \ Quota Policy](/docs/policies/quota-inbound "Quota Policy") --- # Transform Response Body Policy - Zuplo Docs Menu [​](#transform-response-body-policy) Transform Response Body Policy =================================================================== ### Custom Policy Example Zuplo is extensible, so we don't have a built-in policy for Transform Response Body, instead we've a template here that shows you how you can use your superpower (code) to achieve your goals. To learn more about custom policies [see the documentation](/docs/policies/custom-code-outbound) . This example policy shows how to use `response.json()` to read the outgoing response as a JSON object. The object can then be modified as appropriate. It's then converted back to a string and a new `Response` is returned in the policy with the new body. If the incoming response body isn't JSON, you can use `response.text()` or `response.blob()` to access the contents as raw text or a [blob](https://developer.mozilla.org/en-US/docs/Web/API/Response/blob) . import { ZuploContext, ZuploRequest } from "@zuplo/runtime"; export default async function ( response: Response, request: ZuploRequest, context: ZuploContext, ) { // Get the outgoing body as an Object const obj = await response.json(); // Modify the object as required obj.myNewProperty = "Hello World"; // Stringify the object const body = JSON.stringify(obj); // Return a new response with the new body return new Response(body, request); } ts [​](#configuration) Configuration --------------------------------- The example below shows how to configure a custom code policy in the 'policies.json' document that utilizes the above example policy code. { "name": "transform-body-outbound", "policyType": "custom-code-outbound", "handler": { "export": "default", "module": "$import(./modules/transform-body-outbound)" } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `transform-body-outbound`. * `handler.export` `` - The name of the exported type. Value should be `default`. * `handler.module` `` - The module containing the policy. Value should be `$import(./modules/YOUR_MODULE)`. [​](#using-the-policy) Using the Policy --------------------------------------- Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Add or Set Query Parameters Policy](/docs/policies/set-query-params-inbound "Add or Set Query Parameters Policy") [Next page →\ \ Remove Response Headers Policy](/docs/policies/remove-headers-outbound "Remove Response Headers Policy") --- # XML to JSON Outbound Policy - Zuplo Docs Menu [​](#xml-to-json-outbound-policy) XML to JSON Outbound Policy ============================================================= This policy is useful for converting legacy XML or SOAP APIs into modern REST APIs. It can be useful to add a custom outbound policy that runs after this policy to further transform the raw converted content into something more user friendly. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-xml-to-json-outbound-policy", "policyType": "xml-to-json-outbound", "handler": { "export": "XmlToJsonOutboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "attributeNamePrefix": "@\_", "ignoreAttributes": true, "ignoreDeclarations": true, "ignoreProcessingInstructions": true, "parseOnStatusCodes": "200-299", "removeNSPrefix": true, "stopNodes": \["root.a", "\*.accounts"\], "textNodeName": "#text", "trimValues": true } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `xml-to-json-outbound`. * `handler.export` `` - The name of the exported type. Value should be `XmlToJsonOutboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/xml-to-json-outbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `removeNSPrefix` `` - Remove namespace string from tag and attribute names. Defaults to `true`. * `ignoreProcessingInstructions` `` - Ignore processing instruction tags. i.e. `, , ?>`. Defaults to `true`. * `ignoreDeclarations` `` - Ignore declarations. i.e. ``. Defaults to `true`. * `ignoreAttributes` `` - Ignore tag attributes. Defaults to `true`. * `stopNodes` `` - At particular point, if you don't want to parse a tag and it's nested tags then you can set their path in stopNodes. You can also set tags which should not be processed irrespective of their path using \* as the wildcard. * `attributeNamePrefix` `` - The prefix of attribute names in the resulting JS object. Defaults to `"@_"`. * `textNodeName` `` - Text value of a tag is parsed to #text property by default. Defaults to `"#text"`. * `trimValues` `` - Remove surrounding whitespace from tag or attribute value. Defaults to `true`. * `parseOnStatusCodes` `` - A list of status codes and ranges "200-299, 304" that should the XML parser should run on. If not set, the parser will run on all status codes. [​](#using-the-policy) Using the Policy --------------------------------------- This policy can help expose legacy XML or SOAP APIs using modern JSON REST APIs. The policy is configurable in ways that make it easier to strip parts of the XML document that you are unlikely to use, such as processing instructions, namespaces, or directives. The default options for this policy will generally give you a fairly clean output. However, it is likely that the output of the raw conversion is still not in the best format. The best way to clean up the output of your XML is first, run this policy, then add a [custom code outbound policy](/docs/policies/custom-code-outbound) that further reshapes the JSON data structure. An example policy that cleans up a SOAP response is shown below. SOAP Response USD Dollar EUR Euro xml The code in the policy below takes the output (`response.json()`) of the XML to JSON Outbound policy and reshapes it to a simple JSON structure. modules/clean-soap.ts import { ZuploContext, ZuploRequest } from "@zuplo/runtime"; export default async function cleanSoapBody( response: Response, request: ZuploRequest, context: ZuploContext, ) { const soap = await response.json(); const data: { isoCode: string; name: string }\[\] = soap.Envelope.Body.ListOfCurrenciesByNameResponse.ListOfCurrenciesByNameResult.tCurrency.map( (c) => ({ isoCode: c.sISOCode, name: c.sName, }), ); return new Response(JSON.stringify({ total: data.length, data }), { headers: response.headers, status: response.status, statusText: response.statusText, }); } \`\`; ts The JSON response of your API would then be a easily consumable JSON object. JSON Response { "total": 2, "data": \[\ { "isoCode": "USD", "name": "Dollar" },\ { "isoCode": "EUR", "name": "Euro" }\ \] } json Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Set Status Code Policy](/docs/policies/set-status-outbound "Set Status Code Policy") [Next page →\ \ Replace String in Response Body Policy](/docs/policies/replace-string-outbound "Replace String in Response Body Policy") --- # Transform Request Body Policy - Zuplo Docs Menu [​](#transform-request-body-policy) Transform Request Body Policy ================================================================= ### Custom Policy Example Zuplo is extensible, so we don't have a built-in policy for Transform Request Body, instead we've a template here that shows you how you can use your superpower (code) to achieve your goals. To learn more about custom policies [see the documentation](/docs/policies/custom-code-inbound) . This example policy shows how to use `request.json()` to read the incoming request as a JSON object. The object can then be modified as appropriate. It's then converted back to a string and a new `Request` is returned in the policy with the new body. If the incoming request body isn't JSON, you can use `request.text()` or `request.blob()` to access the contents as raw text or a [blob](https://developer.mozilla.org/en-US/docs/Web/API/Request/blob) . import { ZuploContext, ZuploRequest } from "@zuplo/runtime"; export default async function (request: ZuploRequest, context: ZuploContext) { // Get the incoming body as an Object const obj = await request.json(); // Modify the object as required obj.myNewProperty = "Hello World"; // Stringify the object const body = JSON.stringify(obj); // Return a new request based on the // original but with the new body return new ZuploRequest(request, { body }); } ts [​](#configuration) Configuration --------------------------------- The example below shows how to configure a custom code policy in the 'policies.json' document that utilizes the above example policy code. { "name": "transform-body-inbound", "policyType": "custom-code-inbound", "handler": { "export": "default", "module": "$import(./modules/transform-body-inbound)" } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `transform-body-inbound`. * `handler.export` `` - The name of the exported type. Value should be `default`. * `handler.module` `` - The module containing the policy. Value should be `$import(./modules/YOUR_MODULE)`. [​](#using-the-policy) Using the Policy --------------------------------------- Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Sleep / Delay Policy](/docs/policies/sleep-inbound "Sleep / Delay Policy") [Next page →\ \ Remove Request Headers Policy](/docs/policies/remove-headers-inbound "Remove Request Headers Policy") --- # Supabase JWT Auth Policy - Zuplo Docs Menu [​](#supabase-jwt-auth-policy) Supabase JWT Auth Policy ======================================================= The Supabase JWT Authentication policy allows you to authenticate incoming requests using a token created by [supabase.com](https://supabase.com) . When configured, you can have Zuplo check incoming requests for a JWT token and automatically populate the `ZuploRequest`'s `user` property with a user object. This `user` object will have a `sub` property - taking the `sub` id from the JWT token. It will also have a `data` property populated by other data returned in the JWT token - including all your claims, `user_metadata` and `app_metadata`. You can also require specific claims to have specific values to allow authentication to complete, providing a layer of authorization. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-supabase-jwt-auth-inbound-policy", "policyType": "supabase-jwt-auth-inbound", "handler": { "export": "SupabaseJwtInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "allowUnauthenticatedRequests": false, "requiredClaims": { "claim\_1": \["valid\_value\_1", "valid\_value\_2"\] }, "secret": "$env(SUPABASE\_JWT\_SECRET)" } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `supabase-jwt-auth-inbound`. * `handler.export` `` - The name of the exported type. Value should be `SupabaseJwtInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/supabase-jwt-auth-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `secret` **(required)** `` - The key used to verify the signature of the JWT token. * `allowUnauthenticatedRequests` `` - Indicates whether the request should continue if authentication fails. Default is `false` which means unauthenticated users will automatically receive a 401 response. Defaults to `false`. * `requiredClaims` `` - Any claims that must be present for authentication to succeed - multiple valid values can be specified for each claim. [​](#using-the-policy) Using the Policy --------------------------------------- [​](#authorization) Authorization --------------------------------- You can also require certain claims to be valid by specifying this in the options. For example, if you require the claim `user_role` to be either `admin` or `supa_user`, you would configure the policy as follows: { "export": "SupabaseJwtInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "secret": "$env(SUPABASE\_JWT\_SECRET)", "allowUnauthenticatedRequests": false, "requiredClaims": { "user\_role": \["admin", "supa\_user"\] } } } json Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ PropelAuth JWT Auth Policy](/docs/policies/propel-auth-jwt-inbound "PropelAuth JWT Auth Policy") [Next page →\ \ Curity Phantom Token Auth Policy](/docs/policies/curity-phantom-token-inbound "Curity Phantom Token Auth Policy") --- # Sleep / Delay Policy - Zuplo Docs Menu [​](#sleep--delay-policy) Sleep / Delay Policy ============================================== Add a delay to the incoming request. Useful for testing. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-sleep-inbound-policy", "policyType": "sleep-inbound", "handler": { "export": "SleepInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "sleepInMs": 1000 } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `sleep-inbound`. * `handler.export` `` - The name of the exported type. Value should be `SleepInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/sleep-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `sleepInMs` **(required)** `` - The number of milliseconds to delay the request. [​](#using-the-policy) Using the Policy --------------------------------------- Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Mock API Response Policy](/docs/policies/mock-api-inbound "Mock API Response Policy") [Next page →\ \ Transform Request Body Policy](/docs/policies/transform-body-inbound "Transform Request Body Policy") --- # Set Status Code Policy - Zuplo Docs Menu [​](#set-status-code-policy) Set Status Code Policy =================================================== Sets the status code on the on the outgoing response. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-set-status-outbound-policy", "policyType": "set-status-outbound", "handler": { "export": "SetStatusOutboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "status": 200, "statusText": "OK" } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `set-status-outbound`. * `handler.export` `` - The name of the exported type. Value should be `SetStatusOutboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/set-status-outbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `status` `` - The status code to be used in the response. * `statusText` `` - The statusText to be used in the response. [​](#using-the-policy) Using the Policy --------------------------------------- Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Set Headers Policy](/docs/policies/set-headers-outbound "Set Headers Policy") [Next page →\ \ XML to JSON Outbound Policy](/docs/policies/xml-to-json-outbound "XML to JSON Outbound Policy") --- # Upstream Firebase Admin Auth Policy - Zuplo Docs Menu [​](#upstream-firebase-admin-auth-policy) Upstream Firebase Admin Auth Policy ============================================================================= This policy adds a Firebase Admin token to the outgoing `Authentication` header allowing requests to Firebase using Service Account admin permissions. This can be useful for calling Firebase services such as Firestore through a Zuplo endpoint that is secured with other means of Authentication such as API keys. Additionally, this policy can be useful for service content to all API users (for example serving a specific Firestore document containing configuration data) We recommend reading the `serviceAccountJson` from environment variables (so it is not checked in to source control) using the `$env(ENV_VAR)` syntax. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-upstream-firebase-admin-auth-inbound-policy", "policyType": "upstream-firebase-admin-auth-inbound", "handler": { "export": "UpstreamFirebaseAdminAuthInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "expirationOffsetSeconds": 300, "serviceAccountJson": "$env(SERVICE\_ACCOUNT\_JSON)", "tokenRetries": 3 } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `upstream-firebase-admin-auth-inbound`. * `handler.export` `` - The name of the exported type. Value should be `UpstreamFirebaseAdminAuthInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/upstream-firebase-admin-auth-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `serviceAccountJson` **(required)** `` - The Google Service Account key in JSON format. Note you can load this from environment variables using the $env(ENV\_VAR) syntax. * `tokenRetries` `` - The number of times to retry fetching the token in the event of a failure. Defaults to `3`. * `expirationOffsetSeconds` `` - The number of seconds less than the token expiration to cache the token. Defaults to `300`. [​](#using-the-policy) Using the Policy --------------------------------------- Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Upstream GCP Self-Signed JWT Policy](/docs/policies/upstream-gcp-jwt-inbound "Upstream GCP Self-Signed JWT Policy") [Next page →\ \ Upstream Firebase User Auth Policy](/docs/policies/upstream-firebase-user-auth-inbound "Upstream Firebase User Auth Policy") --- # Upstream GCP Service Auth Policy - Zuplo Docs Menu [​](#upstream-gcp-service-auth-policy) Upstream GCP Service Auth Policy ======================================================================= This policy allows you to delegate authentication and authorization to your gateway without writing any code on your origin service by adding a GCP Issued ID Token to outgoing header allowing the service to be secured with GCP IAM. This is a useful means of securing your origin server so that only your Zuplo gateway can make requests against it. This policy works with [GCP Identity Aware Proxy](https://zuplo.com/docs/articles/gke-with-upstream-auth-policy) or services like [Cloud Run](https://cloud.google.com/iap/docs/managing-access) that natively support IAM authorization. We recommend reading the `serviceAccountJson` from environment variables (so it is not checked in to source control) using the `$env(ENV_VAR)` syntax. For information on how Google's service based auth works see [Authenticating for invocation](https://cloud.google.com/functions/docs/securing/authenticating) [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-upstream-gcp-service-auth-inbound-policy", "policyType": "upstream-gcp-service-auth-inbound", "handler": { "export": "UpstreamGcpServiceAuthInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "audience": "https://my-service-a2ev-uc.a.run.app", "scopes": \["https://www.googleapis.com/auth/cloud-platform"\], "serviceAccountJson": "$env(SERVICE\_ACCOUNT\_JSON)" } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `upstream-gcp-service-auth-inbound`. * `handler.export` `` - The name of the exported type. Value should be `UpstreamGcpServiceAuthInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/upstream-gcp-service-auth-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `audience` `` - The audience for the service to be called. This is typically the URL of your service endpoint like '[https://my-service-a2ev-uc.a.run.app](https://my-service-a2ev-uc.a.run.app) '. If calling a Google API, leave this empty. * `scopes` `` - The scopes to grant the access token. See [documentation](https://developers.google.com/identity/protocols/oauth2/scopes) for details. This is only set with calling a Google API. If calling a service like Cloud Run, etc. leave this empty. * `serviceAccountJson` **(required)** `` - The Google Service Account key in JSON format. Note you can load this from environment variables using the `$env(ENV_VAR)` syntax. * `tokenRetries` `` - The number of times to retry fetching the token in the event of a failure. Defaults to `3`. * `expirationOffsetSeconds` `` - The number of seconds less than the token expiration to cache the token. Defaults to `300`. * `useMemoryCacheOnly` `` - This is an advanced option that should only be used if you do not want to persist information in ZoneCache. * `version` `` - The version of the policy. Allowed values are `1`, `2`. Defaults to `1`. [​](#using-the-policy) Using the Policy --------------------------------------- This policy requires a Google Service Account and key that will be used to identify the Zuplo API Gateway. Once this policy is configured you will need to configure your GCP backend to only accept authenticated requests. ### [​](#create-the-gcp-service-account) Create the GCP Service Account The first thing you will need to do to use this policy is [create a service account](https://cloud.google.com/iam/docs/service-accounts-create) . You should create a unique service account for your Zuplo Gateway (i.e. `zuplo-gateway`). Give the account permission to call any services you want to proxy with Zuplo. Next, you will need to [create the Service Account key](https://cloud.google.com/iam/docs/keys-create-delete) (using the JSON format). The json file will download. Next, in your Zuplo project, set the `SERVICE_ACCOUNT_JSON` environment variable as a secret with the value of the downloaded JSON document. The value of the private key is a JSON file. **Before you save the file to Zuplo's environment variables**, you must remove all line breaks and all instances of the `\n` escape character. The JSON file should be a single line. ### [​](#configure-the-policy) Configure the Policy There are multiple uses for this policy. The way you are using this policy dictate the configuration options that need to be set. ### [​](#invoking-your-gcp-services) Invoking Your GCP Services When calling your own services like Cloud Run, authenticating using Identity Aware Proxy, or calling other services that you own, you will specify the `audience` property. When using this policy, you need to set the `audience` to the appropriate value depending on the service you are using. For backend's secured with Identity Aware Proxy, the value for `audience` should be the Client ID of your OAuth application. For backend's using Cloud Run IAM , the value for `audience` should be the full URL of the Cloud Run instance. An example configuration of this policy when calling Cloud Run is shown below. { "name": "gcp-service-auth", "policyType": "upstream-gcp-service-auth-inbound-policy", "handler": { "module": "$import(@zuplo/runtime)", "export": "UpstreamGcpServiceAuthInboundPolicy", "options": { "audience": "https://my-app-1235.a.run.app", "serviceAccountJson": "$env(GCP\_SERVICE\_ACCOUNT)" } } } json ### [​](#invoking-google-apis) Invoking Google APIs When using this policy to directly invoke a Google API (i.e. executing a [Workflow](https://cloud.google.com/workflows/docs/executing-workflow) the `scopes` property must be set. The scopes need to be set to the values each Google API call specifies. The way you can find the required scopes is usually to refer to Google's documentation. They typically have a section title [**Authorization scopes**](https://cloud.google.com/resource-manager/reference/rest/v1/projects/get#authorization-scopes) . The scopes will be in the format of a url. For example, `https://www.googleapis.com/auth/cloud-platform`. An example configuration of this policy when calling a Google Cloud API is shown below. { "name": "gcp-service-auth-gcloud-api", "policyType": "upstream-gcp-service-auth-inbound-policy", "handler": { "module": "$import(@zuplo/runtime)", "export": "UpstreamGcpServiceAuthInboundPolicy", "options": { "scopes": \[\ "https://www.googleapis.com/auth/cloud-platform",\ "https://www.googleapis.com/auth/cloud-platform.read-only",\ "https://www.googleapis.com/auth/cloudplatformprojects",\ "https://www.googleapis.com/auth/cloudplatformprojects.readonly"\ \], "serviceAccountJson": "$env(GCP\_SERVICE\_ACCOUNT)" } } } json Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Upstream Azure AD Service Auth Policy](/docs/policies/upstream-azure-ad-service-auth-inbound "Upstream Azure AD Service Auth Policy") [Next page →\ \ Upstream GCP Federated Auth Policy](/docs/policies/upstream-gcp-federated-auth-inbound "Upstream GCP Federated Auth Policy") --- # Add or Set Query Parameters Policy - Zuplo Docs Menu [​](#add-or-set-query-parameters-policy) Add or Set Query Parameters Policy =========================================================================== Adds or sets query parameters on the incoming request. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-set-query-params-inbound-policy", "policyType": "set-query-params-inbound", "handler": { "export": "SetQueryParamsInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "params": \[\ {\ "name": "my-key",\ "value": "my-value"\ }\ \] } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `set-query-params-inbound`. * `handler.export` `` - The name of the exported type. Value should be `SetQueryParamsInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/set-query-params-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `params` **(required)** `` - An array of query params to set in the request. By default, query parameters will be overwritten if they already exist in the request, specify the overwrite property to change this behavior. * `name` **(required)** `` - The name of the param. * `value` **(required)** `` - The value of the param. * `overwrite` `` - Overwrite the value if the param is already present in the request. Defaults to `true`. [​](#using-the-policy) Using the Policy --------------------------------------- Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Set Body Policy](/docs/policies/set-body-inbound "Set Body Policy") [Next page →\ \ Transform Response Body Policy](/docs/policies/transform-body-outbound "Transform Response Body Policy") --- # Set Body Policy - Zuplo Docs Menu [​](#set-body-policy) Set Body Policy ===================================== The Set Body policy allows you to set or override the incoming request body. [GET or HEAD requests do not support bodies on Zuplo](https://zuplo.com/docs/articles/zp-body-removed) , so be sure to use the [Change Method](https://zuplo.com/docs/policies/change-method-inbound) policy to update the method to a `POST` or whatever is appropriate. You might also need to use the [Set Header](https://zuplo.com/docs/policies/set-headers-inbound) policy to set a `content-type`. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-set-body-inbound-policy", "policyType": "set-body-inbound", "handler": { "export": "SetBodyInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "body": "Hello World!" } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `set-body-inbound`. * `handler.export` `` - The name of the exported type. Value should be `SetBodyInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/set-body-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `body` **(required)** `` - The value to set for the body. [​](#using-the-policy) Using the Policy --------------------------------------- Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Add or Set Request Headers Policy](/docs/policies/set-headers-inbound "Add or Set Request Headers Policy") [Next page →\ \ Add or Set Query Parameters Policy](/docs/policies/set-query-params-inbound "Add or Set Query Parameters Policy") --- # Set Headers Policy - Zuplo Docs Menu [​](#set-headers-policy) Set Headers Policy =========================================== Adds or sets headers on the on the outgoing response. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-set-headers-outbound-policy", "policyType": "set-headers-outbound", "handler": { "export": "SetHeadersOutboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "headers": \[\ {\ "name": "my-header",\ "value": "my-value"\ }\ \] } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `set-headers-outbound`. * `handler.export` `` - The name of the exported type. Value should be `SetHeadersOutboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/set-headers-outbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `headers` **(required)** `` - An array of headers to set on the response. By default, headers will be overwritten if they already exists in the response, specify the overwrite property to change this behavior. * `name` **(required)** `` - The name of the header. * `value` **(required)** `` - The value of the header. * `overwrite` `` - Overwrite the value if the header is already present in the response. Defaults to `true`. [​](#using-the-policy) Using the Policy --------------------------------------- Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Clear Response Headers Policy](/docs/policies/clear-headers-outbound "Clear Response Headers Policy") [Next page →\ \ Set Status Code Policy](/docs/policies/set-status-outbound "Set Status Code Policy") --- # Add or Set Request Headers Policy - Zuplo Docs Menu [​](#add-or-set-request-headers-policy) Add or Set Request Headers Policy ========================================================================= The set header policy adds a header to the request in the inbound pipeline. This can be used to set a security header required by the downstream service. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-set-headers-inbound-policy", "policyType": "set-headers-inbound", "handler": { "export": "SetHeadersInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "headers": \[\ {\ "name": "my-custom-header",\ "value": "test"\ }\ \] } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `set-headers-inbound`. * `handler.export` `` - The name of the exported type. Value should be `SetHeadersInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/set-headers-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `headers` **(required)** `` - An array of headers to set in the request. By default, headers will be overwritten if they already exists in the request, specify the overwrite property to change this behavior. * `name` **(required)** `` - The name of the header. * `value` **(required)** `` - The value of the header. * `overwrite` `` - Overwrite the value if the header is already present in the request. Defaults to `true`. [​](#using-the-policy) Using the Policy --------------------------------------- An example for using this policy is if your backend service uses basic authentication you might use this policy to attach the Basic auth header to the request: { "export": "SetHeadersInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "headers": \[\ {\ "name": "Authorization",\ "value": "Basic DIGEST\_HERE",\ "overwrite": true\ }\ \] } } json When doing this, you most likely want to set the secret as an environment variable, which can be accessed in the policy as follows { "export": "SetHeadersInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "headers": \[\ {\ "name": "Authorization",\ "value": "$env(BASIC\_AUTHORIZATION\_HEADER\_VALUE)",\ "overwrite": true\ }\ \] } } json And you would set the environment variable `BASIC_AUTHORIZATION_HEADER_VALUE` to `Basic DIGEST_HERE`. Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Remove Query Parameters Policy](/docs/policies/remove-query-params-inbound "Remove Query Parameters Policy") [Next page →\ \ Set Body Policy](/docs/policies/set-body-inbound "Set Body Policy") --- # Replace String in Response Body Policy - Zuplo Docs Menu [​](#replace-string-in-response-body-policy) Replace String in Response Body Policy =================================================================================== Replace a string in the incoming request body [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-replace-string-outbound-policy", "policyType": "replace-string-outbound", "handler": { "export": "ReplaceStringOutboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "match": "/(\\\\d+)/g", "mode": "regexp", "replaceWith": "1234" } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `replace-string-outbound`. * `handler.export` `` - The name of the exported type. Value should be `ReplaceStringOutboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/replace-string-outbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `mode` **(required)** `` - The type of string replacement to perform. Allowed values are `regexp`, `string`. * `match` **(required)** `` - The pattern to match. * `replaceWith` **(required)** `` - The value to each match is replaced with. [​](#using-the-policy) Using the Policy --------------------------------------- Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ XML to JSON Outbound Policy](/docs/policies/xml-to-json-outbound "XML to JSON Outbound Policy") [Next page →\ \ Upstream Azure AD Service Auth Policy](/docs/policies/upstream-azure-ad-service-auth-inbound "Upstream Azure AD Service Auth Policy") --- # Remove Request Headers Policy - Zuplo Docs Menu [​](#remove-request-headers-policy) Remove Request Headers Policy ================================================================= Remove headers from the incoming request. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-remove-headers-inbound-policy", "policyType": "remove-headers-inbound", "handler": { "export": "RemoveHeadersInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "headers": \["x-request-id", "content-type"\] } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `remove-headers-inbound`. * `handler.export` `` - The name of the exported type. Value should be `RemoveHeadersInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/remove-headers-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `headers` **(required)** `` - An array of headers to remove from the incoming request. [​](#using-the-policy) Using the Policy --------------------------------------- Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Transform Request Body Policy](/docs/policies/transform-body-inbound "Transform Request Body Policy") [Next page →\ \ Clear Request Headers Policy](/docs/policies/clear-headers-inbound "Clear Request Headers Policy") --- # Request Size Limit Policy - Zuplo Docs Menu [​](#request-size-limit-policy) Request Size Limit Policy ========================================================= Enforces a maximum size in bytes of the incoming request. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-request-size-limit-inbound-policy", "policyType": "request-size-limit-inbound", "handler": { "export": "RequestSizeLimitInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "maxSizeInBytes": 10000 } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `request-size-limit-inbound`. * `handler.export` `` - The name of the exported type. Value should be `RequestSizeLimitInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/request-size-limit-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `maxSizeInBytes` **(required)** `` - The maximum size of the request in bytes. * `trustContentLengthHeader` `` - If true, the policy will reject any request with a `content-length` header in excess of `maxSizeInBytes` bytes value, but will not verify the actual size of the request. This is more efficient and offers slightly better memory usage but should only be used if you trust/control the clients calling the gateway to send an accurate content-length. If false, the gateway will actually verify the request size and reject any request with a size in excess of the stated maximum. [​](#using-the-policy) Using the Policy --------------------------------------- Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Require Origin Policy](/docs/policies/require-origin-inbound "Require Origin Policy") [Next page →\ \ Stripe Webhook Auth Policy](/docs/policies/stripe-webhook-verification-inbound "Stripe Webhook Auth Policy") --- # Require Origin Policy - Zuplo Docs Menu [​](#require-origin-policy) Require Origin Policy ================================================= The Require Origin policy is used to enforce that the client is sending an `origin` header that matches your allow-list specified in the policy options. This is useful if you want to stop any browser traffic from different domains. However, it is important to note that it does not guarantee that traffic is only coming from a browser. Somebody could simulate a browser request from a backend server and set any origin they like. If the incoming origin is missing, or not allowed - a 400 Forbidden Problem Response will be sent to the client. You can customize the `detail` property in the policy options. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-require-origin-inbound-policy", "policyType": "require-origin-inbound", "handler": { "export": "RequireOriginInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "failureDetail": "Your origin is not authorized to make this request.", "origins": "https://example.com, https://example.org" } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `require-origin-inbound`. * `handler.export` `` - The name of the exported type. Value should be `RequireOriginInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/require-origin-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `origins` **(required)** `` - A comma separated string containing valid origins. * `failureDetail` `` - The `detail` of the HTTP Problem response, if the origin is missing or disallowed. Defaults to `"Forbidden"`. [​](#using-the-policy) Using the Policy --------------------------------------- Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Bot Detection Policy](/docs/policies/bot-detection-inbound "Bot Detection Policy") [Next page →\ \ Request Size Limit Policy](/docs/policies/request-size-limit-inbound "Request Size Limit Policy") --- # Request Validation Policy - Zuplo Docs Menu [​](#request-validation-policy) Request Validation Policy ========================================================= The Request Validation policy is used to validate incoming requests based on schemas in OpenAPI specifications. When configured, any requests that do not conform to your OpenAPI schema will be rejected with a `400: Bad Request` response containing a detailed error message (in JSON) explaining why the request was not accepted. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-request-validation-inbound-policy", "policyType": "request-validation-inbound", "handler": { "export": "RequestValidationInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "includeRequestInLogs": false, "logLevel": "info", "validateBody": "reject-and-log", "validatePathParameters": "log-only", "validateQueryParameters": "log-only" } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `request-validation-inbound`. * `handler.export` `` - The name of the exported type. Value should be `RequestValidationInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/request-validation-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `logLevel` `` - The log level to use when logging validation errors. Allowed values are `error`, `warn`, `info`, `debug`. Defaults to `"info"`. * `validateBody` `` - The action to perform when validation fails. Allowed values are `none`, `log-only`, `reject-and-log`, `reject-only`. * `validateQueryParameters` `` - The action to perform when validation fails. Allowed values are `none`, `log-only`, `reject-and-log`, `reject-only`. * `validatePathParameters` `` - The action to perform when validation fails. Allowed values are `none`, `log-only`, `reject-and-log`, `reject-only`. * `validateHeaders` `` - The action to perform when validation fails. Allowed values are `none`, `log-only`, `reject-and-log`, `reject-only`. * `includeRequestInLogs` `` - Whether to include the request in the logs. Defaults to `false`. [​](#using-the-policy) Using the Policy --------------------------------------- Here's an example of how to specify a schema for validation in a request body in OpenAPI. "requestBody": { "description": "user to add to the system", "content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string" }, "age": { "type": "integer" } }, "required": \[\ "name",\ "age"\ \] } } } } json Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Audit Logs Policy](/docs/policies/audit-log-inbound "Audit Logs Policy") [Next page →\ \ Bot Detection Policy](/docs/policies/bot-detection-inbound "Bot Detection Policy") --- # Remove Query Parameters Policy - Zuplo Docs Menu [​](#remove-query-parameters-policy) Remove Query Parameters Policy =================================================================== Remove query parameters from the incoming request [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-remove-query-params-inbound-policy", "policyType": "remove-query-params-inbound", "handler": { "export": "RemoveQueryParamsInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "params": \["param1", "param2"\] } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `remove-query-params-inbound`. * `handler.export` `` - The name of the exported type. Value should be `RemoveQueryParamsInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/remove-query-params-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `params` **(required)** `` - An array of query parameters to be removed from the incoming request. [​](#using-the-policy) Using the Policy --------------------------------------- Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Form Data to JSON Policy](/docs/policies/formdata-to-json-inbound "Form Data to JSON Policy") [Next page →\ \ Add or Set Request Headers Policy](/docs/policies/set-headers-inbound "Add or Set Request Headers Policy") --- # RBAC Authorization Policy - Zuplo Docs Menu [​](#rbac-authorization-policy) RBAC Authorization Policy ========================================================= ### Custom Policy Example Zuplo is extensible, so we don't have a built-in policy for RBAC Authorization, instead we've a template here that shows you how you can use your superpower (code) to achieve your goals. To learn more about custom policies [see the documentation](/docs/policies/custom-code-inbound) . RBAC policies can be built many ways depending on your requirements. This example shows how to perform a simple check of whether or not the current user is a member of a set of allowed roles. import { HttpProblems, ZuploContext, ZuploRequest } from "@zuplo/runtime"; interface PolicyOptions { allowedRoles: string\[\]; } export default async function ( request: ZuploRequest, context: ZuploContext, options: PolicyOptions, policyName: string, ) { // Check that an authenticated user is set // NOTE: This policy requires an authentication policy to run before if (!request.user) { context.log.error( "User isn't authenticated. A authorization policy must come before the RBAC policy.", ); return HttpProblems.unauthorized(request, context); } // Check that the user has roles if (!request.user.data.roles) { context.log.error("The user isn't assigned any roles."); return HttpProblems.unauthorized(request, context); } // Check that the user has one of the allowed roles if ( !options.allowedRoles.some((allowedRole) => request.user?.data.roles.includes(allowedRole), ) ) { context.log.error( \`The user '${request.user.sub}' isn't authorized to perform this action.\`, ); return HttpProblems.forbidden(request, context); } // If they made it here, they are authorized return request; } ts [​](#configuration) Configuration --------------------------------- The example below shows how to configure a custom code policy in the 'policies.json' document that utilizes the above example policy code. { "name": "my-rbac-policy-inbound-policy", "policyType": "rbac-policy-inbound", "handler": { "\_name": "basic", "export": "default", "module": "$import(./modules/YOUR\_MODULE)", "options": { "allowedRoles": \["admin", "editor"\] } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `rbac-policy-inbound`. * `handler.export` `` - The name of the exported type. Value should be `default`. * `handler.module` `` - The module containing the policy. Value should be `$import(./modules/YOUR_MODULE)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/rbac-policy-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `allowedRoles` `` - The roles allowed to access the resource Defaults to `[]`. [​](#using-the-policy) Using the Policy --------------------------------------- Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Access Control List Policy](/docs/policies/acl-policy-inbound "Access Control List Policy") [Next page →\ \ Geo-location filtering Policy](/docs/policies/geo-filter-inbound "Geo-location filtering Policy") --- # Remove Response Headers Policy - Zuplo Docs Menu [​](#remove-response-headers-policy) Remove Response Headers Policy =================================================================== Remove configured headers from the outgoing response. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-remove-headers-outbound-policy", "policyType": "remove-headers-outbound", "handler": { "export": "RemoveHeadersOutboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "headers": \["x-amz-content-sha256", "x-amz-date"\] } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `remove-headers-outbound`. * `handler.export` `` - The name of the exported type. Value should be `RemoveHeadersOutboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/remove-headers-outbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `headers` **(required)** `` - An array of headers to be removed from the outgoing response. [​](#using-the-policy) Using the Policy --------------------------------------- Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Transform Response Body Policy](/docs/policies/transform-body-outbound "Transform Response Body Policy") [Next page →\ \ Clear Response Headers Policy](/docs/policies/clear-headers-outbound "Clear Response Headers Policy") --- # Readme Metrics Policy - Zuplo Docs Menu [​](#readme-metrics-policy) Readme Metrics Policy ================================================= [Readme](https://readme.com) is a developer Documentation and metrics service. This policy pushes the request/response data to their ingestion endpoint so you can see your Zuplo API traffic in their API calls dashboard. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-readme-metrics-inbound-policy", "policyType": "readme-metrics-inbound", "handler": { "export": "ReadmeMetricsInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "apiKey": "$env(README\_API\_KEY)", "url": "https://metrics.readme.io/request", "useFullRequestPath": false, "userEmailPropertyPath": "" } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `readme-metrics-inbound`. * `handler.export` `` - The name of the exported type. Value should be `ReadmeMetricsInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/readme-metrics-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `apiKey` **(required)** `` - The API key to use when sending metrics calls to Readme. * `userLabelPropertyPath` `` - This is the path to the property on `request.user` that contains the label you want to use. For example `.data.accountNumber` would read the `request.user.data.accountNumber` property. Defaults to `".sub"`. * `userEmailPropertyPath` `` - This is the path to the property on `request.user` that contains the e-mail of the user. For example `.data.email` would read the `request.user.data.email` property. Defaults to `""`. * `development` `` - Whether the data should be ingested as 'development' mode or not. Defaults to true for working-copy and false for all other environments. * `useFullRequestPath` `` - When true, Zuplo sends the full request path (which might contain sensitive information). By default, we only send the route path which should not contain sensitive information. Defaults to `false`. * `url` `` - The URL to send metering events. This is useful for testing purposes. Defaults to `"https://metrics.readme.io/request"`. [​](#using-the-policy) Using the Policy --------------------------------------- ![Readme API Calls Dashboard](https://cdn.zuplo.com/assets/071b2ead-7769-413b-a66a-133ae6fd755d.png) Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Amberflo Metering / Billing Policy](/docs/policies/amberflo-metering-inbound "Amberflo Metering / Billing Policy") [Next page →\ \ A/B Test Inbound Policy](/docs/policies/ab-test-inbound "A/B Test Inbound Policy") --- # Quota Policy - Zuplo Docs Menu [​](#quota-policy) Quota Policy =============================== You can use the Quota policy to limit the number of requests that are allowed to happen in a given time period (e.g., monthly). The policy can be applied the users or based on custom keys. It supports `monthly`, `weekly`, `daily` and `hourly` quotas. By default a `requests` meter is incremented by 1 for every request but you can also quota by other arbitrary meters; more on this below. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-quota-inbound-policy", "policyType": "quota-inbound", "handler": { "export": "QuotaInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "allowances": { "requests": 10 }, "period": "monthly", "quotaBy": "user", "quotaOnStatusCodes": "200-399" } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `quota-inbound`. * `handler.export` `` - The name of the exported type. Value should be `QuotaInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/quota-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `period` **(required)** `` - The period of the quota. Allowed values are `hourly`, `daily`, `weekly`, `monthly`. * `quotaBy` **(required)** `` - The quota by. Allowed values are `user`, `function`. Defaults to `"user"`. * `quotaAnchorMode` `` - How the policy determines the anchor date for ongoing quota cycles - defaults to `first-api-call` which uses the first API call for this key. Allowed values are `first-api-call`, `function`. Defaults to `"first-api-call"`. * `allowances` `` - The allowances for the quota. * `quotaOnStatusCodes` `` - A list of successful status codes and ranges "200-299, 304" that should trigger a quota increment. Defaults to `"200-299"`. * `identifier` `` - The module and functions to dynamically set the anchor date and/or the key/allowances for this request. * `module` **(required)** `` - Specifies the module to load your custom functions, in the format `$import(./modules/my-module)`. Defaults to `"$import(./modules/my-module)"`. * `getAnchorDateExport` `` - used when quotaAnchorMode is `function`. Specifies the export to load your custom function to get the anchor date. Defaults to `"getAnchorDate"`. * `getQuotaDetailExport` `` - used when quotaBy is `function`. Specifies the export to load your custom function to get the quota detail. Defaults to `"getQuotaDetail"`. [​](#using-the-policy) Using the Policy --------------------------------------- The Quota policy needs to know when to anchor the quota start date so that the Zuplo runtime can know where in the quota cycle you are. By default the runtime uses the `"quotaAnchorMode": "first-api-call"` which checks to see if we have an existing quota record for this user or custom quota key and, if not, sets it based on the time of the first API call for this key. You can customize the subscription date by setting the `getAnchorDateExport` function, more below under **Custom Anchor Date**. [​](#quota-cycles--periods) Quota Cycles / Periods -------------------------------------------------- The quota periods run from the anchor date and **time** until the next matching cycle. For `monthly` periods, if the anchor date is `2024-01-31 04:30Z` then the quota cycle will terminate on the same day of the next month or the last day of that month if it is a shorter month, at the same time. In this case the quota cycle will reset on `2024-02-29 04:30Z` (because 2024 is a leap year). `weekly` cycles shift on the same day of the next week, at the same time. `daily` on the next day, at the same time. `hourly` on the same minute, of the next hour. [​](#custom-meters) Custom Meters --------------------------------- You can set custom meters in the allowances property of the options to include custom meters other than `requests`. For example, here we set a monthly allowance of 10 `bananas`. { "name": "my-quota-inbound-policy", "policyType": "quota-inbound", "handler": { "export": "QuotaInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "period": "monthly", "quotaBy": "user", "allowances": { "bananas": 10 } } } } json For this to work you must tell the runtime how many `bananas` to increment in a given request/response lifecycle. This is achieved by using the `setMeters` method on the `QuotaInboundPolicy` class: import { QuotaInboundPolicy } from "@zuplo/runtime"; // ... QuotaInboundPolicy.setMeters(context, { bananas: 5, oranges: 3 }); ts This is typically invoked in a custom inbound or outbound policy or a handler.s [​](#dynamic-quota-allowances-and-keys) Dynamic Quota Allowances and Keys ------------------------------------------------------------------------- Like **Dynamic Rate Limiting**, Quota Keys and allowances can also be set dynamically in Zuplo. This is achieved by setting the `identifier` module and `getQuotaDetailExport` in your options: { "name": "my-quota-inbound-policy", "policyType": "quota-inbound", "handler": { "export": "QuotaInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "identifier": { "getQuotaDetailExport": "getQuotaDetail", "module": "$import(./modules/my-module)" }, "quotaAnchorMode": "first-api-call", // Note this must be 'function' when using a custom detail function "quotaBy": "function" } } } json If you wanted to key on a property from the user metadata, like organizationId you might have a `getQuotaDetail` implementation that looks like this. // ./modules/my-module.ts import { GetQuotaDetailFunction } from "@zuplo/runtime"; export const getQuotaDetail: GetQuotaDetailFunction = async ( request, context, policyName, ) => { return { key: request.user.data.organizationId, allowances: { bananas: 100, }, }; }; ts Note that this method supports async calls and could be used to load quotas from another API, but we would recommend caching the results for performance reasons. [​](#custom-anchor-date) Custom Anchor Date ------------------------------------------- Similarly, the Anchor Date can be set programmatically - for example you may load the 'subscription' start date from another database or API. { "name": "my-quota-inbound-policy", "policyType": "quota-inbound", "handler": { "export": "QuotaInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "identifier": { "getAnchorDateExport": "getQuotaDetail", "module": "$import(./modules/my-module)" }, // Note this must be 'function' when using a custom anchor date "quotaAnchorMode": "function", "quotaBy": "user" } } } json // ./modules/my-module.ts import { GetQuotaAnchorDateFunction } from "@zuplo/runtime"; export const getAnchorDate: GetQuotaAnchorDateFunction = async ( request, context, policyName, ) => { // simple example fetch call, needs error handling, auth etc. const response = await fetch( \`https://my-subs-api/subs/${request.user.data.organizationId}\`, ); const data = await response.json(); return new Date(data.startDate); }; ts [​](#get-usage) Get Usage ------------------------- You can also programmatically access the usage counts with the `getUsage` static function on `QuotaInboundPolicy`. This call **must** occur **after** the Quota-Inbound policy has executed. const usage = QuotaInboundPolicy.getUsage(context, 'quota-policy-name'); context.log.info(usage); // This would generate the following output: { anchorDate: string; nextResetDate: string; meters: Record; } // example { anchorDate: "2023-08-20T03:05:05.493Z", nextResetDate: "2024-08-20T03:05:05.493Z", meters: { requests: 1, bananas: 10 } } ts Note that if the quota has not yet been updated for a particular meter, the meter will be undefined in the response. Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Stripe Webhook Auth Policy](/docs/policies/stripe-webhook-verification-inbound "Stripe Webhook Auth Policy") [Next page →\ \ Moesif Analytics & Billing Policy](/docs/policies/moesif-inbound "Moesif Analytics & Billing Policy") --- # Rate Limiting Policy - Zuplo Docs Menu [​](#rate-limiting-policy) Rate Limiting Policy =============================================== Rate-limiting allows you to set a maximum rate of requests for your API gateway. This is useful to enforce rate limits agreed with your clients and protect your downstream services. The Zuplo Rate-Limit allows you to limit based on different attributes of the incoming request. For example, you might set a rate limit of 10 requests per second per user, or 20 requests per second for a given IP address. The Zuplo rate-limiter also allows you to set a custom bucket name by which to effect a rate-limit using a function. When a client reaches a rate limit - they will receive a `429` response code. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-rate-limit-inbound-policy", "policyType": "rate-limit-inbound", "handler": { "export": "RateLimitInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "rateLimitBy": "ip", "requestsAllowed": 2, "timeWindowMinutes": 1 } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `rate-limit-inbound`. * `handler.export` `` - The name of the exported type. Value should be `RateLimitInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/rate-limit-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `rateLimitBy` **(required)** `` - The identifying element of the request that enforces distinct rate limits. For example, you can limit by `user`, `ip`, `function` or `all` - function allows you to specify a simple function to create a string identifier to create a rate-limit group. Allowed values are `user`, `ip`, `function`, `all`. Defaults to `"user"`. * `requestsAllowed` **(required)** `` - The max number of requests allowed in the given time window. Defaults to `1000`. * `timeWindowMinutes` **(required)** `` - The time window in which the requests are rate-limited. The count restarts after each window expires. Defaults to `60`. * `identifier` `` - The function that returns dynamic configuration data. Used only with `rateLimitBy=function`. * `export` **(required)** `` - used only with rateLimitBy=function. Specifies the export to load your custom bucket function, e.g. `default`, `rateLimitIdentifier`. Defaults to `"$import(./modules/my-module)"`. * `module` **(required)** `` - Specifies the module to load your custom bucket function, in the format `$import(./modules/my-module)`. Defaults to `""`. * `headerMode` `` - Adds the retry-after header. Allowed values are `none`, `retry-after`. Defaults to `"retry-after"`. * `throwOnFailure` `` - If true, the policy will throw an error in the event there is a problem connecting to the rate limit service. Defaults to `false`. * `mode` `` - The mode of the policy. If set to `async`, the policy will check if the request is over the rate limit without blocking. This can result in some requests allowed over the rate limit. Allowed values are `strict`, `async`. Defaults to `"strict"`. [​](#using-the-policy) Using the Policy --------------------------------------- Note you can have multiple instances of rate-limiting policies to use in combination. You should apply the longest duration timeWindow first, in order to the shortest duration time window. [​](#using-a-custom-function) Using a custom function ----------------------------------------------------- You can create a rate-limit bucket based on any property of a request using a custom function that returns a `CustomRateLimitDetails` object (which provides the identifier used by the limiting system). The `CustomRateLimitDetails` object can be used to override the `timeWindowMinutes` & `requestsAllowed` options. This example would create a unique rate-limiting function based on the `customerId` parameter in routes (note it’s important that a policy like this is applied to a route that has a `/:customerId` parameter). //module - ./modules/rate-limiter.ts import { CustomRateLimitDetails, ZuploRequest, ZuploContext, } from "@zuplo/runtime"; export function rateLimitKey( request: ZuploRequest, context: ZuploContext, policyName: string, ): CustomRateLimitDetails | undefined { context.log.info( \`processing customerId '${request.params.customerId}' for rate-limit policy '${policyName}'\`, ); if (request.params.customerId === "43567890") { // Override timeWindowMinutes & requestsAllowed return { key: request.params.customerId, requestsAllowed: 100, timeWindowMinutes: 1, }; } } ts // config - ./config/policies.json "export": "RateLimitInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "rateLimitBy": "function", "requestsAllowed": 2, "timeWindowMinutes": 1, "identifier": { "module": "$import(./modules/rate-limiter)", "export": "rateLimitKey" } } json Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ IP Restriction Policy](/docs/policies/ip-restriction-inbound "IP Restriction Policy") [Next page →\ \ Complex Rate Limiting Policy](/docs/policies/complex-rate-limit-inbound "Complex Rate Limiting Policy") --- # PropelAuth JWT Auth Policy - Zuplo Docs Menu [​](#propelauth-jwt-auth-policy) PropelAuth JWT Auth Policy =========================================================== Authenticate requests with JWT tokens issued by [PropelAuth](https://propelauth.com) . This is a customized version of the [OpenId JWT Policy](https://zuplo.com/docs/policies/open-id-jwt-auth-inbound) specifically for PropelAuth. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-propel-auth-jwt-inbound-policy", "policyType": "propel-auth-jwt-inbound", "handler": { "export": "PropelAuthJwtInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "allowUnauthenticatedRequests": false, "authUrl": "https://6587563.propelauthtest.com", "verifierKey": "$env(PROPEL\_VERIFIER\_KEY)" } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `propel-auth-jwt-inbound`. * `handler.export` `` - The name of the exported type. Value should be `PropelAuthJwtInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/propel-auth-jwt-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `allowUnauthenticatedRequests` `` - Allow unauthenticated requests to proceed. This is use useful if you want to use multiple authentication policies or if you want to allow both authenticated and non-authenticated traffic. Defaults to `false`. * `authUrl` **(required)** `` - Your PropelAuth authUrl. For example, `https://6587563.propelauthtest.com`. * `verifierKey` **(required)** `` - Your public (verifier) key that is used to verify access tokens. This key has a value that begins with '-----BEGIN PUBLIC KEY-----'. Make sure to remove all line breaks from the key before saving the variable. [​](#using-the-policy) Using the Policy --------------------------------------- Adding PropelAuth to your route takes just a few steps, but before you can add the policy you'll need to have PropelAuth setup for API Authentication. ### [​](#setup-propelauth) Setup PropelAuth You'll need a [PropelAuth](https://www.propelauth.com/) account to use this policy. If you don't already have a client to call your API, the easiest thing to do is start with one of the [PropelAuth examples](https://docs.propelauth.com/example-apps/apps) such as the [React example](https://www.propelauth.com/post/react-express-starter-app) . Follow the instructions for setting up the example, then you can change the authenticated API the example calls with your Zuplo API or just use the example to get an access token. ### [​](#set-environment-variables) Set Environment Variables Before adding the policy, there are a few environment variables that will need to be set that will be used in the PropelAuth JWT Policy. 1. In the [Zuplo Portal](https://portal.zuplo.com) open the **Environment Variables** section in the **Settings** tab. 2. Click **Add new Variable** and enter the name `PROPEL_AUTH_URL` in the name field. Set the value to your PropelAuth Auth URL. You can find this value in the **Backend Integration** tab in the PropelAuth portal. 3. Click **Add new Variable** and enter the name `PROPEL_VERIFIER_KEY` in the name field. Set the value to your PropelAuth Public (Verifier) Key. You can find this value in the **Backend Integration** tab in the PropelAuth portal. ### [​](#add-the-propelauth-jwt-policy) Add the PropelAuth JWT Policy The next step is to add the PropelAuth JWT policy to a route in your project. 1. In the [Zuplo Portal](https://portal.zuplo.com) open the **Route Designer** in the **Files** tab then click **routes.oas.json**. 2. Select or create a route that you want to authenticate with PropelAuth. Expand the **Policies** section and click **Add Policy**. Search for and select the PropelAuth JWT Auth policy. ![](https://cdn.zuplo.com/assets/7fc2c436-c0a2-42cb-95d8-8425c88f5948.png) 3. With the policy selected, notice that there are two properties, `authUrl` and `verifierKey` that are pre-populated with environment variable names that you set in the previous section. ![](https://cdn.zuplo.com/assets/49bd02eb-3d71-436b-a9bc-3ecca9222111.png) 4. Click **OK** to save the policy. ### [​](#test-the-policy) Test the Policy Finally, you'll make two API requests to your route to test that authentication is working as expected. 1. In the route designer on the route you added the policy, click the **Test** button. In the dialog that opens, click **Test** to make a request. 2. The API Gateway should respond with a **401 Unauthorized** response. ![](https://cdn.zuplo.com/assets/626e10a2-2350-439a-9081-1ccf1fe90cad.png) 3. Now to make an authenticated request, add a header to the request called `Authorization`. Set the value of the header to `Bearer YOUR_ACCESS_TOKEN` replacing `YOUR_ACCESS_TOKEN` with the value of the Auth0 access token you saved from the first section of this tutorial. ![](https://cdn.zuplo.com/assets/1486821b-cade-4041-b05b-80d3366327a5.png) 4. Click the **Test** button and a **200 OK** response should be returned. ![](https://cdn.zuplo.com/assets/8182f932-8db6-4456-842f-f65158b174c0.png) You have now setup PropelAuth JWT Authentication on your API Gateway. See [this document](/docs/articles/oauth-authentication) for more information about OAuth authorization in Zuplo. Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ JWT Auth Policy](/docs/policies/open-id-jwt-auth-inbound "JWT Auth Policy") [Next page →\ \ Supabase JWT Auth Policy](/docs/policies/supabase-jwt-auth-inbound "Supabase JWT Auth Policy") --- # Okta FGA Authorization Policy - Zuplo Docs Menu [​](#okta-fga-authorization-policy) Okta FGA Authorization Policy ================================================================= This policy will authorize requests using Okta FGA. If the request is not authorized, a 403 response will be returned. ### Beta This policy is in beta. You can use it today, but it may change in non-backward compatible ways before the final release. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-okta-fga-authz-inbound-policy", "policyType": "okta-fga-authz-inbound", "handler": { "export": "OktaFGAAuthZInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "authorizationModelId": "$env(FGA\_MODEL\_ID)", "credentials": { "clientId": "$env(FGA\_CLIENT\_ID)", "clientSecret": "$env(FGA\_CLIENT\_SECRET)" }, "region": "us1", "storeId": "$env(FGA\_STORE\_ID)" } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `okta-fga-authz-inbound`. * `handler.export` `` - The name of the exported type. Value should be `OktaFGAAuthZInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/okta-fga-authz-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `region` **(required)** `` - The region your store is deployed. Allowed values are `us1`, `eu1`, `au1`. * `storeId` **(required)** `` - The ID of the store. * `authorizationModelId` **(required)** `` - The ID of the authorization model. * `allowUnauthorizedRequests` `` - Indicates whether the request should continue if authorization fails. Default is `false` which means unauthorized users will automatically receive a 403 response. Defaults to `false`. * `credentials` **(required)** `` - No description available. * `clientId` **(required)** `` - The client ID. * `clientSecret` **(required)** `` - The client secret. [​](#using-the-policy) Using the Policy --------------------------------------- [​](#usage) Usage ----------------- To use this policy, you must programmatically set the relationship checks to be performed against your Okta FGA store. This is done using the static `setContextChecks` method. The most common way to set the authorization checks are: 1. Creating custom inbound policies for each authorization scenario 2. Creating a custom inbound policy that reads data from the OpenAPI operation and sets the authorization checks dynamically ### [​](#example-custom-authorization-policies) Example: Custom Authorization Policies Create a file like `modules/oktafga-checks.ts` to define your custom authorization policies: import { ZuploRequest, ZuploContext, RuntimeError, HttpProblems, OktaFGAAuthZInboundPolicy, } from "@zuplo/runtime"; export async function canReadFolder( request: ZuploRequest, context: ZuploContext, ) { if (!request.params?.folderId) { throw new RuntimeError("Folder ID not found in request"); } context.log.info("Setting OktaFGA context checks"); if (!request.user?.sub) { return HttpProblems.forbidden(request, context, { detail: "User not found", }); } // Set the authorization check to verify if the user has viewer access to the folder OktaFGAAuthZInboundPolicy.setContextChecks(context, { user: \`user:${request.user.sub}\`, relation: "viewer", object: \`folder:${request.params.folderId}\`, }); return request; } export async function canEditDocument( request: ZuploRequest, context: ZuploContext, ) { if (!request.params?.documentId) { throw new RuntimeError("Document ID not found in request"); } if (!request.user?.sub) { return HttpProblems.forbidden(request, context, { detail: "User not found", }); } // Set the authorization check to verify if the user has editor access to the document OktaFGAAuthZInboundPolicy.setContextChecks(context, { user: \`user:${request.user.sub}\`, relation: "editor", object: \`document:${request.params.documentId}\`, }); return request; } typescript #### [​](#applying-to-routes) Applying to Routes In your route configuration, apply both the custom authorization policy and the OktaFGA policy: { "path": "/folders/:folderId", "methods": \["GET"\], "policies": { "inbound": \["jwt-auth", "authz-can-read-folder", "oktafga-authz"\] } } json Then in your `policies.json`: { "name": "authz-can-read-folder", "export": "canReadFolder", "module": "$import(./modules/oktafga-checks)" }, { "name": "oktafga-authz", "export": "OktaFGAAuthZInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { // OktaFGA configuration... } } json ### [​](#example-dynamic-authorization-checks) Example: Dynamic Authorization Checks You can make your authorization checks more dynamic by reading data from your OktaAPI specification or other sources. This allows you to define authorization rules that adapt based on the route, method, or other request properties. For example, you could access custom data defined in your route: export async function dynamicAuthCheck( request: ZuploRequest, context: ZuploContext, ) { // Access custom data from the route configuration const data = context.route.raw<{ "x-authz": { resourceType: string; permission: string; resourceIdParam: string; }; }>(); const authzData = data\["x-authz"\]; if (!authzData?.resourceType || !authzData?.permission) { throw new RuntimeError( "Missing resource type or permission in route config", ); } if (!request.user?.sub) { return HttpProblems.forbidden(request, context); } // Extract resource ID from request parameters const resourceId = request.params?.\[authzData.resourceIdParam\]; if (!resourceId) { throw new RuntimeError( \`Resource ID parameter '${authzData.resourceIdParam}' not found\`, ); } // Set dynamic authorization check OktaFGAAuthZInboundPolicy.setContextChecks(context, { user: \`user:${request.user.sub}\`, relation: authzData.permission, object: \`${authzData.resourceType}:${resourceId}\`, }); return request; } typescript Then in your OpenAPI document, you would set the custom data on the `x-authz` property: { "paths": { "/custom-data": { "post": { "x-authz": { "resourceType": "document", "resourceIdParam": "documentId", "permission": "editor" } } } } } json Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ AuthZEN Authorization Policy](/docs/policies/authzen-inbound "AuthZEN Authorization Policy") [Next page →\ \ OpenFGA Authorization Policy](/docs/policies/openfga-authz-inbound "OpenFGA Authorization Policy") --- # OpenFGA Authorization Policy - Zuplo Docs Menu [​](#openfga-authorization-policy) OpenFGA Authorization Policy =============================================================== OpenFGA is a high-performance and flexible authorization system that implements the Zanzibar model. It allows you to define complex authorization rules based on relationships between users, objects, and actions. This policy will authorize requests using OpenFGA. If the request is not authorized, a 403 response will be returned. ### Beta This policy is in beta. You can use it today, but it may change in non-backward compatible ways before the final release. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-openfga-authz-inbound-policy", "policyType": "openfga-authz-inbound", "handler": { "export": "OpenFGAAuthZInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "apiUrl": "https://api.us1.fga.dev", "authorizationModelId": "$env(FGA\_MODEL\_ID)", "credentials": { "method": "client-credentials", "clientId": "$env(FGA\_CLIENT\_ID)", "clientSecret": "$env(FGA\_CLIENT\_SECRET)", "apiAudience": "https://api.us1.fga.dev/", "oauthTokenEndpointUrl": "https://fga.us.auth0.com/oauth/token" }, "storeId": "$env(FGA\_STORE\_ID)" } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `openfga-authz-inbound`. * `handler.export` `` - The name of the exported type. Value should be `OpenFGAAuthZInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/openfga-authz-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `apiUrl` **(required)** `` - The URL of the OpenFGA service. * `storeId` **(required)** `` - The ID of the store. * `authorizationModelId` **(required)** `` - The ID of the authorization model. * `allowUnauthorizedRequests` `` - Indicates whether the request should continue if authorization fails. Default is `false` which means unauthorized users will automatically receive a 403 response. Defaults to `false`. * `credentials` **(required)** `` - No description available. [​](#using-the-policy) Using the Policy --------------------------------------- [​](#usage) Usage ----------------- To use this policy, you must programmatically set the relationship checks to be performed against your OpenFGA store. This is done using the static `setContextChecks` method. The most common way to set the authorization checks are: 1. Creating custom inbound policies for each authorization scenario 2. Creating a custom inbound policy that reads data from the OpenAPI operation and sets the authorization checks dynamically ### [​](#example-custom-authorization-policies) Example: Custom Authorization Policies Create a file like `modules/openfga-checks.ts` to define your custom authorization policies: import { ZuploRequest, ZuploContext, RuntimeError, HttpProblems, OpenFGAAuthZInboundPolicy, } from "@zuplo/runtime"; export async function canReadFolder( request: ZuploRequest, context: ZuploContext, ) { if (!request.params?.folderId) { throw new RuntimeError("Folder ID not found in request"); } context.log.info("Setting OpenFGA context checks"); if (!request.user?.sub) { return HttpProblems.forbidden(request, context, { detail: "User not found", }); } // Set the authorization check to verify if the user has viewer access to the folder OpenFGAAuthZInboundPolicy.setContextChecks(context, { user: \`user:${request.user.sub}\`, relation: "viewer", object: \`folder:${request.params.folderId}\`, }); return request; } export async function canEditDocument( request: ZuploRequest, context: ZuploContext, ) { if (!request.params?.documentId) { throw new RuntimeError("Document ID not found in request"); } if (!request.user?.sub) { return HttpProblems.forbidden(request, context, { detail: "User not found", }); } // Set the authorization check to verify if the user has editor access to the document OpenFGAAuthZInboundPolicy.setContextChecks(context, { user: \`user:${request.user.sub}\`, relation: "editor", object: \`document:${request.params.documentId}\`, }); return request; } typescript #### [​](#applying-to-routes) Applying to Routes In your route configuration, apply both the custom authorization policy and the OpenFGA policy: { "path": "/folders/:folderId", "methods": \["GET"\], "policies": { "inbound": \["jwt-auth", "authz-can-read-folder", "openfga-authz"\] } } json Then in your `policies.json`: { "name": "authz-can-read-folder", "export": "canReadFolder", "module": "$import(./modules/openfga-checks)" }, { "name": "openfga-authz", "export": "OpenFGAAuthZInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { // OpenFGA configuration... } } json ### [​](#example-dynamic-authorization-checks) Example: Dynamic Authorization Checks You can make your authorization checks more dynamic by reading data from your OpenAPI specification or other sources. This allows you to define authorization rules that adapt based on the route, method, or other request properties. For example, you could access custom data defined in your route: export async function dynamicAuthCheck( request: ZuploRequest, context: ZuploContext, ) { // Access custom data from the route configuration const data = context.route.raw<{ "x-authz": { resourceType: string; permission: string; resourceIdParam: string; }; }>(); const authzData = data\["x-authz"\]; if (!authzData?.resourceType || !authzData?.permission) { throw new RuntimeError( "Missing resource type or permission in route config", ); } if (!request.user?.sub) { return HttpProblems.forbidden(request, context); } // Extract resource ID from request parameters const resourceId = request.params?.\[authzData.resourceIdParam\]; if (!resourceId) { throw new RuntimeError( \`Resource ID parameter '${authzData.resourceIdParam}' not found\`, ); } // Set dynamic authorization check OpenFGAAuthZInboundPolicy.setContextChecks(context, { user: \`user:${request.user.sub}\`, relation: authzData.permission, object: \`${authzData.resourceType}:${resourceId}\`, }); return request; } typescript Then in your OpenAPI document, you would set the custom data on the `x-authz` property: { "paths": { "/custom-data": { "post": { "x-authz": { "resourceType": "document", "resourceIdParam": "documentId", "permission": "editor" } } } } } json Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Okta FGA Authorization Policy](/docs/policies/okta-fga-authz-inbound "Okta FGA Authorization Policy") [Next page →\ \ Axiomatics Authorization Policy](/docs/policies/axiomatics-authz-inbound "Axiomatics Authorization Policy") --- # JWT Auth Policy - Zuplo Docs Menu [​](#jwt-auth-policy) JWT Auth Policy ===================================== The Open ID JWT Authentication policy allows you to authenticate incoming requests using an Open ID-compliant bearer token. It works with common authentication services like Auth0 (sample here) but should also work with any valid Open ID JWT token. When configured, you can have Zuplo check incoming requests for a JWT token and automatically populate the `ZuploRequest` 's `user` property with a user object. This `user` object will have a `sub` property - taking the `sub` id from the JWT token. It will also have a `data` property populated by other data returned in the JWT token (including any claims). See [this document](https://zuplo.com/docs/articles/oauth-authentication) for more information about OAuth authorization in Zuplo. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-open-id-jwt-auth-inbound-policy", "policyType": "open-id-jwt-auth-inbound", "handler": { "export": "OpenIdJwtInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "audience": "$env(AUTH\_AUDIENCE)", "issuer": "$env(AUTH\_ISSUER)", "jwkUrl": "https://zuplo-demo.us.auth0.com/.well-known/jwks.json" } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `open-id-jwt-auth-inbound`. * `handler.export` `` - The name of the exported type. Value should be `OpenIdJwtInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/open-id-jwt-auth-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `authHeader` `` - The name of the header with the key. Defaults to `"Authorization"`. * `issuer` `` - The expected issuer claim in the JWT token. * `audience` `` - The expected audience claim in the JWT token. * `jwkUrl` `` - the url of the JSON Web Key Set (JWKS) - this is used to validate the JWT token signature (either this or `secret` must be set). * `secret` `` - The key used to verify the signature of the JWT token (either this or `jwkUrl` must be set). * `allowUnauthenticatedRequests` `` - indicates whether the request should continue if authentication fails. Defaults is `false` which means unauthenticated users will automatically receive a 401 response. Defaults to `false`. * `subPropertyName` `` - The name of the property in the JWT token that contains the user's unique identifier. * `headers` `` - Additional headers to send with the JWK request. [​](#using-the-policy) Using the Policy --------------------------------------- Note that sometimes the `issuer` and `audience` will vary between your environments (e.g. dev, staging and prod). We recommend storing these values in your environment variables and using `$env(VARIABLE_NAME)` to include them in your policy configuration. Note you can have multiple instances of the same policy with different `name`s if you want to have slightly different rules (such as settings for the `allowUnauthenticatedRequests` setting. { "path": "/products/:123", "methods": \["POST"\], "handler": { "module": "$import(./modules/products)", "export": "postProducts" }, "corsPolicy": "None", "version": "none", "policies": { "inbound": \["your-jwt-policy-name"\] } } json [​](#using-the-user-property-in-code) Using the user property in code --------------------------------------------------------------------- For an example of using the user object in a [RequestHandler](/docs/handlers/custom-handler) , see [Setting up JWT auth with Auth0](/docs/policies/auth0-jwt-auth-inbound) . Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Okta JWT Auth Policy](/docs/policies/okta-jwt-auth-inbound "Okta JWT Auth Policy") [Next page →\ \ PropelAuth JWT Auth Policy](/docs/policies/propel-auth-jwt-inbound "PropelAuth JWT Auth Policy") --- # Okta JWT Auth Policy - Zuplo Docs Menu [​](#okta-jwt-auth-policy) Okta JWT Auth Policy =============================================== Authenticate requests with JWT tokens issued by Okta. This is a customized version of the [OpenId JWT Policy](https://zuplo.com/docs/policies/open-id-jwt-auth-inbound) specifically for Okta. See [this document](https://zuplo.com/docs/articles/oauth-authentication) for more information about OAuth authorization in Zuplo. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-okta-jwt-auth-inbound-policy", "policyType": "okta-jwt-auth-inbound", "handler": { "export": "OktaJwtInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "allowUnauthenticatedRequests": false, "audience": "api://my-api", "issuerUrl": "https://dev-12345.okta.com/oauth2/abc" } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `okta-jwt-auth-inbound`. * `handler.export` `` - The name of the exported type. Value should be `OktaJwtInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/okta-jwt-auth-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `allowUnauthenticatedRequests` `` - Allow unauthenticated requests to proceed. This is use useful if you want to use multiple authentication policies or if you want to allow both authenticated and non-authenticated traffic. Defaults to `false`. * `issuerUrl` **(required)** `` - Your Okta authorization server's issuer URL. For example, `https://dev-12345.okta.com/oauth2/abc`. * `audience` `` - The Okta audience of your API, for example `api://my-api`. [​](#using-the-policy) Using the Policy --------------------------------------- Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Firebase JWT Auth Policy](/docs/policies/firebase-jwt-inbound "Firebase JWT Auth Policy") [Next page →\ \ JWT Auth Policy](/docs/policies/open-id-jwt-auth-inbound "JWT Auth Policy") --- # Policy Catalog - Zuplo Docs Menu Zuplo includes policies for any solution you need for securing and sharing your API. See the [policy introduction](/docs/articles/policies) to learn about using policies. In addition to the built-in policies, Zuplo is [fully programmable](/docs/policies/custom-code-inbound) so developers can simply write code to customize any aspect of Zuplo. Inbound Policies ---------------- [A/B Test Inbound](/docs/policies/ab-test-inbound) [Access Control List](/docs/policies/acl-policy-inbound) [Add or Set Query Parameters](/docs/policies/set-query-params-inbound) [Add or Set Request Headers](/docs/policies/set-headers-inbound) [Amberflo Metering / Billing](/docs/policies/amberflo-metering-inbound) [API Key Authentication](/docs/policies/api-key-inbound) [Archive Request to AWS S3](/docs/policies/archive-request-aws-s3-inbound) [Archive Request to Azure Storage](/docs/policies/archive-request-azure-storage-inbound) [Archive Request to GCP Storage](/docs/policies/archive-request-gcp-storage-inbound) [Aserto Authorization](/docs/policies/aserto-authz-inbound) [Audit Logs](/docs/policies/audit-log-inbound) [Auth0 JWT Auth](/docs/policies/auth0-jwt-auth-inbound) [AuthZEN Authorization](/docs/policies/authzen-inbound) [AWS Cognito JWT Auth](/docs/policies/cognito-jwt-auth-inbound) [Axiomatics Authorization](/docs/policies/axiomatics-authz-inbound) [Basic Auth](/docs/policies/basic-auth-inbound) [Bot Detection](/docs/policies/bot-detection-inbound) [Brown Out](/docs/policies/brownout-inbound) [Caching](/docs/policies/caching-inbound) [Change Method](/docs/policies/change-method-inbound) [Clear Request Headers](/docs/policies/clear-headers-inbound) [Clerk JWT Auth](/docs/policies/clerk-jwt-auth-inbound) [Complex Rate Limiting](/docs/policies/complex-rate-limit-inbound) [Composite Inbound (Group Policies)](/docs/policies/composite-inbound) [Curity Phantom Token Auth](/docs/policies/curity-phantom-token-inbound) [Custom Code Inbound](/docs/policies/custom-code-inbound) [Firebase JWT Auth](/docs/policies/firebase-jwt-inbound) [Form Data to JSON](/docs/policies/formdata-to-json-inbound) [Geo-location filtering](/docs/policies/geo-filter-inbound) [GraphQL Complexity Limit](/docs/policies/graphql-complexity-limit-inbound) [GraphQL Disable Introspection](/docs/policies/graphql-disable-introspection-inbound) [HMAC Auth](/docs/policies/hmac-auth-inbound) [IP Restriction](/docs/policies/ip-restriction-inbound) [JWT Auth](/docs/policies/open-id-jwt-auth-inbound) [JWT Scope Validation](/docs/policies/jwt-scopes-inbound) [LDAP Auth](/docs/policies/ldap-auth-inbound) [Mock API Response](/docs/policies/mock-api-inbound) [Moesif Analytics & Billing](/docs/policies/moesif-inbound) [Monetization](/docs/policies/monetization-inbound) [mTLS Auth](/docs/policies/mtls-auth-inbound) [Okta FGA Authorization](/docs/policies/okta-fga-authz-inbound) [Okta JWT Auth](/docs/policies/okta-jwt-auth-inbound) [OpenFGA Authorization](/docs/policies/openfga-authz-inbound) [PropelAuth JWT Auth](/docs/policies/propel-auth-jwt-inbound) [Quota](/docs/policies/quota-inbound) [Rate Limiting](/docs/policies/rate-limit-inbound) [RBAC Authorization](/docs/policies/rbac-policy-inbound) [Readme Metrics](/docs/policies/readme-metrics-inbound) [Remove Query Parameters](/docs/policies/remove-query-params-inbound) [Remove Request Headers](/docs/policies/remove-headers-inbound) [Request Size Limit](/docs/policies/request-size-limit-inbound) [Request Validation](/docs/policies/request-validation-inbound) [Require Origin](/docs/policies/require-origin-inbound) [Set Body](/docs/policies/set-body-inbound) [Sleep / Delay](/docs/policies/sleep-inbound) [Stripe Webhook Auth](/docs/policies/stripe-webhook-verification-inbound) [Supabase JWT Auth](/docs/policies/supabase-jwt-auth-inbound) [Transform Request Body](/docs/policies/transform-body-inbound) [Upstream Azure AD Service Auth](/docs/policies/upstream-azure-ad-service-auth-inbound) [Upstream Firebase Admin Auth](/docs/policies/upstream-firebase-admin-auth-inbound) [Upstream Firebase User Auth](/docs/policies/upstream-firebase-user-auth-inbound) [Upstream GCP Federated Auth](/docs/policies/upstream-gcp-federated-auth-inbound) [Upstream GCP Self-Signed JWT](/docs/policies/upstream-gcp-jwt-inbound) [Upstream GCP Service Auth](/docs/policies/upstream-gcp-service-auth-inbound) Outbound Policies ----------------- [A/B Test Outbound](/docs/policies/ab-test-outbound) [Archive Response to AWS S3](/docs/policies/archive-response-aws-s3-outbound) [Archive Response to Azure Storage](/docs/policies/archive-response-azure-storage-outbound) [Clear Response Headers](/docs/policies/clear-headers-outbound) [Composite Outbound (Group Policies)](/docs/policies/composite-outbound) [Custom Code Outbound](/docs/policies/custom-code-outbound) [Remove Response Headers](/docs/policies/remove-headers-outbound) [Replace String in Response Body](/docs/policies/replace-string-outbound) [Set Headers](/docs/policies/set-headers-outbound) [Set Status Code](/docs/policies/set-status-outbound) [Transform Response Body](/docs/policies/transform-body-outbound) [XML to JSON Outbound](/docs/policies/xml-to-json-outbound) * * * [Next page →\ \ Policy Fundamentals](/docs/articles/policies "Policy Fundamentals") --- # mTLS Auth Policy - Zuplo Docs Menu [​](#mtls-auth-policy) mTLS Auth Policy ======================================= This policy will authenticate users based on mTLS certificates that are configured for your project. This policy is available only to enterprise customers (contact [sales@zuplo.com](mailto:sales@zuplo.com) to request info). When a requests is authenticated with an mTLS certificate, the certificate data will be set as the user object of the request. The `user.sub` property will be the value of the certificates DN. ### Enterprise Feature This policy is only available as part of our enterprise plans. If you would like to use this in production reach out to us: [sales@zuplo.com](mailto:sales@zuplo.com) [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-mtls-auth-inbound-policy", "policyType": "mtls-auth-inbound", "handler": { "export": "MTLSAuthInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "allowExpiredCertificates": false, "allowRevokedCertificates": false, "allowUnauthenticatedRequests": false } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `mtls-auth-inbound`. * `handler.export` `` - The name of the exported type. Value should be `MTLSAuthInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/mtls-auth-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `allowUnauthenticatedRequests` `` - Indicates whether the request should continue if authentication fails. Default is `false` which means unauthenticated users will automatically receive a 401 response. Defaults to `false`. * `allowExpiredCertificates` `` - Indicates whether the request should continue if the certificate is expired. Defaults to `false`. * `allowRevokedCertificates` `` - Indicates whether the request should continue if the certificate is revoked. Defaults to `false`. [​](#using-the-policy) Using the Policy --------------------------------------- Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Basic Auth Policy](/docs/policies/basic-auth-inbound "Basic Auth Policy") [Next page →\ \ LDAP Auth Policy](/docs/policies/ldap-auth-inbound "LDAP Auth Policy") --- # LDAP Auth Policy - Zuplo Docs Menu [​](#ldap-auth-policy) LDAP Auth Policy ======================================= Authenticate requests using an LDAP server. ### Enterprise Feature This policy is only available as part of our enterprise plans. If you would like to use this in production reach out to us: [sales@zuplo.com](mailto:sales@zuplo.com) [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-ldap-auth-inbound-policy", "policyType": "ldap-auth-inbound", "handler": { "export": "LDAPAuthInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "ldapConnectorName": "my-ldap-connector" } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `ldap-auth-inbound`. * `handler.export` `` - The name of the exported type. Value should be `LDAPAuthInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/ldap-auth-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `ldapConnectorName` **(required)** `` - The name of your configured LDAP service connector. [​](#using-the-policy) Using the Policy --------------------------------------- Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ mTLS Auth Policy](/docs/policies/mtls-auth-inbound "mTLS Auth Policy") [Next page →\ \ HMAC Auth Policy](/docs/policies/hmac-auth-inbound "HMAC Auth Policy") --- # Monetization Policy - Zuplo Docs Menu [​](#monetization-policy) Monetization Policy ============================================= The Monetization policy allows you to track and monetize the usage of our API resources, declaratively and programatically. Follow our [Quickstart guide for Monetization](https://zuplo.com/docs/articles/monetization-dev-portal-setup) to get started. ### Beta This policy is in beta. You can use it today, but it may change in non-backward compatible ways before the final release. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-monetization-inbound-policy", "policyType": "monetization-inbound", "handler": { "export": "MonetizationInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "meters": { "requests": 1 } } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `monetization-inbound`. * `handler.export` `` - The name of the exported type. Value should be `MonetizationInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/monetization-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `allowRequestsWithoutSubscription` `` - Indicates if requests without subscription should be allowed or not. Defaults to `false`. * `allowedSubscriptionStatuses` `` - Indicates which subscription statuses should be allowed. Defaults to `[["active","incomplete","trialing"]]`. * `bucketId` `` - Indicates the bucket to be used, overrides the default one. * `allowRequestsOverQuota` `` - Indicates if requests over quota should be allowed or not. Defaults to `false`. * `meters` **(required)** `` - The meters to be used by the policy against the subscription quota. * `meterOnStatusCodes` `` - A list of successful status codes and ranges "200-299, 304" that should trigger a metering call. Defaults to `"200-299"`. [​](#using-the-policy) Using the Policy --------------------------------------- Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Moesif Analytics & Billing Policy](/docs/policies/moesif-inbound "Moesif Analytics & Billing Policy") [Next page →\ \ Amberflo Metering / Billing Policy](/docs/policies/amberflo-metering-inbound "Amberflo Metering / Billing Policy") --- # Mock API Response Policy - Zuplo Docs Menu [​](#mock-api-response-policy) Mock API Response Policy ======================================================= Returns example responses from the OpenAPI document associated with this route. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-mock-api-inbound-policy", "policyType": "mock-api-inbound", "handler": { "export": "MockApiInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "contentType": "application/json", "exampleName": "example1", "random": false } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `mock-api-inbound`. * `handler.export` `` - The name of the exported type. Value should be `MockApiInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/mock-api-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `random` `` - Indicates whether the response should be selected randomly, from the available examples (that match any filter criteria). If `false` the first matching example is used. Defaults to `false`. * `responsePrefixFilter` `` - Specifies a prefix to match the responses to select from. Typically this is a status code like "200" or "2XX". If you want the policy to select randomly from all 2XX codes, set this property to "2" and random to `true`. * `contentType` `` - Specify the content-type of the response to select from. If not specified, the first matching response is used (or random). * `exampleName` `` - Specify the name of the example to select. If not specified, the first matching response is used (or random). [​](#using-the-policy) Using the Policy --------------------------------------- Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ A/B Test Inbound Policy](/docs/policies/ab-test-inbound "A/B Test Inbound Policy") [Next page →\ \ Sleep / Delay Policy](/docs/policies/sleep-inbound "Sleep / Delay Policy") --- # Moesif Analytics & Billing Policy - Zuplo Docs Menu [​](#moesif-analytics--billing-policy) Moesif Analytics & Billing Policy ======================================================================== Moesif [moesif.com](https://moesif.com) is an API analytics and monetization platform. This policy allows you to measure (and meter) API calls flowing through your Zuplo gateway. Add the policy to each route you want to meter. Note you can specify the Meter API Name and Meter Value (meter increment) at the policy level. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-moesif-inbound-policy", "policyType": "moesif-inbound", "handler": { "export": "MoesifInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "applicationId": "$env(MOESIF\_APPLICATION\_ID)", "logRequestBody": true, "logResponseBody": true } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `moesif-inbound`. * `handler.export` `` - The name of the exported type. Value should be `MoesifInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/moesif-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `applicationId` **(required)** `` - Your Moesif application ID. * `logRequestBody` `` - Set to false to disable sending the request body to Moesif. Defaults to `true`. * `logResponseBody` `` - Set to false to disable sending the response body to Moesif. Defaults to `true`. [​](#using-the-policy) Using the Policy --------------------------------------- By default, Zuplo will read the `request.user.sub` property and assign this as the moesif `user_id` attribute when sending to Moesif. However, this and the following attributes can be overriden in a [custom code policy](/docs/policies/custom-code-inbound) . * `api_version` * `company_id` * `session_token` * `user_id` * `metadata` Here is some example code that shows how to override two of these attributes // Add this import at the top of your doc import { setMoesifContext } from "@zuplo/runtime"; setMoesifContext(context, { userId: "user-1234", metadata: { some: "arbitrary", meta: "data", }, }); ts [​](#execute-on-every-route) Execute on every route --------------------------------------------------- If you want to execute this policy on every route, you can add a hook in your [runtime extensions](/docs/articles/runtime-extensions) file `zuplo.runtime.ts`: import { RuntimeExtensions } from "@zuplo/runtime"; export function runtimeInit(runtime: RuntimeExtensions) { runtime.addRequestHook((request, context) => { return context.invokeInboundPolicy("moesif-inbound", request); }); } ts Note you can add a guard clause around the context.invokeInboundPolicy if you want to exclude a few routes. Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Quota Policy](/docs/policies/quota-inbound "Quota Policy") [Next page →\ \ Monetization Policy](/docs/policies/monetization-inbound "Monetization Policy") --- # IP Restriction Policy - Zuplo Docs Menu [​](#ip-restriction-policy) IP Restriction Policy ================================================= ### Custom Policy Example Zuplo is extensible, so we don't have a built-in policy for IP Restriction, instead we've a template here that shows you how you can use your superpower (code) to achieve your goals. To learn more about custom policies [see the documentation](/docs/policies/custom-code-inbound) . This custom policy allows you to specify a set of IP addresses that are allowed or blocked from making requests on your API. This can be useful for adding light-weight security to your API in non-critical scenarios. For example, if you want to ensure only employees on your corporate VPN can't access development environments. Generally, this policy shouldn't be relied upon as the only security for protecting sensitive workloads. import { HttpProblems, ZuploContext, ZuploRequest } from "@zuplo/runtime"; import ipRangeCheck from "ip-range-check"; interface PolicyOptions { allowedIpAddresses?: string\[\]; blockedIpAddresses?: string\[\]; } export default async function ( request: ZuploRequest, context: ZuploContext, options: PolicyOptions, policyName: string, ) { // TODO: Validate the policy options. Skipping in the example for brevity // Get the incoming IP address const ip = request.headers.get("true-client-ip"); // If the allowed IP addresses are set, then the incoming IP // must be in that list if (options.allowedIpAddresses) { const allowed = ipRangeCheck(ip, options.allowedIpAddresses); if (!allowed) { return HttpProblems.unauthorized(request, context); } } // If the blocked IP addresses are set, then the incoming IP // can't be in that list if (options.blockedIpAddresses) { const blocked = ipRangeCheck(ip, options.allowedIpAddresses); if (blocked) { return HttpProblems.unauthorized(request, context); } } // If we made it this far, the IP address is allowed, continue return request; } ts [​](#configuration) Configuration --------------------------------- The example below shows how to configure a custom code policy in the 'policies.json' document that utilizes the above example policy code. { "name": "my-ip-restriction-inbound-policy", "policyType": "ip-restriction-inbound", "handler": { "\_name": "basic", "export": "default", "module": "$import(./modules/YOUR\_MODULE)", "options": { "allowedIpAddresses": \["184.42.1.4", "102.1.5.2/24"\] } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `ip-restriction-inbound`. * `handler.export` `` - The name of the exported type. Value should be `default`. * `handler.module` `` - The module containing the policy. Value should be `$import(./modules/YOUR_MODULE)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/ip-restriction-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `allowedIpAddresses` `` - The IP addresses or CIDR ranges to allow * `blockedIpAddresses` `` - The IP addresses or CIDR ranges to allow [​](#using-the-policy) Using the Policy --------------------------------------- Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Geo-location filtering Policy](/docs/policies/geo-filter-inbound "Geo-location filtering Policy") [Next page →\ \ Rate Limiting Policy](/docs/policies/rate-limit-inbound "Rate Limiting Policy") --- # JWT Scope Validation Policy - Zuplo Docs Menu [​](#jwt-scope-validation-policy) JWT Scope Validation Policy ============================================================= Validates that the JWT token includes specific scopes [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-jwt-scopes-inbound-policy", "policyType": "jwt-scopes-inbound", "handler": { "export": "JWTScopeValidationInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "scopes": \["read:users", "write:projects"\] } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `jwt-scopes-inbound`. * `handler.export` `` - The name of the exported type. Value should be `JWTScopeValidationInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/jwt-scopes-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `scopes` **(required)** `` - An array of of JWT scopes. [​](#using-the-policy) Using the Policy --------------------------------------- Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Axiomatics Authorization Policy](/docs/policies/axiomatics-authz-inbound "Axiomatics Authorization Policy") [Next page →\ \ Access Control List Policy](/docs/policies/acl-policy-inbound "Access Control List Policy") --- # HMAC Auth Policy - Zuplo Docs Menu [​](#hmac-auth-policy) HMAC Auth Policy ======================================= ### Custom Policy Example Zuplo is extensible, so we don't have a built-in policy for HMAC Auth, instead we've a template here that shows you how you can use your superpower (code) to achieve your goals. To learn more about custom policies [see the documentation](/docs/policies/custom-code-inbound) . This example policy demonstrates how to use a shared secret to create an [HMAC](https://en.wikipedia.org/wiki/HMAC) signature to sign a payload (in this case the body). When the request is sent, the signature is sent in the request header. The policy can then verify that the signature matches the payload - thus ensuring that the sender had the same shared secret. This policy is configured with the value of the `secret`. Normally, you would store this as an environment variable secret. Additionally, the policy option `headerName` is used to set the header that will be used by the client to send the signature. import { HttpProblems, ZuploContext, ZuploRequest } from "@zuplo/runtime"; interface PolicyOptions { secret: string; headerName: string; } export default async function ( request: ZuploRequest, context: ZuploContext, options: PolicyOptions, policyName: string, ) { // Validate the policy options if (typeof options.secret !== "string") { throw new Error( \`The option 'secret' on policy '${policyName}' must be a string. Received ${typeof options.secret}.\`, ); } if (typeof options.headerName !== "string") { throw new Error( \`The option 'headerName' on policy '${policyName}' must be a string. Received ${typeof options.headerName}.\`, ); } // Get the authorization header const token = request.headers.get(options.headerName); // No auth header, unauthorized if (!token) { return HttpProblems.unauthorized(request, context); } // Convert the hex encoded token to an Uint8Array const tokenData = new Uint8Array( token.match(/../g)!.map((h) => parseInt(h, 16)), ); // Get the data to verify // This could be anything (headers, query parameter, etc.) // For this example, we will just verify the entire body value const data = await request.text(); // Create a crypto key from a secret stored as an environment variable const encoder = new TextEncoder(); const encodedSecret = encoder.encode(options.secret); const key = await crypto.subtle.importKey( "raw", encodedSecret, { name: "HMAC", hash: "SHA-256" }, false, \["verify"\], ); // Verify that the data const verified = await crypto.subtle.verify( "HMAC", key, tokenData, encoder.encode(data), ); // Check if the data is verified, if not return unauthorized if (!verified) { return HttpProblems.unauthorized(request, context); } // Request is authorized, continue return request; } ts [​](#configuration) Configuration --------------------------------- The example below shows how to configure a custom code policy in the 'policies.json' document that utilizes the above example policy code. { "name": "my-hmac-auth-inbound-policy", "policyType": "hmac-auth-inbound", "handler": { "\_name": "basic", "export": "default", "module": "$import(./modules/YOUR\_MODULE)", "options": { "secret": "$env(MY\_SECRET)", "headerName": "signed-request" } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `hmac-auth-inbound`. * `handler.export` `` - The name of the exported type. Value should be `default`. * `handler.module` `` - The module containing the policy. Value should be `$import(./modules/YOUR_MODULE)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/hmac-auth-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `secret` **(required)** `` - The secret to use for HMAC authentication * `headerName` **(required)** `` - The header where the HMAC signature is send [​](#using-the-policy) Using the Policy --------------------------------------- The example below demonstrates how you could sign a value in order to create an HMAC signature for use with this policy. const token = await sign("my data", environment.MY\_SECRET); async function sign( key: string | ArrayBuffer, val: string, ): Promise { const encoder = new TextEncoder(); const cryptoKey = await crypto.subtle.importKey( "raw", typeof key === "string" ? encoder.encode(key) : key, { name: "HMAC", hash: { name: "SHA-256" } }, false, \["sign"\], ); const token = await crypto.subtle.sign( "HMAC", cryptoKey, encoder.encode(val), ); return Array.prototype.map .call(new Uint8Array(token), function (x) { return ("0" + x.toString(16)).slice(-2); }) .join(""); } ts Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ LDAP Auth Policy](/docs/policies/ldap-auth-inbound "LDAP Auth Policy") [Next page →\ \ Aserto Authorization Policy](/docs/policies/aserto-authz-inbound "Aserto Authorization Policy") --- # GraphQL Disable Introspection Policy - Zuplo Docs Menu [​](#graphql-disable-introspection-policy) GraphQL Disable Introspection Policy =============================================================================== This is useful in production to prevent attackers from learning about your API. You can still keep introspection enabled for any request not going through Zuplo. This policy allows you to disable introspection queries on your API. Any introspection query will be blocked with a `403 Forbidden` response. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-graphql-disable-introspection-inbound-policy", "policyType": "graphql-disable-introspection-inbound", "handler": { "export": "GraphQLDisableIntrospectionInboundPolicy", "module": "$import(@zuplo/runtime)", "options": {} } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `graphql-disable-introspection-inbound`. * `handler.export` `` - The name of the exported type. Value should be `GraphQLDisableIntrospectionInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/graphql-disable-introspection-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. [​](#using-the-policy) Using the Policy --------------------------------------- Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Archive Response to AWS S3 Policy](/docs/policies/archive-response-aws-s3-outbound "Archive Response to AWS S3 Policy") [Next page →\ \ GraphQL Complexity Limit Policy](/docs/policies/graphql-complexity-limit-inbound "GraphQL Complexity Limit Policy") --- # Geo-location filtering Policy - Zuplo Docs Menu [​](#geo-location-filtering-policy) Geo-location filtering Policy ================================================================= Block requests based on geo-location parameters: country, region code, and ASN [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-geo-filter-inbound-policy", "policyType": "geo-filter-inbound", "handler": { "export": "GeoFilterInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "allow": { "asns": "395747, 28304", "countries": "US, CA", "regionCodes": "TX, WA" }, "block": { "asns": "395747, 28304", "countries": "US, CA", "regionCodes": "TX, WA" }, "ignoreUnknown": true } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `geo-filter-inbound`. * `handler.export` `` - The name of the exported type. Value should be `GeoFilterInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/geo-filter-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `block` `` - No description available. * `countries` `` - comma separated string of country codes to allow (e.g. "US, CA"). * `regionCodes` `` - comma separated string of region codes to allow (e.g. "TX, WA"). * `asns` `` - comma separated string of ASNs to allow (e.g. "395747, 28304"). * `allow` `` - No description available. * `countries` `` - comma separated string of country codes to allow (e.g. "US, CA"). * `regionCodes` `` - comma separated string of region codes to allow (e.g. "TX, WA"). * `asns` `` - comma separated string of ASNs to allow (e.g. "395747, 28304"). * `ignoreUnknown` `` - Specifies whether unknown geo-location parameters should be ignored (allowed through). Defaults to `true`. [​](#using-the-policy) Using the Policy --------------------------------------- [​](#geo-location-filter-policy) Geo-location Filter Policy ----------------------------------------------------------- Specify an allow list or block list of: * **Countries** - Country of the incoming request. The [two-letter country code](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) in the request, for example, "US". * **regionCodes** - If known, the [ISO 3166-2](https://en.wikipedia.org/wiki/ISO_3166-2) code for the first-level region associated with the IP address of the incoming request, for example, "TX" * **ASNs** - ASN of the incoming request, for example, 395747. If you specify an allow and block list for the same location type (e.g. `country`) may have no effect or block all requests. { "allow" : { "countries" : "US" }, "block" : { "countries" : "MC" } } plain The policy will only allow requests from US, so any request from MC would be automatically blocked. Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ RBAC Authorization Policy](/docs/policies/rbac-policy-inbound "RBAC Authorization Policy") [Next page →\ \ IP Restriction Policy](/docs/policies/ip-restriction-inbound "IP Restriction Policy") --- # GraphQL Complexity Limit Policy - Zuplo Docs Menu [​](#graphql-complexity-limit-policy) GraphQL Complexity Limit Policy ===================================================================== This policy allows you to add a limit for the depth and a limit for the complexity of a GraphQL query. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-graphql-complexity-limit-inbound-policy", "policyType": "graphql-complexity-limit-inbound", "handler": { "export": "GraphQLComplexityLimitInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "useComplexityLimit": { "complexityLimit": 10 }, "useDepthLimit": { "ignore": \[\] } } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `graphql-complexity-limit-inbound`. * `handler.export` `` - The name of the exported type. Value should be `GraphQLComplexityLimitInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/graphql-complexity-limit-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `useComplexityLimit` **(required)** `` - No description available. * `complexityLimit` `` - The maximum complexity a query is allowed to have. * `endpointUrl` `` - The endpoint URL to use for the complexity calculation. * `useDepthLimit` **(required)** `` - No description available. * `depthLimit` `` - The maximum depth a query is allowed to have. * `ignore` `` - The fields to ignore when calculating the depth of a query. [​](#using-the-policy) Using the Policy --------------------------------------- ### [​](#depth-limit) Depth Limit Limit the depth a GraphQL query is allowed to query for. * **maxDepth** - Number of levels a GraphQL query is allowed to query for. This allows you to limit the depth of a GraphQL query. This is useful to prevent DoS attacks on your GraphQL server. { # Level 0 me { # Level 1 name friends { # Level 2 name friends { # Level 3 name # ... } } } } plain ### [​](#complexity-limit) Complexity Limit Example: * **maxComplexity** - Maximum complexity allowed for a query. { me { name # Complexity +1 age # Complexity +1 email # Complexity +1 friends { name # Complexity +1 height # Complexity +1 } } } # Total complexity = 5 plain Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ GraphQL Disable Introspection Policy](/docs/policies/graphql-disable-introspection-inbound "GraphQL Disable Introspection Policy") [Next page →\ \ Composite Inbound (Group Policies) Policy](/docs/policies/composite-inbound "Composite Inbound (Group Policies) Policy") --- # Firebase JWT Auth Policy - Zuplo Docs Menu [​](#firebase-jwt-auth-policy) Firebase JWT Auth Policy ======================================================= Authenticate requests with JWT tokens issued by Firebase. The payload of the JWT token, if successfully authenticated, with be on the `request.user.data` object accessible to the runtime. See [this document](https://zuplo.com/docs/articles/oauth-authentication) for more information about OAuth authorization in Zuplo. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-firebase-jwt-inbound-policy", "policyType": "firebase-jwt-inbound", "handler": { "export": "FirebaseJwtInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "allowUnauthenticatedRequests": false, "projectId": "my-project-id" } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `firebase-jwt-inbound`. * `handler.export` `` - The name of the exported type. Value should be `FirebaseJwtInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/firebase-jwt-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `allowUnauthenticatedRequests` `` - Allow unauthenticated requests to proceed. This is use useful if you want to use multiple authentication policies or if you want to allow both authenticated and non-authenticated traffic. Defaults to `false`. * `projectId` **(required)** `` - Your Firebase Project ID. [​](#using-the-policy) Using the Policy --------------------------------------- Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ AWS Cognito JWT Auth Policy](/docs/policies/cognito-jwt-auth-inbound "AWS Cognito JWT Auth Policy") [Next page →\ \ Okta JWT Auth Policy](/docs/policies/okta-jwt-auth-inbound "Okta JWT Auth Policy") --- # Custom Code Outbound Policy - Zuplo Docs Menu [​](#custom-code-outbound-policy) Custom Code Outbound Policy ============================================================= Add your own custom outbound policy coded in TypeScript. See below for more details on how to build your own policy. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-custom-code-outbound-policy", "policyType": "custom-code-outbound", "handler": { "\_name": "basic", "export": "default", "module": "$import(./modules/YOUR\_MODULE)", "options": { "config1": "YOUR\_VALUE", "config2": true } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `custom-code-outbound`. * `handler.export` `` - The name of the exported type. Value should be `YOUR_EXPORT`. * `handler.module` `` - The module containing the policy. Value should be `$import(./modules/YOUR_MODULE)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/custom-code-outbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. [​](#using-the-policy) Using the Policy --------------------------------------- ### The outbound policy will only execute if the response status codeis 'ok' (e.g. `response.ok === true` or the status code is 200-299) - see [response.ok on MDN](https://developer.mozilla.org/en-US/docs/Web/API/Response/ok) . ### [​](#writing-a-policy) Writing A Policy Custom policies can be written to extend the functionality of your gateway. This document is about outbound policies that can intercept the request and, if required, modify it before passing down the chain. The outbound custom policy is similar to the inbound custom policy but also accepts a `Response` parameter. The outbound policy must return a valid `Response` (or throw an error, which will result in a 500 Internal Server Error for your consumer, not recommended). Note that both `ZuploRequest` and `Response` are based on the web standards [Request](https://developer.mozilla.org/en-US/docs/Web/API/request) and [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response) . ZuploRequest adds a few additional properties for convenience, like `user` and `params`. export type OutboundPolicyHandler = ( response: Response, request: ZuploRequest, context: ZuploContext, options: TOptions, policyName: string, ) => Promise; ts A common use case for outbound policies is to change the body of the response. In this example, we'll imagine we are proxying the `/todos` example api at [https://jsonplaceholder.typicode.com/todos](https://jsonplaceholder.typicode.com/todos) . The format of the /todos response looks like this \[\ {\ "userId": 1,\ "id": 1,\ "title": "delectus aut autem",\ "completed": false\ },\ {\ "userId": 1,\ "id": 2,\ "title": "quis ut nam facilis et officia qui",\ "completed": false\ },\ \ json\ \ We will write an outbound policy that does two things\ \ 1. Removes the `userId` property\ 2. Adds a new outbound header called `color`\ \ Here's the code:\ \ // /modules/my-first-policy.ts\ export default async function (\ response: Response,\ request: ZuploRequest,\ context: ZuploContext,\ options: any,\ policyName: string,\ ) {\ if (response.status !== 200) {\ // if we get an unexpected response code, something went wrong, just let the response flow\ return response;\ }\ \ const data = (await response.json()) as any\[\]; // we know this is JSON and an array\ data.forEach((item) => {\ delete item.userId;\ });\ \ // create a new response\ const newResponse = new Response(JSON.stringify(data), {\ status: response.status,\ headers: response.headers,\ });\ \ // let's add an additional header as an example, for good measure\ newResponse.headers.set("color", "yellow");\ \ return newResponse;\ }\ \ ts\ \ Note, that because we're not using the original response here (we just use the new one called `newResponse`) we didn't need to `clone` the original response before reading the body with `.json()`. If you need to read the body and use that same instance you must first `clone()` to avoid runtime errors such as "Body is unusable".\ \ [​](#wiring-up-the-policy-on-routes)\ Wiring up the policy on routes\ -------------------------------------------------------------------\ \ Policies are activated by specifying them on routes in the route.oas.json file. Here's how we could wire up our new route:\ \ // /config/policies.json\ {\ "policies": \[\ {\ "name": "my-first-policy",\ "policyType": "custom-code-outbound",\ "handler": {\ "export": "default",\ "module": "$import(./modules/my-first-policy)"\ }\ }\ \]\ }\ \ json\ \ // /config/routes.oas.json\ {\ ...\ "paths": {\ "x-zuplo-path": {\ "pathMode": "open-api"\ },\ "get": {\ "summary": "New Route",\ "description": "",\ "x-zuplo-route": {\ "corsPolicy": "none",\ "handler": {\ "export": "urlForwardHandler",\ "module": "$import(@zuplo/runtime)",\ "options": {\ "baseUrl": "https://getting-started.zuplo.io"\ }\ },\ "policies": {\ "inbound": \[\],\ "outbound": \[\ "my-first-policy",\ \]\ }\ },\ }\ \ }\ \ json\ \ ### [​](#custom-policy-options)\ Custom Policy Options\ \ In your policy configuration, you can specify additional information to configure your policy on the options property. In the example below we set an example object with some properties of type string and number. Note these objects can be as complicated as you like.\ \ {\ "name": "my-first-policy",\ "policyType": "custom-code-outbound",\ "handler": {\ "export": "default",\ "module": "$import(./modules/my-first-policy)",\ "options": {\ "you": "can",\ "specify": "anything",\ "here": 0\ }\ }\ }\ \ json\ \ The value of this property will be passed to your policy's handler as the `options` parameter. Sometimes it's useful to create a type as shown below.\ \ type MyPolicyOptionsType = {\ you: string;\ specify: string;\ here: number;\ };\ export default async function (\ response: Response,\ request: ZuploRequest,\ context: ZuploContext,\ options: MyPolicyOptionsType,\ policyName: string,\ ) {\ // your policy code goes here, and can use the options to perform any\ // configuration\ context.log.info(options.you);\ }\ \ ts\ \ You can also use the `any` type if you prefer not to create a type.\ \ [​](#adding-headers)\ Adding headers\ -----------------------------------\ \ Note if you just need to add headers, it more efficient not read the body stream and reuse it, e.g.\ \ export default async function (\ response: Response,\ request: ZuploRequest,\ context: ZuploContext,\ options: any,\ policyName: string,\ ) {\ // create a new response\ const newResponse = new Response(response.body, {\ status: response.status,\ headers: response.headers,\ });\ \ // let's add an additional header as an example, for good measure\ newResponse.headers.set("color", "yellow");\ \ return newResponse;\ }\ \ ts\ \ Read more about [how policies work](/docs/articles/policies)\ \ * * *\ \ [← Previous page\ \ Custom Code Inbound Policy](/docs/policies/custom-code-inbound "Custom Code Inbound Policy")\ [Next page →\ \ Audit Logging](/docs/articles/custom-audit-log-policy "Audit Logging") --- # Curity Phantom Token Auth Policy - Zuplo Docs Menu [​](#curity-phantom-token-auth-policy) Curity Phantom Token Auth Policy ======================================================================= Authenticate requests with Phantom Tokens issued by Curity. The payload of the Phantom JWT token, if successfully authenticated, with be on the `request.user.data` object accessible to the runtime. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-curity-phantom-token-inbound-policy", "policyType": "curity-phantom-token-inbound", "handler": { "export": "CurityPhantomTokenInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "cacheDurationSeconds": 600 } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `curity-phantom-token-inbound`. * `handler.export` `` - The name of the exported type. Value should be `CurityPhantomTokenInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/curity-phantom-token-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `clientId` **(required)** `` - The client ID of the Curity application. * `clientSecret` **(required)** `` - The client secret of the Curity application. * `introspectionUrl` **(required)** `` - The introspection URL of the Curity application. * `cacheDurationSeconds` `` - The duration in seconds to cache the introspected response. Defaults to `600`. [​](#using-the-policy) Using the Policy --------------------------------------- Adding the Curity Phantom Token Pattern to your route is trivial. Before getting started, make sure that you have an instance of [the Curity Identity Server](https://curity.io/) up and running. ### [​](#setup-the-curity-identity-server) Setup the Curity Identity Server Getting the Curity Identity Server up and running is quick. Follow the [Getting Started Guide](https://curity.io/resources/getting-started/) to install and configure the server. #### [​](#introspection) Introspection In addition to the instructions outlined in the Getting Started Guide a client that enable introspection is needed. Typical recommendation for this is to create a new separate client that only enables the introspection capability. ![](https://cdn.zuplo.com/assets/fed55feb-479f-40e6-82a3-734a7459fd97.png) #### [​](#exposing-the-runtime) Exposing the Runtime Depending on where the Curity Identity Server is deployed you might have to expose the runtime node using a reverse proxy. One option is to use [ngrok](https://curity.io/resources/learn/expose-local-curity-ngrok/) but other solutions could also be used. #### [​](#oauth-tools) OAuth Tools With the server up and running and available you can use [OAuth Tools](https://oauth.tools/) to test the configuration and make sure that you are able to obtain a token. If an opaque token is possible to obtain you are good to continue. ### [​](#set-environment-variables) Set Environment Variables Before adding the policy, there are a few environment variables that will need to be set that will be used in the Curity Phantom Token Policy. 1. In the [Zuplo Portal](https://portal.zuplo.com) open the **Environment Variables** section in the **Settings** tab. 2. Click **Add new Variable** and enter the name `INTROSPECTION_URL` in the name field. Set the value to URL endpoint of the Curity Identity Server that handles introspection. Ex. `https://idsvr.example.com/oauth/v2/oauth-introspect` 3. Click **Add new Variable** again and enter the name `CLIENT_ID` in the name field. Set the value to ID of the client that you added the introspection capability to. 4. Click **Add new Variable** again and enter the name `CLIENT_SECRET` in the name field. Set the value to the secret of the client that you added the introspection capability to. **Make sure to enable `is Secret?`.** ### [​](#add-the-curity-phantom-token-policy) Add the Curity Phantom Token Policy The next step is to add the Curity Phantom Token Auth policy to a route in your project. The next step is to add the Curity Phantom Token Auth policy to a route in your project. 1. In the [Zuplo Portal](https://portal.zuplo.com) open the **Route Designer** in the **Files** tab then click **routes.oas.json**. 2. Select or create a route that you want to authenticate with the Curity Phantom Token Pattern. Expand the **Policies** section and click **Add Policy**. Search for and select the **Curity Phantom Token Auth** policy. 3. Add the following to options: "clientId": "$env(CLIENT\_ID)", "clientSecret": "$env(CLIENT\_SECRET)", "introspectionUrl": "$env(INTROSPECTION\_URL)", json The policy configuration should now look like this: 4. Click **OK** to save the policy. 5. Click **Save All** to save all the configurations. ### [​](#test-the-policy) Test the Policy Head over to [OAuth Tools](https://oauth.tools/) to test the policy. 1. Run a flow to obtain an opaque token (typically Code Flow) 2. Configure an **External API** flow and add your Zuplo endpoint in the **API Endpoint** field. Set the request method and choose the opaque token obtained in step 1. ![](https://cdn.zuplo.com/assets/a7752689-f57d-45e5-8103-87116d3ab779.png) 3. Click **Send**. The panel on the right should now display the response from the API. If the upstream API echoes back what is sent you will see that the `Authorization` header now contains a JWT instead of the original opaque token that was sent in the request. ### [​](#conclusion) Conclusion You have now setup the Curity Phantom Token Pattern for Authentication. Your API Gateway now accepts an opaque access token in the Authorization header and will handle obtaining a corresponding signed JWT that will be passed on to the upstream API. Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Supabase JWT Auth Policy](/docs/policies/supabase-jwt-auth-inbound "Supabase JWT Auth Policy") [Next page →\ \ Basic Auth Policy](/docs/policies/basic-auth-inbound "Basic Auth Policy") --- # Composite Outbound (Group Policies) Policy - Zuplo Docs [​](#composite-outbound-group-policies-policy) Composite Outbound (Group Policies) Policy ========================================================================================= The Composite outbound policy allows you to create groups of other policies, for easy reuse across multiple routes. Other policies are referenced by their `name`. Be careful not to create circular references which can cause your gateway to fail. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-composite-outbound-policy", "policyType": "composite-outbound", "handler": { "export": "CompositeOutboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "policies": \["policy1", "policy2"\] } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `composite-outbound`. * `handler.export` `` - The name of the exported type. Value should be `CompositeOutboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/composite-outbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `policies` `` - The list of policy references (beware circular references). [​](#using-the-policy) Using the Policy --------------------------------------- Read more about [how policies work](/docs/articles/policies) * * * --- # Form Data to JSON Policy - Zuplo Docs Menu [​](#form-data-to-json-policy) Form Data to JSON Policy ======================================================= Converts form data in the incoming request to JSON. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-formdata-to-json-inbound-policy", "policyType": "formdata-to-json-inbound", "handler": { "export": "FormDataToJsonInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "badRequestIfNotFormData": true } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `formdata-to-json-inbound`. * `handler.export` `` - The name of the exported type. Value should be `FormDataToJsonInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/formdata-to-json-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `badRequestIfNotFormData` `` - Should the policy return an error if the request is not of the type form data. Defaults to `true`. * `optionalHoneypotName` `` - The name of the honeypot field. Used to provide basic spam filtering. [​](#using-the-policy) Using the Policy --------------------------------------- Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Change Method Policy](/docs/policies/change-method-inbound "Change Method Policy") [Next page →\ \ Remove Query Parameters Policy](/docs/policies/remove-query-params-inbound "Remove Query Parameters Policy") --- # Composite Inbound (Group Policies) Policy - Zuplo Docs Menu [​](#composite-inbound-group-policies-policy) Composite Inbound (Group Policies) Policy ======================================================================================= The Composite inbound policy allows you to create groups of other policies, for easy reuse across multiple routes. Other policies are referenced by their `name`. Be careful not to create circular references which can cause your gateway to fail. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-composite-inbound-policy", "policyType": "composite-inbound", "handler": { "export": "CompositeInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "policies": \["policy1", "policy2"\] } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `composite-inbound`. * `handler.export` `` - The name of the exported type. Value should be `CompositeInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/composite-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `policies` `` - The list of policy references (beware circular references). [​](#using-the-policy) Using the Policy --------------------------------------- Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ GraphQL Complexity Limit Policy](/docs/policies/graphql-complexity-limit-inbound "GraphQL Complexity Limit Policy") [Next page →\ \ Brown Out Policy](/docs/policies/brownout-inbound "Brown Out Policy") --- # Custom Code Inbound Policy - Zuplo Docs Menu [​](#custom-code-inbound-policy) Custom Code Inbound Policy =========================================================== Add your own custom inbound policy coded in TypeScript. See below for more details on how to build your own policy. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-custom-code-inbound-policy", "policyType": "custom-code-inbound", "handler": { "\_name": "basic", "export": "default", "module": "$import(./modules/YOUR\_MODULE)", "options": { "config1": "YOUR\_VALUE", "config2": true } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `custom-code-inbound`. * `handler.export` `` - The name of the exported type. Value should be `YOUR_EXPORT`. * `handler.module` `` - The module containing the policy. Value should be `$import(./modules/YOUR_MODULE)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/custom-code-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `*` `` - Any object your custom policy consumes [​](#using-the-policy) Using the Policy --------------------------------------- [​](#writing-a-policy) Writing A Policy --------------------------------------- Custom policies can be written to extend the functionality of your gateway. This document is about inbound policies that can intercept the request and, if required, modify it before passing down the chain. Policies have a similar but subtly different signature to a [request handler](/docs/handlers/custom-handler) . They also accept a `ZuploRequest` parameter but they must return either a `ZuploRequest` or a `Response`. Note that both `ZuploRequest` and `Response` are based on the web standards [Request](https://developer.mozilla.org/en-US/docs/Web/API/request) and [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response) . ZuploRequest adds a few additional properties for convenience, like `user` and `params`. Returning a `ZuploRequest` is a signal to continue the request pipeline and what you return will be passed to the next policy, and finally the request handler. If you return a `Response` that tells Zuplo to short-circuit this request and immediately respond to the client. export type InboundPolicyHandler = ( request: ZuploRequest, context: ZuploContext, options: TOptions, policyName: string, ) => Promise; ts A common use case for policies is authentication. In the following example we'll create a simple auth policy that checks for an `api-key` header: [​](#a-simple-auth-policy) A simple auth policy ----------------------------------------------- // my-first-policy.ts import { ZuploRequest } from "@zuplo/runtime"; export default async function( request: ZuploRequest, context: ZuploContext options: any, policyName: string) { const apiKeyHeader = request.headers.get("api-key"); if (!apiKeyHeader) { return new Response(\`No api-key header\`, { status: 401}); } if (apiKeyHeader !== \`magic-password\`) { return new Response(\`Incorrect API Key\`, { status: 401}); } // TODO - lets set the user property on the request for // downstream consumption return request; } ts This policy checks for an `api-key` header and rejects requests that don't have one. If such a header is found, it then checks the content of the header for a magic password. This example shouldn't be used in a real API but is demonstrative of how you might build custom authentication. [​](#wiring-up-the-policy-on-routes) Wiring up the policy on routes ------------------------------------------------------------------- Policies are activated by specifying them on routes in the route.oas.json file. Here's how we could wire up our new auth route: // /config/policies.json { "policies": \[\ {\ "name": "my-first-policy",\ "policyType": "custom-code-inbound",\ "handler": {\ "export": "default",\ "module": "$import(./modules/my-first-policy)"\ }\ }\ \] } json // /config/routes.oas.json { ... "paths": { "/redirect-test": { "x-zuplo-path": { "pathMode": "open-api" }, "get": { "summary": "Testing rewrite handler", "x-zuplo-route": { "corsPolicy": "none", "handler": { "module": "$import(@zuplo/runtime)", "export": "redirectHandler", "options": { "location": "/docs" } } }, "policies": { "inbound": \["my-first-policy"\] } } } } } json [​](#policy-options-1) Policy Options ------------------------------------- In your policy configuration, you can specify additional information to configure your policy on the options property. In the example below we set an example object with some properties of type string and number. Note these objects can be as complicated as you like. { "name": "my-first-policy", "policyType": "custom-code-inbound", "handler": { "export": "default", "module": "$import(./modules/my-first-policy)", "options": { "you": "can", "specify": "anything", "here": 0 } } } json The value of this property will be passed to your policy's handler as the `options` parameter. Sometimes it's useful to create a type as shown below. type MyPolicyOptionsType = { you: string; specify: string; here: number; }; export default async function ( request: ZuploRequest, context: ZuploContext, options: MyPolicyOptionsType, policyName: string, ) { // your policy code goes here, and can use the options to perform any // configuration context.log.info(options.you); } ts You can also use the `any` type if you prefer not to create a type. [​](#setting-the-user-property) Setting the user property --------------------------------------------------------- When building a policy it's common to modify the request object in some way before passing control downstream. The `ZuploRequest` type has a `user` property that isn't set for unauthenticated requests. Authenticated requests should have a valid `user` property. Since this is an authentication policy, we should set that property before passing control to the next in line. The user object should have a `sub` property which is a unique user id. Let's use Zuplo's policy `options` to extend our example. You can pass options to a policy from the policies.json file. In this case, we'll create a dictionary of API keys to `sub` ids. "policies": \[\ {\ "name": "my-first-policy",\ "policyType": "custom-code-inbound",\ "handler": {\ "export": "default",\ "module": "$import(./modules/my-first-policy)",\ // some options that will be passed to our Policy\ "options": {\ "123" : "sub-1",\ "abc" : "sub-2"\ }\ }\ }\ \] json Now let's update the policy to read these options and use the dictionary keys as the `api-key` and to map the sub identifier. import { ZuploRequest, ZuploContext } from "@zuplo/runtime"; export default async function ( request: ZuploRequest, context: ZuploContext, options: any, policyName: string, ) { const apiKeyHeader = request.headers.get("api-key"); if (!apiKeyHeader) { return new Response(\`No api-key header\`, { status: 401 }); } const matchedKey = options\[apiKeyHeader\]; if (matchedKey === undefined) { return new Response(\`Incorrect API Key\`, { status: 401 }); } request.user = { sub: matchedKey }; return request; } ts We can then use this user object in the request handler import { ZuploRequest } from "@zuplo/runtime"; export default async function (request: ZuploRequest) { // let's return the user sub to the client as proof it's working return \`User sub ${request.user.sub}\`; } ts Here is this example working as a gif ![Policy in action](https://cdn.zuplo.com/docs/assets/2021-11-21_21.44.35-BcXgZTqL.gif) [​](#modifying-the-request-headers) Modifying the request headers ----------------------------------------------------------------- Sometimes we need to modify the request more significantly, and this will require creating a new request object. In this case, let's imagine we want to convert incoming parameters to headers. export default async function (request: ZuploRequest) { // create a new request based on the old one, // this is required because the original request's // headers are immutable const newRequest = new ZuploRequest(request); // enumerate over the params object and copy to the new // request Object.keys(request.params).forEach((param) => { newRequest.headers.set(param, request.params\[param\]); }); return newRequest; } ts For a more complex example, check out the [custom logging implementation](/docs/articles/custom-logging-example) . Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Caching Policy](/docs/policies/caching-inbound "Caching Policy") [Next page →\ \ Custom Code Outbound Policy](/docs/policies/custom-code-outbound "Custom Code Outbound Policy") --- # Clerk JWT Auth Policy - Zuplo Docs Menu [​](#clerk-jwt-auth-policy) Clerk JWT Auth Policy ================================================= Authenticate requests with JWT tokens issued by Clerk. This is a customized version of the [OpenId JWT Policy](https://zuplo.com/docs/policies/open-id-jwt-auth-inbound) specifically for Clerk. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-clerk-jwt-auth-inbound-policy", "policyType": "clerk-jwt-auth-inbound", "handler": { "export": "ClerkJwtInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "allowUnauthenticatedRequests": false, "frontendApiUrl": "https://sensible-skunk-49.clerk.accounts.dev" } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `clerk-jwt-auth-inbound`. * `handler.export` `` - The name of the exported type. Value should be `ClerkJwtInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/clerk-jwt-auth-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `allowUnauthenticatedRequests` `` - Allow unauthenticated requests to proceed. This is use useful if you want to use multiple authentication policies or if you want to allow both authenticated and non-authenticated traffic. Defaults to `false`. * `frontendApiUrl` **(required)** `` - Your Clerk frontend api url, i.e. `https://sensible-skunk-49.clerk.accounts.dev`. Can be found in the Clerk portal: [https://dashboard.clerk.com/last-active?path=api-keys](https://dashboard.clerk.com/last-active?path=api-keys) . [​](#using-the-policy) Using the Policy --------------------------------------- Adding Clerk authentication to your route takes just a few steps. Follow the instructions below to setup Clerk and the Clerk policy. [​](#setup-clerk) Setup Clerk ----------------------------- If you haven't already done so, create a Clerk account and follow one of their [Quickstarts](https://clerk.com/docs/quickstarts/overview) to create a client app that can obtain an access token. In order to setup your policy in the API, you'll need to navigate to the [Clerk Dashboard](https://dashboard.clerk.com/) and Navigate to the [API Keys](https://dashboard.clerk.com/last-active?path=api-keys) section. Click **Advanced** at the bottom of the page and copy the value of the **Frontend API URL**. You'll use this value later in your API policy configuration. ### [​](#set-environment-variables) Set Environment Variables Before adding the policy, you'll need to create an environment variable to store the Clerk Frontend API URL. 1. In the [Zuplo Portal](https://portal.zuplo.com) open the **Environment Variables** section in the **Settings** tab. 2. Click **Add new Variable** and enter the name `CLERK_FRONTEND_API_URL` in the name field. Set the value to the value you copied previously from the Clerk dashboard. ### [​](#add-the-clerk-policy) Add the Clerk Policy The next step is to add the Clerk JWT Auth policy to a route in your project. 1. In the [Zuplo Portal](https://portal.zuplo.com) open the **Route Designer** in the **Files** tab then click **routes.oas.json**. 2. Select or create a route that you want to authenticate with Clerk. Expand the **Policies** section and click **Add Policy**. Search for and select the Clerk JWT Auth policy. ![](https://cdn.zuplo.com/assets/c4bab517-1e42-4f68-83ce-b0ee4adca713.png) 3. With the policy selected, notice that there is a property `frontendApiUrl` that are pre-populated with environment variable names that you set in the previous section. ![](https://cdn.zuplo.com/assets/85d90802-d919-47c6-b944-c6ec3574a714.png) 4. Click **OK** to save the policy. ### [​](#test-the-policy) Test the Policy Finally, you'll make two API requests to your route to test that authentication is working as expected. 1. In the route designer on the route you added the policy, click the **Test** button. In the dialog that opens, click **Test** to make a request. 2. The API Gateway should respond with a **401 Unauthorized** response. ![](https://cdn.zuplo.com/assets/626e10a2-2350-439a-9081-1ccf1fe90cad.png) 3. Now to make an authenticated request, add a header to the request called `Authorization`. Set the value of the header to `Bearer YOUR_ACCESS_TOKEN` replacing `YOUR_ACCESS_TOKEN` with the value of the Clerk access token retrieved from your client app. ![](https://cdn.zuplo.com/assets/1486821b-cade-4041-b05b-80d3366327a5.png) 4. Click the **Test** button and a **200 OK** response should be returned. ![](https://cdn.zuplo.com/assets/8182f932-8db6-4456-842f-f65158b174c0.png) You have now setup Clerk JWT Authentication on your API Gateway. See [this document](/docs/articles/oauth-authentication) for more information about OAuth authorization in Zuplo. Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Auth0 JWT Auth Policy](/docs/policies/auth0-jwt-auth-inbound "Auth0 JWT Auth Policy") [Next page →\ \ AWS Cognito JWT Auth Policy](/docs/policies/cognito-jwt-auth-inbound "AWS Cognito JWT Auth Policy") --- # AWS Cognito JWT Auth Policy - Zuplo Docs Menu [​](#aws-cognito-jwt-auth-policy) AWS Cognito JWT Auth Policy ============================================================= Authenticate requests with JWT tokens issued by AWS Cognito. This is a customized version of the [OpenId JWT Policy](https://zuplo.com/docs/policies/open-id-jwt-auth-inbound) specifically for AWS Cognito. See [this document](https://zuplo.com/docs/articles/oauth-authentication) for more information about OAuth authorization in Zuplo. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-cognito-jwt-auth-inbound-policy", "policyType": "cognito-jwt-auth-inbound", "handler": { "export": "CognitoJwtInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "allowUnauthenticatedRequests": false, "region": "us-east-1", "userPoolId": "$env(AWS\_COGNITO\_USER\_POOL\_ID)" } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `cognito-jwt-auth-inbound`. * `handler.export` `` - The name of the exported type. Value should be `CognitoJwtInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/cognito-jwt-auth-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `allowUnauthenticatedRequests` `` - Allow unauthenticated requests to proceed. This is use useful if you want to use multiple authentication policies or if you want to allow both authenticated and non-authenticated traffic. Defaults to `false`. * `region` **(required)** `` - The AWS region where your Cognito instance is deployed. * `userPoolId` **(required)** `` - The user pool identifier. [​](#using-the-policy) Using the Policy --------------------------------------- Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Clerk JWT Auth Policy](/docs/policies/clerk-jwt-auth-inbound "Clerk JWT Auth Policy") [Next page →\ \ Firebase JWT Auth Policy](/docs/policies/firebase-jwt-inbound "Firebase JWT Auth Policy") --- # Clear Request Headers Policy - Zuplo Docs Menu [​](#clear-request-headers-policy) Clear Request Headers Policy =============================================================== Removes all headers from the incoming request except for those in the exclude list. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-clear-headers-inbound-policy", "policyType": "clear-headers-inbound", "handler": { "export": "ClearHeadersInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "exclude": \["my-header", "aws-request-id"\] } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `clear-headers-inbound`. * `handler.export` `` - The name of the exported type. Value should be `ClearHeadersInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/clear-headers-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `exclude` `` - The headers that should not be removed. [​](#using-the-policy) Using the Policy --------------------------------------- Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Remove Request Headers Policy](/docs/policies/remove-headers-inbound "Remove Request Headers Policy") [Next page →\ \ Change Method Policy](/docs/policies/change-method-inbound "Change Method Policy") --- # Clear Response Headers Policy - Zuplo Docs Menu [​](#clear-response-headers-policy) Clear Response Headers Policy ================================================================= Removes all headers from the response except for those in the exclude list. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-clear-headers-outbound-policy", "policyType": "clear-headers-outbound", "handler": { "export": "ClearHeadersOutboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "exclude": \["my-header", "aws-request-id"\] } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `clear-headers-outbound`. * `handler.export` `` - The name of the exported type. Value should be `ClearHeadersOutboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/clear-headers-outbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `exclude` `` - The headers that should not be removed. [​](#using-the-policy) Using the Policy --------------------------------------- Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Remove Response Headers Policy](/docs/policies/remove-headers-outbound "Remove Response Headers Policy") [Next page →\ \ Set Headers Policy](/docs/policies/set-headers-outbound "Set Headers Policy") --- # Change Method Policy - Zuplo Docs Menu [​](#change-method-policy) Change Method Policy =============================================== Changes the HTTP method of the incoming request. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-change-method-inbound-policy", "policyType": "change-method-inbound", "handler": { "export": "ChangeMethodInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "method": "POST" } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `change-method-inbound`. * `handler.export` `` - The name of the exported type. Value should be `ChangeMethodInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/change-method-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `method` **(required)** `` - The HTTP Method to be used, e.g. POST, GET, PUT, PATCH, etc. [​](#using-the-policy) Using the Policy --------------------------------------- Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Clear Request Headers Policy](/docs/policies/clear-headers-inbound "Clear Request Headers Policy") [Next page →\ \ Form Data to JSON Policy](/docs/policies/formdata-to-json-inbound "Form Data to JSON Policy") --- # Caching Policy - Zuplo Docs Menu [​](#caching-policy) Caching Policy =================================== Respond to matched incoming requests with cached content [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-caching-inbound-policy", "policyType": "caching-inbound", "handler": { "export": "CachingInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "cacheHttpMethods": \["GET"\], "expirationSecondsTtl": 60, "headers": "content-type", "statusCodes": \[200, 201, 404\] } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `caching-inbound`. * `handler.export` `` - The name of the exported type. Value should be `CachingInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/caching-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `cacheId` `` - Specifies an id or 'key' for this policy to store cache. This is useful for cache-busting. For example, set this property to an env var and if you change that env var value, you invalidate the cache. * `dangerouslyIgnoreAuthorizationHeader` `` - By default, the Authorization header is always considered in the caching policy. You can disable by setting this to `true`. Defaults to `false`. * `headers` `` - The headers to be considered when caching. Defaults to `[]`. * `cacheHttpMethods` `` - HTTP Methods to be cached. Valid methods are: GET, POST, PUT, PATCH, DELETE, HEAD. Defaults to `["GET"]`. * `expirationSecondsTtl` `` - The timeout of the cache in seconds. Defaults to `60`. * `statusCodes` `` - Response status codes to be cached. Defaults to `[[200,206,301,302,303,404,410]]`. [​](#using-the-policy) Using the Policy --------------------------------------- ### [​](#cache-busting) Cache-busting If you need to support cache-busting on demand, we recommend applying a `cacheId` property based on an Environment Variable. Ensure all your cache policies are using a cachedId based on a variable and then change that variable (and trigger a redeploy) to clear the cache. e.g. { "export": "CachingInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "cachedId": "$env(CACHE\_ID)", // this is reading an env var "expirationSecondsTtl": 60, "dangerouslyIgnoreAuthorizationHeader": false, "headers": \["header\_used\_as\_part\_of\_cache\_key"\] } } json Then you would setup an env var for this, we recommend using the current date it was set, e.g. `2023-07-05-11-57` and then simply change this value and trigger a redeploy to bust your cache. ![Env Var](https://cdn.zuplo.com/uploads/CleanShot%202023-07-05%20at%2011.57.48%402x.png) Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Brown Out Policy](/docs/policies/brownout-inbound "Brown Out Policy") [Next page →\ \ Custom Code Inbound Policy](/docs/policies/custom-code-inbound "Custom Code Inbound Policy") --- # Brown Out Policy - Zuplo Docs Menu [​](#brown-out-policy) Brown Out Policy ======================================= The brownout policy allows performing scheduled downtime on your API. This can be useful for helping notify clients of an impending deprecation or for scheduling maintenance. This policy uses [cron schedules](https://crontab.guru) to check if a request should experience a brownout or not. When a request falls into a scheduled brownout an error response will be return. The error response can be customized by setting the `problem` properties. For more information using brownouts to alert clients on impending API changes/deprecations see our blog post [How to version an API](https://zuplo.com/blog/2022/05/17/how-to-version-an-api) [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-brownout-inbound-policy", "policyType": "brownout-inbound", "handler": { "export": "BrownoutInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "cronSchedule": "\* 2 \* \* \*", "problem": { "type": "https://example.com/problems/deprecation-announcement", "title": "Deprecation Test", "detail": "This is a temporary brownout every day between 02:00-03:00 to alert of an upcoming deprecation.", "status": 400 } } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `brownout-inbound`. * `handler.export` `` - The name of the exported type. Value should be `BrownoutInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/brownout-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `cronSchedule` **(required)** `` - The cron schedule for when this policy is enabled. This can be a single cron string or an array of multiple cron strings. * `problem` `` - The problem that is returned in the response body when this policy is enabled. * `type` `` - The type of problem. * `title` `` - The title of problem. * `detail` `` - The detail of problem. * `status` `` - Http status code of the problem. [​](#using-the-policy) Using the Policy --------------------------------------- [​](#cron-schedules) Cron Schedules ----------------------------------- This policy accepts a single cron schedule or an array of cron schedules. Any time a requests falls withing that schedule the brownout response will be set. Example schedules could be: **Every Day between 2am and 3am** "cronSchedule": "\* 2 \* \* \*" json **Every Hour on the hour, and the 15th, 30th, and 45th minutes** "cronSchedule": \["0 \* \* \* \*", "15 \* \* \* \*", "30 \* \* \* \*", "45 \* \* \* \*"\] json This can also be written as: "cronSchedule": \["0/15 \* \* \* \*"\] json [​](#cron-expression-format) Cron Expression Format --------------------------------------------------- This policy uses the [linux cron syntax](https://man7.org/linux/man-pages/man5/crontab.5.html) with the addition that you can optionally specify seconds by prepending the minute field with another field. ┌───────────── second (0 - 59, optional) │ ┌───────────── minute (0 - 59) │ │ ┌───────────── hour (0 - 23) │ │ │ ┌───────────── day of month (1 - 31) │ │ │ │ ┌───────────── month (1 - 12) │ │ │ │ │ ┌───────────── weekday (0 - 7) \* \* \* \* \* \* txt All linux cron features are supported, including * lists * ranges * ranges in lists * step values * month names (jan,feb,... - case insensitive) * weekday names (mon,tue,... - case insensitive) * time nicknames (@yearly, @annually, @monthly, @weekly, @daily, @hourly - case insensitive) To test out cron patterns try using a tool like [crontab.guru](https://crontab.guru/) . Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Composite Inbound (Group Policies) Policy](/docs/policies/composite-inbound "Composite Inbound (Group Policies) Policy") [Next page →\ \ Caching Policy](/docs/policies/caching-inbound "Caching Policy") --- # Bot Detection Policy - Zuplo Docs Menu [​](#bot-detection-policy) Bot Detection Policy =============================================== The bot detection inbound policy provides a bot score for every request that can be used to determine the likelihood the request came from a bot. The policy can be configured to automatically block traffic with a set score or simply pass along the score for you to respond in other policies or handlers. ### Enterprise Feature This policy is only available as part of our enterprise plans. If you would like to use this in production reach out to us: [sales@zuplo.com](mailto:sales@zuplo.com) [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-bot-detection-inbound-policy", "policyType": "bot-detection-inbound", "handler": { "export": "BotDetectionInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "blockScoresBelow": 80 } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `bot-detection-inbound`. * `handler.export` `` - The name of the exported type. Value should be `BotDetectionInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/bot-detection-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `blockScoresBelow` **(required)** `` - The threshold at which bots are automatically blocked. [​](#using-the-policy) Using the Policy --------------------------------------- Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Request Validation Policy](/docs/policies/request-validation-inbound "Request Validation Policy") [Next page →\ \ Require Origin Policy](/docs/policies/require-origin-inbound "Require Origin Policy") --- # Basic Auth Policy - Zuplo Docs Menu [​](#basic-auth-policy) Basic Auth Policy ========================================= The Basic Authentication policy allows you to authenticate incoming requests using the Basic authentication standard. You can configure multiple accounts with different passwords and a different bucket of user 'data'. The API will expect a Basic Auth header (you can generate samples [using this tool](https://www.debugbear.com/basic-auth-header-generator) ). Requests with invalid credentials (or no header) will not be authenticated. Authenticated requests will populate the `user` property of the `ZuploRequest` parameter on your RequestHandler. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-basic-auth-inbound-policy", "policyType": "basic-auth-inbound", "handler": { "export": "BasicAuthInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "accounts": \[\ {\ "data": {\ "name": "John Doe",\ "email": "john.doe@gmail.com"\ },\ "password": "$env(ACCOUNT\_JOHN\_PASSWORD)",\ "username": "$env(ACCOUNT\_JOHN\_USERNAME)"\ }\ \], "allowUnauthenticatedRequests": false } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `basic-auth-inbound`. * `handler.export` `` - The name of the exported type. Value should be `BasicAuthInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/basic-auth-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `accounts` **(required)** `` - An array of account objects (username, password and data properties). * `username` **(required)** `` - The username for the account (this will be the `sub` property on `request.user`. * `password` **(required)** `` - The password for the account - note we recommend storing this in environment variables. * `data` `` - The data payload you want associated with this account (this will be the `data` property on `request.user`). * `allowUnauthenticatedRequests` `` - If 'true' allows the request to continue even if authenticated. When 'false' (the default) any unauthenticated request is automatically rejected with a 401. Defaults to `false`. [​](#using-the-policy) Using the Policy --------------------------------------- Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Curity Phantom Token Auth Policy](/docs/policies/curity-phantom-token-inbound "Curity Phantom Token Auth Policy") [Next page →\ \ mTLS Auth Policy](/docs/policies/mtls-auth-inbound "mTLS Auth Policy") --- # AuthZEN Authorization Policy - Zuplo Docs Menu [​](#authzen-authorization-policy) AuthZEN Authorization Policy =============================================================== This policy will authorize requests using a PDP (Policy Decision Point) service that is compatible with the AuthZen standard. Read more about the [AuthZen working group](https://openid.net/wg/authzen/) . It is designed to be extremely simple to configure, with a default configuration that can dynamically read the `subject`, `resource` and `action` id from the Zuplo request or context objects using the special `$authzen-prop(request.headers.user-id)` syntax. Example options: { "authorizerHostname": "example.aserto.com", "subject": { "type": "identity", "id": "$authzen-prop(request.user.sub)" }, "resource": { "type": "route", "id": "$authzen-prop(context.route.path)" }, "action": { "name": "$authzen-prop(request.method)" }, "throwOnError": true // defaults to true if not specified } json Note, the `$authzen-prop` syntax only works on this policy and on the `id` and `name` properties. ### Beta This policy is in beta. You can use it today, but it may change in non-backward compatible ways before the final release. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-authzen-inbound-policy", "policyType": "authzen-inbound", "handler": { "export": "AuthZenInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "action": { "name": "$authzen-prop(request.method)" }, "authorizerAuthorizationHeader": "Bearer $env(AUTHZEN\_PDP\_TOKEN)", "authorizerHostname": "example.aserto.com", "resource": { "id": "$authzen-prop(context.route.path)", "type": "route" }, "subject": { "id": "$authzen-prop(request.user.sub)", "type": "identity" }, "throwOnError": true } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `authzen-inbound`. * `handler.export` `` - The name of the exported type. Value should be `AuthZenInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/authzen-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `authorizerHostname` **(required)** `` - The hostname of the AuthZen PDP service. * `authorizerAuthorizationHeader` `` - The authorization header to use when communicating with the AuthZen PDP service. * `subject` **(required)** `` - The subject of the request. * `type` **(required)** `` - The type of the resource. * `id` **(required)** `` - The id of the resource. Note you can use the `$authzen-prop()` syntax to reference the resource id. * `resource` **(required)** `` - The resource of the request. Note you can use the `$authzen-prop()` syntax to reference the resource id. * `type` **(required)** `` - The type of the resource. * `id` **(required)** `` - The id of the resource. Note you can use the `$authzen-prop()` syntax to reference the resource id. * `action` **(required)** `` - The action of the request. Note you can use the `$authzen-prop()` syntax to reference the action. * `name` **(required)** `` - The name of the action. Note you can use the `$authzen-prop()` syntax to reference the action name. * `throwOnError` `` - If explicitly set to false, the policy will not throw an error if there is any problem communicating with the AuthZen PDP service and allow calls through. By default throwOnError is assumed to be on/true. Defaults to `true`. [​](#using-the-policy) Using the Policy --------------------------------------- By default, the policy will use the `subject`, `resource`, and `action` properties from the policy options file, with the special `$authzen-prop()` syntax to reference dynamic values. However, you can also have programmatic control over the payload sent to the PDP by setting the payload wholly or partially using the `setAuthorizationContext` method in a custom policy _before_ the AuthZenInboundPolicy. AuthZenInboundPolicy.setAuthorizationPayload(context, { subject: { type: "user", id: request.user.data.organization, }, resource: { type: "pizza", id: ContextData.get(context, "pizza-size"), }, action: { name: request.method }, }); ts This object will be combined with the one generated by the options with this authorization payload set on context taking priority. Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Aserto Authorization Policy](/docs/policies/aserto-authz-inbound "Aserto Authorization Policy") [Next page →\ \ Okta FGA Authorization Policy](/docs/policies/okta-fga-authz-inbound "Okta FGA Authorization Policy") --- # Axiomatics Authorization Policy - Zuplo Docs Menu [​](#axiomatics-authorization-policy) Axiomatics Authorization Policy ===================================================================== This policy will authorize requests using Axiomatics Policy Server. If the request is not authorized, a 403 response will be returned. This policy is designed to be highly customizable in order to tailor the authorization requests to the specific needs of your application. You can add default attributes on the policy that are included in every request, or you can programmatically add attributes to the request using the `setAuthAttributes` method. Using this policy in conjunction with an authorization policy will automatically set AttributeSubject attributes for the user in the request. ### Beta This policy is in beta. You can use it today, but it may change in non-backward compatible ways before the final release. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-axiomatics-authz-inbound-policy", "policyType": "axiomatics-authz-inbound", "handler": { "export": "AxiomaticsAuthZInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "pdpPassword": "$env(PDP\_PASSWORD)", "pdpUrl": "https://pdp.example.com", "pdpUsername": "pdp-user" } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `axiomatics-authz-inbound`. * `handler.export` `` - The name of the exported type. Value should be `AxiomaticsAuthZInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/axiomatics-authz-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `allowUnauthorizedRequests` `` - Indicates whether the request should continue if authorization fails. Default is `false` which means unauthorized users will automatically receive a 403 response. Defaults to `false`. * `pdpUrl` **(required)** `` - The URL to which the plugin will make a JSON POST request before proxying the original request. * `pdpUsername` **(required)** `` - The username to use when authenticating with the PDP. * `pdpPassword` **(required)** `` - The password to use when authenticating with the PDP. * `includeDefaultActionAttributes` `` - Indicates whether the plugin should include default action attributes in the authorization request. Defaults to `true`. * `includeDefaultResourceAttributes` `` - Indicates whether the plugin should include default resource attributes in the authorization request. Defaults to `true`. * `includeDefaultSubjectAttributes` `` - Indicates whether the plugin should include default subject attributes in the authorization request. Defaults to `true`. * `tokenHeaderName` `` - The name of the header that carries the JWT. Defaults to `"Authorization"`. * `accessSubjectAttributes` `` - A list of attributes that will be included in the authorization request. * `attributeId` **(required)** `` - The attribute ID that will be used in the PDP request. * `value` **(required)** `` - The value of the attribute. * `resourceAttributes` `` - A list of attributes that will be included in the authorization request. * `attributeId` **(required)** `` - The attribute ID that will be used in the PDP request. * `value` **(required)** `` - The value of the attribute. * `actionAttributes` `` - A list of attributes that will be included in the authorization request. * `attributeId` **(required)** `` - The attribute ID that will be used in the PDP request. * `value` **(required)** `` - The value of the attribute. [​](#using-the-policy) Using the Policy --------------------------------------- ### [​](#authorization-attributes) Authorization Attributes There are a few different ways authorization attributes are set on the authorization request. #### [​](#default-attributes) Default Attributes By default the policy will set the following attributes on the authorization request: * `request.user.sub` - (AccessSubject) The subject of the user making the request. Only set if the user is authenticated. * `request.method` - (Action) The HTTP method of the request. * `request.scheme` - (Resource) The scheme of the request URL. * `request.host` - (Resource) The host of the request URL. * `request.pathname` - (Resource) The pathname of the request URL. * `request.query.*` - (Resource) The value of each query parameter in the request URL. For example `?foo=baz` would set `request.query.foo=baz`. * `request.params.*` - (Resource) The value of each path parameter in the request URL. For example the route pattern `/accounts/:id` would set `request.params.accounts=value`. The default attributes can be disabled by setting the policy options that start with `includeDefault` to `false`, for example `includeDefaultResourceAttributes: false` will disable the Resource category attributes. Below is an example of the default authorization request. { "Request": { "AccessSubject": \[\ {\ "Attribute": \[\ {\ "AttributeId": "request.user.sub",\ "Value": "nate"\ }\ \]\ }\ \], "Action": \[\ {\ "Attribute": \[\ {\ "AttributeId": "request.method",\ "Value": "GET"\ }\ \]\ }\ \], "Resource": \[\ {\ "Attribute": \[\ {\ "AttributeId": "request.scheme",\ "Value": "https"\ },\ {\ "AttributeId": "request.host",\ "Value": "my-api-main-bdeec51.d2.zuplo.dev"\ },\ {\ "AttributeId": "request.pathname",\ "Value": "/test"\ },\ {\ "AttributeId": "request.params.id",\ "Value": "123"\ },\ {\ "AttributeId": "request.query.param",\ "Value": "1"\ }\ \]\ }\ \] } } json #### [​](#hard-coded-attributes) Hard Coded Attributes In some cases it cane be useful to set hard coded attributes on the policy itself. On case for this might be to set the environment the API is running in so that different policies can be applied to say a staging or development environment. An example of how you could set the `custom.environment` attribute to an environment variable is shown below. "resourceAttributes": \[\ {\ "attributeId": "custom.environment",\ "value": "$env(CUSTOM\_ENVIRONMENT)"\ }\ \] json #### [​](#programmatically-setting-attributes) Programmatically Setting Attributes For the more robust customization of the authorization request, you can set authorization attributes programmatically. This is done by running a custom inbound policy before the authorization policy. The custom policy can set any attribute on the authorization request. Below is an example of how you could set the `custom.resourceId` attribute to the value of a property in the request body. custom-attributes.ts import { ZuploContext, ZuploRequest, AxiomaticsAuthZInboundPolicy, } from "@zuplo/runtime"; export default async function policy( request: ZuploRequest, context: ZuploContext, options: MyPolicyOptionsType, policyName: string, ) { // Get the body of the request const body = await request.json(); // Set the custom attribute AxiomaticsAuthZInboundPolicy.setAuthAttributes(context, { Resource: \[\ {\ Attribute: \[\ {\ AttributeId: "custom.recordId",\ Value: body.recordId,\ },\ \],\ },\ \], }); return request; } ts Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ OpenFGA Authorization Policy](/docs/policies/openfga-authz-inbound "OpenFGA Authorization Policy") [Next page →\ \ JWT Scope Validation Policy](/docs/policies/jwt-scopes-inbound "JWT Scope Validation Policy") --- # Complex Rate Limiting Policy - Zuplo Docs Menu [​](#complex-rate-limiting-policy) Complex Rate Limiting Policy =============================================================== You can use the Complex Rate Limiting policy to limit the number of requests based on complex counters, based on details of the request or the response ### Enterprise Feature This policy is only available as part of our enterprise plans. It's free to try only any plan for development only purposes. If you would like to use this in production reach out to us: [sales@zuplo.com](mailto:sales@zuplo.com) [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-complex-rate-limit-inbound-policy", "policyType": "complex-rate-limit-inbound", "handler": { "export": "ComplexRateLimitInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "limits": { "apples": 2, "bananas": 3 }, "rateLimitBy": "ip", "timeWindowMinutes": 0.6 } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `complex-rate-limit-inbound`. * `handler.export` `` - The name of the exported type. Value should be `ComplexRateLimitInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/complex-rate-limit-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `rateLimitBy` **(required)** `` - The identifying element of the request that enforces distinct rate limits. For example, you can limit by `user`, `ip`, `function` or `all` - function allows you to specify a simple function to create a string identifier to create a rate-limit group. Allowed values are `user`, `ip`, `function`, `all`. Defaults to `"user"`. * `limits` **(required)** `` - A dictionary (string: number) of limits to be enforced across custom counters for this policy. * `timeWindowMinutes` **(required)** `` - The time window in which the requests are rate-limited. The count restarts after each window expires. Defaults to `60`. * `identifier` `` - The function that returns dynamic configuration data. Used only with `rateLimitBy=function`. * `export` **(required)** `` - used only with rateLimitBy=function. Specifies the export to load your custom bucket function, e.g. `default`, `rateLimitIdentifier`. Defaults to `""`. * `module` **(required)** `` - Specifies the module to load your custom bucket function, in the format `$import(./modules/my-module)`. Defaults to `""`. * `headerMode` `` - Adds the retry-after header. Allowed values are `none`, `retry-after`. Defaults to `"retry-after"`. * `throwOnFailure` `` - If true, the policy will throw an error in the event there is a problem connecting to the rate limit service. Defaults to `false`. * `mode` `` - The mode of the policy. If set to `async`, the policy will check if the request is over the rate limit without blocking. This can result in some requests allowed over the rate limit. Allowed values are `strict`, `async`. Defaults to `"strict"`. [​](#using-the-policy) Using the Policy --------------------------------------- This policy allows setting multiple limits that can optionally be overridden them programmatically. ### [​](#set-increments-programmatically) Set Increments Programmatically Override the increments for limits in the current request. If your policy is has a limit set as follows: "limits": { "compute": 10 } plain You can use this function to override the increment of the `compute` unites consumed on a request by calling `setIncrements(context, { compute: 5 })` on a custom policy. This can be useful if you want to dynamically change the increment of a limit based on data in the response (say a header). Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Rate Limiting Policy](/docs/policies/rate-limit-inbound "Rate Limiting Policy") [Next page →\ \ Audit Logs Policy](/docs/policies/audit-log-inbound "Audit Logs Policy") --- # Auth0 JWT Auth Policy - Zuplo Docs Menu [​](#auth0-jwt-auth-policy) Auth0 JWT Auth Policy ================================================= Authenticate requests with JWT tokens issued by Auth0. This is a customized version of the [OpenId JWT Policy](https://zuplo.com/docs/policies/open-id-jwt-auth-inbound) specifically for Auth0. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-auth0-jwt-auth-inbound-policy", "policyType": "auth0-jwt-auth-inbound", "handler": { "export": "Auth0JwtInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "allowUnauthenticatedRequests": false, "audience": "https://api.example.com/", "auth0Domain": "my-company.auth0.com" } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `auth0-jwt-auth-inbound`. * `handler.export` `` - The name of the exported type. Value should be `Auth0JwtInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/auth0-jwt-auth-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `allowUnauthenticatedRequests` `` - Allow unauthenticated requests to proceed. This is use useful if you want to use multiple authentication policies or if you want to allow both authenticated and non-authenticated traffic. Defaults to `false`. * `auth0Domain` **(required)** `` - Your Auth0 domain. For example, `my-company.auth0.com`. * `audience` `` - The Auth0 audience of your API, for example `https://api.example.com/`. [​](#using-the-policy) Using the Policy --------------------------------------- Adding Auth0 to your route takes just a few steps, but before you can add the policy you'll need to have Auth0 setup for API Authentication. ### [​](#setup-auth0) Setup Auth0 To use Auth0 as an API authentication provider, you'll need to create both an Application and an API in the Auth0 dashboard. The steps below cover the basics, but if you need more details see the Auth0 links throughout this document. 1. Create the Auth0 API ([Auth0 Doc](https://auth0.com/docs/get-started/auth0-overview/set-up-apis) ) In the Auth0 dashboard, select **APIs** on the sidebar, then click the **\+ Create API** button. Enter the **Name** and **Identifier** of your application. The identifier is usually a URI such as `https://api.example.com/`. The URL used in the identifier does NOT have to be the URL of your actual API. A common practice is to use the URL of your production API. Save this value, you'll use it in the next section. 2. Get the Auth0 Domain On your newly created Auth0 API, click the **Test** tab. This tabs shows how to create a [Machine-to-Machine](https://auth0.com/docs/get-started/authentication-and-authorization-flow/call-your-api-using-the-client-credentials-flow) access token from a test application that Auth0 automatically created for your API. From the first code block on this page, find the URL value as shown below. Copy the **hostname** portion (outlined in red) of this URL (not the `https://` or the trailing `/oauth/token` parts). For example `your-account.us.auth0.com`. Save this value, you'll use it in the next section. ![Auth0 Access Token](https://cdn.zuplo.com/assets/53f91f6d-17c2-469d-9e23-ac3beb9a804b.png) 3. Get an Access Token Find the code block that contains the `access_token` and copy the **entire** token value (without the quotes) and save it. You'll use this later to test your Auth0 JWT policy in Zuplo. ![Auth0 Access Token](https://cdn.zuplo.com/assets/991dbd66-2bb9-4bc1-8ae0-8d928b5dcb7e.png) ### [​](#set-environment-variables) Set Environment Variables Before adding the policy, there are a few environment variables that will need to be set that will be used in the Auth0 JWT Policy. It is very important in the next steps that the values match **EXACTLY** as they are found in Auth0. 1. In the [Zuplo Portal](https://portal.zuplo.com) open the **Environment Variables** section in the **Settings** tab. 2. Click **Add new Variable** and enter the name `AUTH0_DOMAIN` in the name field. Set the value to your Auth0 domain. 3. Click **Add new Variable** again and enter the name `AUTH0_AUDIENCE` in the name field. Set the value to the **identifier** URI you used when creating the Auth0 API in the section above (i.e. `https://api.example.com/`). ### [​](#add-the-auth0-policy) Add the Auth0 Policy The next step is to add the Auth0 JWT Auth policy to a route in your project. 1. In the [Zuplo Portal](https://portal.zuplo.com) open the **Route Designer** in the **Files** tab then click **routes.oas.json**. 2. Select or create a route that you want to authenticate with Auth0. Expand the **Policies** section and click **Add Policy**. Search for and select the Auth0 JWT Auth policy. ![](https://cdn.zuplo.com/assets/40c72bc5-be30-4246-809c-58d4ecb18f9e.png) 3. With the policy selected, notice that there are two properties, `auth0Domain` and `audience` that are pre-populated with environment variable names that you set in the previous section. ![](https://cdn.zuplo.com/assets/2aa3fc6a-0e9c-47f6-b08d-c1cc446e54b9.png) 4. Click **OK** to save the policy. ### [​](#test-the-policy) Test the Policy Finally, you'll make two API requests to your route to test that authentication is working as expected. 1. In the route designer on the route you added the policy, click the **Test** button. In the dialog that opens, click **Test** to make a request. 2. The API Gateway should respond with a **401 Unauthorized** response. ![](https://cdn.zuplo.com/assets/626e10a2-2350-439a-9081-1ccf1fe90cad.png) 3. Now to make an authenticated request, add a header to the request called `Authorization`. Set the value of the header to `Bearer YOUR_ACCESS_TOKEN` replacing `YOUR_ACCESS_TOKEN` with the value of the Auth0 access token you saved from the first section of this tutorial. ![](https://cdn.zuplo.com/assets/1486821b-cade-4041-b05b-80d3366327a5.png) 4. Click the **Test** button and a **200 OK** response should be returned. ![](https://cdn.zuplo.com/assets/8182f932-8db6-4456-842f-f65158b174c0.png) You have now setup Auth0 JWT Authentication on your API Gateway. See [this document](/docs/articles/oauth-authentication) for more information about OAuth authorization in Zuplo. Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ API Key Authentication Policy](/docs/policies/api-key-inbound "API Key Authentication Policy") [Next page →\ \ Clerk JWT Auth Policy](/docs/policies/clerk-jwt-auth-inbound "Clerk JWT Auth Policy") --- # Audit Logs Policy - Zuplo Docs Menu [​](#audit-logs-policy) Audit Logs Policy ========================================= Audit logging is an important part of API security that plays a critical role in detecting and correcting issues such as unauthorized access or permission elevations within your system. Audit logging is also a requirement for many compliance certifications as well as part of the buying criteria for larger enterprises. Adding Audit Logging to your APIs that are secured with Zuplo is as easy as adding a policy. Typically you want to add audit logs to any API that modifies data, however depending on the API you may want it on read operations as well (i.e. retrieve a secret key, etc.) ### Enterprise Feature This policy is only available as part of our enterprise plans. If you would like to use this in production reach out to us: [sales@zuplo.com](mailto:sales@zuplo.com) [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-audit-log-inbound-policy", "policyType": "audit-log-inbound", "handler": { "export": "AuditLogsInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "logGeolocation": true, "logIpAddress": true, "logQueryParameters": true, "logRouteParameters": true, "logUser": true } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `audit-log-inbound`. * `handler.export` `` - The name of the exported type. Value should be `AuditLogsInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/audit-log-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `logIpAddress` `` - if the IP address should be logged. Defaults to `true`. * `logUser` `` - if the user's `sub` should be logged. Defaults to `true`. * `logGeolocation` `` - if the geolocation information should be logged (i.e. state, country, longitude, latitude, etc.). Defaults to `true`. * `logQueryParameters` `` - log the values of query parameters. Defaults to `true`. * `logRouteParameters` `` - The parameters in the route to log. Defaults to `true`. * `tenant` `` - if the route parameters should be logged (i.e. the value of `customerId` in the route `/customers/:customerId`). * `metadata` `` - A function to add additional data to the audit logs. [​](#using-the-policy) Using the Policy --------------------------------------- [​](#adding-custom-metadata) Adding Custom Metadata --------------------------------------------------- You can add any additional data to the audit logs with a custom function. Custom metadata functions cannot be asynchronous. Due to the frequency of their calls, asynchronous functions will add significant latency to your API. //module - ./modules/audit-logs.ts import { ZuploRequest } from "@zuplo/runtime"; export function auditLogMetadata(request: ZuploRequest): any { const metadata = { accountId: request.user.data.account, customTraceId: request.headers.get("custom-trace-id"), }; return metadata; } ts [​](#log-data) Log Data ----------------------- The structure of an audit log is shown below. { "route": "/customers/:customerId", "method": "GET", "query": { "a": 1, "b": 2 }, "params": { "customerId": "12345" }, "headers": { "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10\_15\_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.41 Safari/537.36" }, "user": { "sub": "user|12356" }, "geolocation": { "country": "US", "city": "Seattle", "continent": "NA", "latitude": "1.123", "longitude": "4.567", "postalCode": "29700", "metroCode": "100", "region": "Washington", "timezone": "America/LosAngeles" }, "metadata": { // Custom data } } json [​](#audit-logs-in-the-portal) Audit Logs in the Portal ------------------------------------------------------- Audit logs are not currently surfaced in the Zuplo portal, but the feature is planned soon. [​](#audit-log-api) Audit Log API --------------------------------- Audit logs can be retrieved using the Zuplo Management API. Logs can be retrieved by time span and can be filtered by `tenant`. GET /deployments/:deploymentId/auditlogs?tenant=TENANT content-type: application/json authorization: Bearer YOUR\_TOKEN http Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Complex Rate Limiting Policy](/docs/policies/complex-rate-limit-inbound "Complex Rate Limiting Policy") [Next page →\ \ Request Validation Policy](/docs/policies/request-validation-inbound "Request Validation Policy") --- # Archive Response to Azure Storage Policy - Zuplo Docs Menu [​](#archive-response-to-azure-storage-policy) Archive Response to Azure Storage Policy ======================================================================================= ### Custom Policy Example Zuplo is extensible, so we don't have a built-in policy for Archive Response to Azure Storage, instead we've a template here that shows you how you can use your superpower (code) to achieve your goals. To learn more about custom policies [see the documentation](/docs/policies/custom-code-outbound) . In this example shows how you can archive the body of outgoing responses to Azure Blob Storage. This can be useful for auditing, logging, or archival scenarios. import { HttpProblems, ZuploContext, ZuploRequest } from "@zuplo/runtime"; interface PolicyOptions { blobContainerPath: string; blobCreateSas: string; } export default async function ( response: Response, request: ZuploRequest, context: ZuploContext, options: PolicyOptions, ) { // NOTE: policy options should be validated, but to keep the sample short, // we are skipping that here. // because we will read the body, we need to // create a clone of this response first, otherwise // there may be two attempts to read the body // causing a runtime error const clone = response.clone(); // In this example we assume the body could be text, but you could also // response the blob() to handle binary data types like images. // // This example loads the entire body into memory. This is fine for // small payloads, but if you have a large payload you should instead // save the body via streaming. const body = await clone.text(); // let's generate a unique blob name based on the date and requestId const blobName = \`${Date.now()}-${context.requestId}.req.txt\`; const url = \`${options.blobContainerPath}/${blobName}?${options.blobCreateSas}\`; const result = await fetch(url, { method: "PUT", body: body, headers: { "x-ms-blob-type": "BlockBlob", }, }); if (result.status > 201) { const text = await result.text(); context.log.error("Error saving file to storage", text); return HttpProblems.internalServerError(request, context, { detail: text, }); } // Continue the response return response; } ts [​](#configuration) Configuration --------------------------------- The example below shows how to configure a custom code policy in the 'policies.json' document that utilizes the above example policy code. { "name": "my-archive-response-azure-storage-outbound-policy", "policyType": "archive-response-azure-storage-outbound", "handler": { "\_name": "basic", "export": "default", "module": "$import(./modules/YOUR\_MODULE)", "options": { "blobCreateSas": "$env(BLOB\_CREATE\_SAS)", "blobContainerPath": "$env(BLOB\_CONTAINER\_PATH)" } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `archive-response-azure-storage-outbound`. * `handler.export` `` - The name of the exported type. Value should be `default`. * `handler.module` `` - The module containing the policy. Value should be `$import(./modules/YOUR_MODULE)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/archive-response-azure-storage-outbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `blobCreateSas` `` - The Azure shared access token with permission to write to the bucket * `blobContainerPath` `` - The path to the Azure blob container [​](#using-the-policy) Using the Policy --------------------------------------- [​](#using-the-policy-1) Using the Policy ----------------------------------------- In order to use this policy, you'll need to setup Azure storage. You'll find instructions on how to do that below. ### [​](#setup-azure) Setup Azure First, let's set up Azure. You'll need a container in Azure storage ([docs](https://docs.microsoft.com/en-us/azure/storage/common/storage-account-create?tabs=azure-portal) ). Once you have your container you'll need the URL - you can get it on the `properties` tab of your container as shown below. ![Azure](https://cdn.zuplo.com/docs/assets/Untitled-Cr4O4p8L.png) This URL will be the `blobPath` in our policy options. Next, we'll need a SAS (Shared Access Secret) to authenticate with Azure. You can generate one of these on the `Shared access tokens` tab. Note, you should minimize the permissions - and select only the `Create` permission. Choose a sensible start and expiration time for your token. Note, we don't recommend restricting IP addresses because Zuplo runs at the edge in over 200 data-centers world-wide. ![Create permission](https://cdn.zuplo.com/docs/assets/Untitled_1-DgZzuW8r.png) Then generate your SAS token - copy the token (not the URL) to the clipboard and enter it into a new environment variable in your API called `BLOB_CREATE_SAS`. You'll need another environment variable called `BLOB_CONTAINER_PATH`. ![SAS token](https://cdn.zuplo.com/docs/assets/Untitled_2-CR0W8DT6.png) Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Archive Request to AWS S3 Policy](/docs/policies/archive-request-aws-s3-inbound "Archive Request to AWS S3 Policy") [Next page →\ \ Archive Response to AWS S3 Policy](/docs/policies/archive-response-aws-s3-outbound "Archive Response to AWS S3 Policy") --- # Aserto Authorization Policy - Zuplo Docs Menu [​](#aserto-authorization-policy) Aserto Authorization Policy ============================================================= This policy will authorize requests using Aserto. If the request is not authorized, a 403 response will be returned. This policy is designed to be highly customizable in order to tailor the authorization requests to the specific needs of your application. You can use the default authorization context, or you can programmatically add attributes to the request using the `setAuthorizationContext` method. Using this policy in conjunction with an authorization policy will automatically set the `identity_context` for the user in the request. ### Beta This policy is in beta. You can use it today, but it may change in non-backward compatible ways before the final release. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-aserto-authz-inbound-policy", "policyType": "aserto-authz-inbound", "handler": { "export": "AsertoAuthZInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "authorizerApiKey": "f1381f61.......f3dw31", "policyName": "api-auth", "tenantId": "070e5e6d-f71d-4419-aa8f-4a99207bce2b" } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `aserto-authz-inbound`. * `handler.export` `` - The name of the exported type. Value should be `AsertoAuthZInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/aserto-authz-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `allowUnauthorizedRequests` `` - Indicates whether the request should continue if authorization fails. Default is `false` which means unauthorized users will automatically receive a 403 response. Defaults to `false`. * `tenantId` **(required)** `` - The Aserto Tenant ID. * `authorizerApiKey` **(required)** `` - The Aserto API key. * `authorizerApiUrl` `` - The Aserto Authorizer API URL. Defaults to `"https://authorizer.prod.aserto.com"`. * `policyName` `` - The policy instance name. Defaults to `"api-auth"`. * `serviceName` **(required)** `` - Canonicalized service name. * `userSubPropertyPath` `` - The path to the user's sub property in the request. Defaults to `".sub"`. [​](#using-the-policy) Using the Policy --------------------------------------- ### [​](#authorization-attributes) Authorization Attributes There are two options for authorization attributes in the Aserto Policy. You can use the default attributes or you can programmatically add attributes to the request using the `setAuthorizationContext` method. #### [​](#default-attributes) Default Attributes If you don't set any attributes, the policy will automatically use the following authorization context. The `identity_context` will be set to the user's sub. The `user` property value can be customized by setting the `userSubPropertyPath` option. For example, if you want to get the user's email address and you have set an `email` property on the API Key Metadata, you can set the value to `.data.email`. Similarly, you can select values on JWT tokens by setting the value to `.data.claim`. The `resource_context` will be set to the `object_type` and `relation` properties as shown in the example below. The `object_id` will be set to a concatenation of the service name, request method, and route path. The `policy_context` will be set to the `decisions` and `path` properties as shown in the example below. The `policy_instance` will be set to the `authorizerPolicyName` property set in the policies `options`. { "identity\_context": { "type": "IDENTITY\_TYPE\_SUB", "identity": "user-sub-id" }, "resource\_context": { "object\_type": "endpoint", "object\_id": "SERVICE\_NAME:REQUEST\_METHOD:ROUTE\_PATH", "relation": "can\_invoke" }, "policy\_context": { "decisions": \["allowed"\], "path": "rebac.check" }, "policy\_instance": { "name": "AUTHORIZATION\_POLICY\_NAME", "instance\_label": "AUTHORIZATION\_POLICY\_NAME" } } json #### [​](#programmatically-setting-attributes) Programmatically Setting Attributes For the more robust customization of the authorization request, you can set authorization context programmatically. This is done by running a custom inbound policy before the authorization policy. The custom policy can set any attribute on the authorization request. Below is an example of how you could set the `resource_context.id` attribute to the value of the `id` route parameter. custom-context.ts import { ZuploContext, ZuploRequest, AsertoAuthZInboundPolicy, } from "@zuplo/runtime"; export default async function policy( request: ZuploRequest, context: ZuploContext, options: MyPolicyOptionsType, policyName: string, ) { // Set the custom context AsertoAuthZInboundPolicy.setAuthorizationContext(context, { resource\_context: { id: request.params.id, type: "resource", }, policy\_instance: { name: "todo", instance\_label: "todo", }, policy\_context: { decisions: \["allowed"\], path: "todoApp.GET.todos", }, }); return request; } ts Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ HMAC Auth Policy](/docs/policies/hmac-auth-inbound "HMAC Auth Policy") [Next page →\ \ AuthZEN Authorization Policy](/docs/policies/authzen-inbound "AuthZEN Authorization Policy") --- # API Key Authentication Policy - Zuplo Docs Menu [​](#api-key-authentication-policy) API Key Authentication Policy ================================================================= You can learn more about the Zuplo API Key Service [in our documentation](https://zuplo.com/docs/articles/api-key-api#buckets) Authenticate requests with Zuplo's fully managed API Key service. This policy is the easiest way to secure your API and can be combined with other policies like Rate limiting, quotas, and more to build a fully featured API to support your partners, developers, or customers. For more information on Zuplo's API Key Management service and options enabling self-serve API Key management see the following resources: * [API Key Authentication Overview](https://zuplo.com/docs/articles/api-key-management) * [API Key Management API](https://zuplo.com/docs/articles/api-key-api) [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-api-key-inbound-policy", "policyType": "api-key-inbound", "handler": { "export": "ApiKeyInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "allowUnauthenticatedRequests": false, "cacheTtlSeconds": 60 } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `api-key-inbound`. * `handler.export` `` - The name of the exported type. Value should be `ApiKeyInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/api-key-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `authHeader` `` - The name of the header with the key. Defaults to `"Authorization"`. * `authScheme` `` - The scheme used on the header. Defaults to `"Bearer"`. * `bucketName` `` - The name of the API Key service bucket. Defaults to the autogenerated bucket name for your project. * `allowUnauthenticatedRequests` `` - If requests should proceed even if the policy does not successfully authenticate the request. Defaults to false and rejects any request without a valid API key (returning a `401 - Unauthorized` response). Set to `true` to support multiple authentication methods or support both authenticated and anonymous requests. Defaults to `false`. * `cacheTtlSeconds` `` - The time to cache authentication results for a particular key. Higher values will decrease latency. Cached results will be valid until the cache expires even in the event the key is deleted, etc. Defaults to `60`. * `disableAutomaticallyAddingKeyHeaderToOpenApi` `` - Zuplo will automatically document your API key header within your OpenAPI specification & Developer Portal. Set this to `true` to disable this behavior. [​](#using-the-policy) Using the Policy --------------------------------------- Adding API Key authentication to your Zuplo API takes only a few minutes. This document shows you how to add the policy to your routes, create an API key, and make a request using the API Key. [​](#add-the-api-key-policy) Add the API Key Policy --------------------------------------------------- The first step to setting up API Key authentication is to add the API Authentication policy to a route in your project. 1. In the [Zuplo Portal](https://portal.zuplo.com) open the **Route Designer** in the **Files** tab then click **routes.oas.json**. 2. Select or create a route that you want to authenticate with API Keys. Expand the **Policies** section and click **Add Policy**. Search for and select the Auth0 JWT Auth policy. ![](https://cdn.zuplo.com/assets/1a35f4e6-9309-4f22-89da-2e2c25e68403.png) 3. With the policy selected, you will see the configuration and information about the options. For this tutorial just leave the options as they are and click **OK** to save the policy. ![](https://cdn.zuplo.com/assets/736fad78-37c8-4f12-9e58-8e697a14284c.png) [​](#create-an-api-key) Create an API Key ----------------------------------------- In order to make a request to the route, you'll need an API Key. 1. In the [Zuplo Portal](https://portal.zuplo.com) open the **API Key Consumers** section in the **Settings** tab. 2. Click the button **Add New Consumer**. 3. In the form that appears, enter a value for the **Subject** such as `my-test`. You can leave the other fields empty. Click **OK** to create the consumer. ![](https://cdn.zuplo.com/assets/68b4571d-fcbc-4c92-977f-7612cd0cfb32.png) 4. Now you can see the newly created consumer and its default API key. Select the**Copy** button to copy the API Key. You will use this value in the next section. ![](https://cdn.zuplo.com/assets/98a3d62f-1b61-4f41-8bac-665e0b02309e.png) ### [​](#test-the-policy) Test the Policy Finally, you'll make two API requests to your route to test that authentication is working as expected. 1. In the route designer on the route you added the policy, click the **Test** button. In the dialog that opens, click **Test** to make a request. 2. The API Gateway should respond with a **401 Unauthorized** response. ![](https://cdn.zuplo.com/assets/626e10a2-2350-439a-9081-1ccf1fe90cad.png) 3. Now to make an authenticated request, add a header to the request called `Authorization`. Set the value of the header to `Bearer YOUR_API_KEY` replacing `YOUR_API_KEY` with the value of the API Key you copied in the previous section. ![](https://cdn.zuplo.com/assets/11a3f88a-8613-43c9-9429-4c82e1f1ab4d.png) 4. Click the **Test** button and a **200 OK** response should be returned. ![](https://cdn.zuplo.com/assets/8182f932-8db6-4456-842f-f65158b174c0.png) You have now setup API Key Authentication on your API Gateway. See [this document](/docs/articles/api-key-management) for more information about API Keys and API Key Management with Zuplo. [​](#writing-tests-with-the-auth-policy) Writing Tests with the Auth Policy --------------------------------------------------------------------------- For information on running tests while using API Key Authentication see the document [Testing API Key Authentication](/docs/articles/testing-api-key-authentication) . Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Policy Fundamentals](/docs/articles/policies "Policy Fundamentals") [Next page →\ \ Auth0 JWT Auth Policy](/docs/policies/auth0-jwt-auth-inbound "Auth0 JWT Auth Policy") --- # Archive Response to AWS S3 Policy - Zuplo Docs Menu [​](#archive-response-to-aws-s3-policy) Archive Response to AWS S3 Policy ========================================================================= ### Custom Policy Example Zuplo is extensible, so we don't have a built-in policy for Archive Response to AWS S3, instead we've a template here that shows you how you can use your superpower (code) to achieve your goals. To learn more about custom policies [see the documentation](/docs/policies/custom-code-outbound) . In this example shows how you can archive the body of outgoing responses to AWS S3 Storage. This can be useful for auditing, logging, or archival scenarios. import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3"; import { ZuploContext, ZuploRequest } from "@zuplo/runtime"; interface PolicyOptions { region: string; bucketName: string; path: string; accessKeyId: string; accessKeySecret: string; } export default async function ( response: Response, request: ZuploRequest, context: ZuploContext, options: PolicyOptions, ) { // NOTE: policy options should be validated, but to keep the sample short, // we are skipping that here. // Initialize the S3 client const s3Client = new S3Client({ region: options.region, credentials: { accessKeyId: options.accessKeyId, secretAccessKey: options.accessKeySecret, }, }); // Create the file const file = \`${options.path}/${Date.now()}-${crypto.randomUUID()}.req.txt\`; // because we will read the body, we need to // create a clone of this response first, otherwise // there may be two attempts to read the body // causing a runtime error const clone = response.clone(); // In this example we assume the body could be text, but you could also // response the blob() to handle binary data types like images. // // This example loads the entire body into memory. This is fine for // small payloads, but if you have a large payload you should instead // save the body via streaming. const body = await clone.text(); // Create the S3 command const command = new PutObjectCommand({ Bucket: options.bucketName, Key: file, Body: body, }); // Use the S3 client to save the object await s3Client.send(command); // Continue the response return response; } ts [​](#configuration) Configuration --------------------------------- The example below shows how to configure a custom code policy in the 'policies.json' document that utilizes the above example policy code. { "name": "my-archive-response-aws-s3-outbound-policy", "policyType": "archive-response-aws-s3-outbound", "handler": { "\_name": "basic", "export": "default", "module": "$import(./modules/YOUR\_MODULE)", "options": { "region": "us-east-1", "bucketName": "test-bucket-123.s3.amazonaws.com", "path": "responses/", "accessKeyId": "$env(AWS\_ACCESS\_KEY\_ID)", "accessKeySecret": "$env(AWS\_ACCESS\_KEY\_SECRET)" } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `archive-response-aws-s3-outbound`. * `handler.export` `` - The name of the exported type. Value should be `default`. * `handler.module` `` - The module containing the policy. Value should be `$import(./modules/YOUR_MODULE)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/archive-response-aws-s3-outbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `region` `` - The AWS region where the bucket is located * `bucketName` `` - The name of the storage bucket * `path` `` - The path where requests are stored * `accessKeyId` `` - The Access Key ID of the account authorized to write to the bucket * `accessKeySecret` `` - The Access Key Secret of the account authorized to write to the bucket [​](#using-the-policy) Using the Policy --------------------------------------- Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Archive Response to Azure Storage Policy](/docs/policies/archive-response-azure-storage-outbound "Archive Response to Azure Storage Policy") [Next page →\ \ GraphQL Disable Introspection Policy](/docs/policies/graphql-disable-introspection-inbound "GraphQL Disable Introspection Policy") --- # Archive Request to AWS S3 Policy - Zuplo Docs Menu [​](#archive-request-to-aws-s3-policy) Archive Request to AWS S3 Policy ======================================================================= ### Custom Policy Example Zuplo is extensible, so we don't have a built-in policy for Archive Request to AWS S3, instead we've a template here that shows you how you can use your superpower (code) to achieve your goals. To learn more about custom policies [see the documentation](/docs/policies/custom-code-inbound) . In this example shows how you can archive the body of incoming requests to AWS S3 Storage. This can be useful for auditing, logging, or archival scenarios. Additionally, you could use this policy to save the body of a request and then enqueue some asynchronous work that uses this body. import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3"; import { ZuploContext, ZuploRequest } from "@zuplo/runtime"; type PolicyOptions = { region: string; bucketName: string; path: string; accessKeyId: string; accessKeySecret: string; }; export default async function ( request: ZuploRequest, context: ZuploContext, options: PolicyOptions, policyName: string, ) { // NOTE: policy options should be validated, but to keep the sample short, // we are skipping that here. // Initialize the S3 client const s3Client = new S3Client({ region: options.region, credentials: { accessKeyId: options.accessKeyId, secretAccessKey: options.accessKeySecret, }, }); // Create the file const file = \`${options.path}/${Date.now()}-${crypto.randomUUID()}.req.txt\`; // because we will read the body, we need to // create a clone of this request first, otherwise // there may be two attempts to read the body // causing a runtime error const clone = request.clone(); // In this example we assume the body could be text, but you could also // request the blob() to handle binary data types like images. // // This example loads the entire body into memory. This is fine for // small payloads, but if you have a large payload you should instead // save the body via streaming. const body = await clone.text(); // Create the S3 command const command = new PutObjectCommand({ Bucket: options.bucketName, Key: file, Body: body, }); // Use the S3 client to save the object await s3Client.send(command); // Continue the request return request; } ts [​](#configuration) Configuration --------------------------------- The example below shows how to configure a custom code policy in the 'policies.json' document that utilizes the above example policy code. { "name": "my-archive-request-aws-s3-inbound-policy", "policyType": "archive-request-aws-s3-inbound", "handler": { "\_name": "basic", "export": "ArchiveResponseOutbound", "module": "$import(@zuplo/runtime)", "options": { "region": "us-east-1", "bucketName": "test-bucket-123.s3.amazonaws.com", "path": "responses/", "accessKeyId": "$env(AWS\_ACCESS\_KEY\_ID)", "accessKeySecret": "$env(AWS\_ACCESS\_KEY\_SECRET)" } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `archive-request-aws-s3-inbound`. * `handler.export` `` - The name of the exported type. Value should be `default`. * `handler.module` `` - The module containing the policy. Value should be `$import(./modules/YOUR_MODULE)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/archive-request-aws-s3-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `region` `` - The AWS region where the bucket is located * `bucketName` `` - The name of the storage bucket * `path` `` - The path where requests are stored * `accessKeyId` `` - The Access Key ID of the account authorized to write to the bucket * `accessKeySecret` `` - The Access Key Secret of the account authorized to write to the bucket [​](#using-the-policy) Using the Policy --------------------------------------- Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Archive Request to GCP Storage Policy](/docs/policies/archive-request-gcp-storage-inbound "Archive Request to GCP Storage Policy") [Next page →\ \ Archive Response to Azure Storage Policy](/docs/policies/archive-response-azure-storage-outbound "Archive Response to Azure Storage Policy") --- # Archive Request to GCP Storage Policy - Zuplo Docs Menu [​](#archive-request-to-gcp-storage-policy) Archive Request to GCP Storage Policy ================================================================================= ### Custom Policy Example Zuplo is extensible, so we don't have a built-in policy for Archive Request to GCP Storage, instead we've a template here that shows you how you can use your superpower (code) to achieve your goals. To learn more about custom policies [see the documentation](/docs/policies/custom-code-inbound) . In this example shows how you can archive the body of incoming requests to Google Cloud Storage. This can be useful for auditing, logging, or archival scenarios. Additionally, you could use this policy to save the body of a request and then enqueue some asynchronous work that uses this body. import { HttpProblems, ZuploContext, ZuploRequest } from "@zuplo/runtime"; type GoogleStoragePolicyOptions = { bucketName: any; }; export default async function policy( request: ZuploRequest, context: ZuploContext, options: GoogleStoragePolicyOptions, policyName: string, ) { // NOTE: policy options should be validated, but to keep the sample short, // we are skipping that here. // because we will read the body, we need to // create a clone of this request first, otherwise // there may be two attempts to read the body // causing a runtime error const clone = request.clone(); // In this example we assume the body could be text, but you could also // request the blob() to handle binary data types like images. // // This example loads the entire body into memory. This is fine for // small payloads, but if you have a large payload you should instead // save the body via streaming. const body = await clone.text(); // generate a unique blob name based on the date and requestId const objectName = \`${Date.now()}-${context.requestId}\`; const authHeader = request.headers.get("Authorization"); // This uses simple uploads where the parameters are in the query string, you // could also use multipart uploads to set more properties // See: https://cloud.google.com/storage/docs/uploading-objects#rest-upload-objects const url = new URL( \`https://storage.googleapis.com/upload/storage/v1/b/${options.bucketName}/o\`, ); url.searchParams.set("uploadType", "media"); url.searchParams.set("name", objectName); const response = await fetch(url.toString(), { method: "POST", body: body, headers: { // Using the authorization header generated by the previous policy authorization: authHeader, // change to whatever content type you want to save "Content-Type": "text/plain", }, }); if (response.status > 201) { const text = await response.text(); context.log.error( \`Error saving file to storage in policy ${policyName}.\`, text, ); return HttpProblems.internalServerError(request, context, { detail: text, }); } // continue return request; } ts [​](#configuration) Configuration --------------------------------- The example below shows how to configure a custom code policy in the 'policies.json' document that utilizes the above example policy code. { "name": "my-archive-request-gcp-storage-inbound-policy", "policyType": "archive-request-gcp-storage-inbound", "handler": { "export": "default", "module": "$import(./modules/YOUR\_MODULE)", "options": { "bucketName": "my-bucket" } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `archive-request-gcp-storage-inbound`. * `handler.export` `` - The name of the exported type. Value should be `default`. * `handler.module` `` - The module containing the policy. Value should be `$import(./modules/YOUR_MODULE)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/archive-request-gcp-storage-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `bucketName` `` - The name of the bucket to archive the request. [​](#using-the-policy) Using the Policy --------------------------------------- [​](#using-the-policy-1) Using the Policy ----------------------------------------- In order to use this policy, you'll need to setup Google Cloud Storage, create an IAM Service Account, and configure the [Upstream GCP Service Auth Policy](/docs/policies/upstream-gcp-service-auth-inbound) . You'll find instructions on how to do that below. ### [​](#setup-a-google-service-account) Setup a Google Service Account In order to authorize your Zuplo API to upload files to Google Storage, you will need to create a Service Account. Instructions for doing so can be found here: [https://cloud.google.com/iam/docs/service-accounts-create](https://cloud.google.com/iam/docs/service-accounts-create) The service account you create will also need permissions to write objects to the storage bucket you will use. The easiest way to do that's to assign the account the **Storage Object Creator (roles/storage.objectCreator)** role. However, you can also scope the permissions to a single bucket if you like. Download the service account JSON and create an environment variable secret with the contents. In this example, the variable is named `SERVICE_ACCOUNT_JSON` ### [​](#setup-google-cloud-storage) Setup Google Cloud Storage In order to use Google Cloud Storage you will need to have a bucket created. If you don't have one you can do so by following this guide: [https://cloud.google.com/storage/docs/creating-buckets](https://cloud.google.com/storage/docs/creating-buckets) ### [​](#upstream-gcp-service-auth-policy) Upstream GCP Service Auth Policy In order to authorize your Zuplo API to upload to the GCP bucket, you will configured the [Upstream GCP Service Auth Policy](/docs/policies/upstream-gcp-service-auth-inbound) . It's important that the auth policy runs **before** this custom policy. The service auth policy will set the `Authorization` header of the request to a JWT token with the requested permissions. In order to generate the correct JWT, you must set the `scopes` to `https://www.googleapis.com/auth/devstorage.read_write` as shown below. { "export": "UpstreamGcpServiceAuthInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "expirationOffsetSeconds": 300, "scopes": \["https://www.googleapis.com/auth/devstorage.read\_write"\], "serviceAccountJson": "$env(SERVICE\_ACCOUNT\_JSON)", "tokenRetries": 3 } } json You can have multiple Upstream GCP Service Auth Policies on the same request. So for example, you might generate a JWT token that first has permission to upload to GCP storage, then you might have a second policy that runs after this policy that authorizes your Zuplo API to all downstream Cloud Run service. Each auth policy will cache the JWT tokens for an hour by default so having multiple policies will have virtually no impact on your APIs latency. Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Archive Request to Azure Storage Policy](/docs/policies/archive-request-azure-storage-inbound "Archive Request to Azure Storage Policy") [Next page →\ \ Archive Request to AWS S3 Policy](/docs/policies/archive-request-aws-s3-inbound "Archive Request to AWS S3 Policy") --- # Archive Request to Azure Storage Policy - Zuplo Docs Menu [​](#archive-request-to-azure-storage-policy) Archive Request to Azure Storage Policy ===================================================================================== ### Custom Policy Example Zuplo is extensible, so we don't have a built-in policy for Archive Request to Azure Storage, instead we've a template here that shows you how you can use your superpower (code) to achieve your goals. To learn more about custom policies [see the documentation](/docs/policies/custom-code-inbound) . In this example shows how you can archive the body of incoming requests to Azure Blob Storage. This can be useful for auditing, logging, or archival scenarios. Additionally, you could use this policy to save the body of a request and then enqueue some asynchronous work that uses this body. import { HttpProblems, ZuploContext, ZuploRequest } from "@zuplo/runtime"; interface PolicyOptions { blobContainerPath: string; blobCreateSas: string; } export default async function ( request: ZuploRequest, context: ZuploContext, options: PolicyOptions, policyName: string, ) { // NOTE: policy options should be validated, but to keep the sample short, // we are skipping that here. // because we will read the body, we need to // create a clone of this request first, otherwise // there may be two attempts to read the body // causing a runtime error const clone = request.clone(); // In this example we assume the body could be text, but you could also // request the blob() to handle binary data types like images. // // This example loads the entire body into memory. This is fine for // small payloads, but if you have a large payload you should instead // save the body via streaming. const body = await clone.text(); // generate a unique blob name based on the date and requestId const blobName = \`${Date.now()}-${context.requestId}.req.txt\`; const url = \`${options.blobContainerPath}/${blobName}?${options.blobCreateSas}\`; const result = await fetch(url, { method: "PUT", body: body, headers: { "x-ms-blob-type": "BlockBlob", }, }); if (result.status > 201) { const text = await result.text(); context.log.error("Error saving file to storage", text); return HttpProblems.internalServerError(request, context, { detail: text, }); } // continue return request; } ts [​](#configuration) Configuration --------------------------------- The example below shows how to configure a custom code policy in the 'policies.json' document that utilizes the above example policy code. { "name": "my-archive-request-azure-storage-inbound-policy", "policyType": "archive-request-azure-storage-inbound", "handler": { "\_name": "basic", "export": "default", "module": "$import(./modules/YOUR\_MODULE)", "options": { "blobCreateSas": "$env(BLOB\_CREATE\_SAS)", "blobContainerPath": "$env(BLOB\_CONTAINER\_PATH)" } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `archive-request-azure-storage-inbound`. * `handler.export` `` - The name of the exported type. Value should be `default`. * `handler.module` `` - The module containing the policy. Value should be `$import(./modules/YOUR_MODULE)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/archive-request-azure-storage-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `blobCreateSas` `` - The Azure shared access token with permission to write to the bucket * `blobContainerPath` `` - The path to the Azure blob container [​](#using-the-policy) Using the Policy --------------------------------------- [​](#using-the-policy-1) Using the Policy ----------------------------------------- In order to use this policy, you'll need to setup Azure storage. You'll find instructions on how to do that below. ### [​](#setup-azure) Setup Azure First, let's set up Azure. You'll need a container in Azure storage ([docs](https://docs.microsoft.com/en-us/azure/storage/common/storage-account-create?tabs=azure-portal) ). Once you have your container you'll need the URL - you can get it on the `properties` tab of your container as shown below. ![Azure](https://cdn.zuplo.com/docs/assets/Untitled-Cr4O4p8L.png) This URL will be the `blobPath` in our policy options. Next, we'll need a SAS (Shared Access Secret) to authenticate with Azure. You can generate one of these on the `Shared access tokens` tab. Note, you should minimize the permissions - and select only the `Create` permission. Choose a sensible start and expiration time for your token. Note, we don't recommend restricting IP addresses because Zuplo runs at the edge in over 200 data-centers world-wide. ![Permissions](https://cdn.zuplo.com/docs/assets/Untitled_1-DgZzuW8r.png) Then generate your SAS token - copy the token (not the URL) to the clipboard and enter it into a new environment variable in your API called `BLOB_CREATE_SAS`. You'll need another environment variable called `BLOB_CONTAINER_PATH`. ![SAS token](https://cdn.zuplo.com/docs/assets/Untitled_2-CR0W8DT6.png) Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Upstream Firebase User Auth Policy](/docs/policies/upstream-firebase-user-auth-inbound "Upstream Firebase User Auth Policy") [Next page →\ \ Archive Request to GCP Storage Policy](/docs/policies/archive-request-gcp-storage-inbound "Archive Request to GCP Storage Policy") --- # Amberflo Metering / Billing Policy - Zuplo Docs Menu [​](#amberflo-metering--billing-policy) Amberflo Metering / Billing Policy ========================================================================== Amberflo [amberflo.com](https://www.amberflo.io) is a usage metering and billing service. This policy allows you to meter API calls going through Zuplo and send them to your Amberflo account using your Amberflo API key. Add the policy to each route you want to meter. Note you can specify the Meter API Name and Meter Value (meter increment) at the policy level. [​](#configuration) Configuration --------------------------------- The configuration shows how to configure the policy in the 'policies.json' document. { "name": "my-amberflo-metering-inbound-policy", "policyType": "amberflo-metering-inbound", "handler": { "export": "AmberfloMeteringInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "apiKey": "$env(AMBERFLO\_API\_KEY)", "customerIdPropertyPath": ".sub", "meterApiName": "$env(AMBERFLO\_METER\_API\_NAME)", "meterValue": "$env(AMBERFLO\_METER\_VALUE)", "statusCodes": "200-299", "url": " https://app.amberflo.io/ingest" } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `amberflo-metering-inbound`. * `handler.export` `` - The name of the exported type. Value should be `AmberfloMeteringInboundPolicy`. * `handler.module` `` - The module containing the policy. Value should be `$import(@zuplo/runtime)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/amberflo-metering-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `apiKey` **(required)** `` - The API key to use when sending metering calls to Amberflo. * `meterApiName` `` - The name of the meter to use when sending metering calls to Amberflo (overridable in code). * `meterValue` `` - The value to use when sending metering calls to Amberflo (overridable in code). * `customerIdPropertyPath` `` - The path to the property on `request.user` contains the customer ID. For example `.data.accountNumber` would read the `request.user.data.accountNumber` property. Defaults to `".sub"`. * `customerId` `` - The default customerId for all metering calls - overridable in code and by `customerIdPropertyPath`. * `dimensions` `` - A dictionary of dimensions to be sent to Amberflo (extensible in code). * `statusCodes` `` - A list of successful status codes and ranges "200-299, 304" that should trigger a metering call to Amberflo. Defaults to `"200-299"`. * `url` `` - The URL to send metering events. This is useful for testing purposes. Defaults to `" https://app.amberflo.io/ingest"`. [​](#using-the-policy) Using the Policy --------------------------------------- You can set the customerId globally (not recommended) by setting it at the policy level or use the `customerIdPropertyPath` to read the customerId from the user object on each request. For example, if you're using API Key auth or JWT auth and want to use the `sub` property as the customerId, you would set the value as follows `"customerIdPropertyPath" : ".sub"` You can also dive into the properties of the metadata. Imagine the `request.user` property is as follows (either based on contents of a JWT token or API Key metadata) { "sub": "bobby-tables", "data": { "email": "bob@example.com", "name": "Bobby Tables", "accountNumber": 1233423, "roles": \["admin"\] } } json You could access the `accountNumber` property as follows. Note the required preceding `'.'`. `"customerIdPropertyPath" : ".data.accountNumber"` You can also set many of the properties of the meter payload programmatically, either in a custom policy or handler. Here is some example code in a custom inbound policy: import { AmberfloMeteringPolicy, ZuploContext, ZuploRequest, } from "@zuplo/runtime"; export default async function ( request: ZuploRequest, context: ZuploContext, options: MyPolicyOptionsType, policyName: string, ) { AmberfloMeteringPolicy.setRequestProperties(context, { customerId: request.user.sub, meterApiName: request.params.color, }); return request; } ts Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Monetization Policy](/docs/policies/monetization-inbound "Monetization Policy") [Next page →\ \ Readme Metrics Policy](/docs/policies/readme-metrics-inbound "Readme Metrics Policy") --- # A/B Test Outbound Policy - Zuplo Docs [​](#ab-test-outbound-policy) A/B Test Outbound Policy ====================================================== ### Custom Policy Example Zuplo is extensible, so we don't have a built-in policy for A/B Test Outbound, instead we've a template here that shows you how you can use your superpower (code) to achieve your goals. To learn more about custom policies [see the documentation](/docs/policies/custom-code-outbound) . This example shows how to perform an action on incoming requests based on the result of a randomly generated number. A/B tests could also be performed on properties such as the `request.user`. A/B tests can also be combined with other policies by passing data to downstream policies. For example, you could save a value in `ContextData` based on the results of the A/B test and use that value in a later policy to modify the request. import { ZuploContext, ZuploRequest } from "@zuplo/runtime"; export default async function ( response: Response, request: ZuploRequest, context: ZuploContext, ) { // Generate a random number to segment the test groups const score = Math.random(); // Get the outgoing response body const data = await response.json(); // Modify the body based on the random value if (score < 0.5) { data.testEnabled = true; } else { data.testEnabled = false; } // Stringify the data object const body = JSON.stringify(data); // Return a new response with the updated body return new Response(body, response); } ts [​](#configuration) Configuration --------------------------------- The example below shows how to configure a custom code policy in the 'policies.json' document that utilizes the above example policy code. { "name": "ab-test-outbound", "policyType": "custom-code-outbound", "handler": { "export": "default", "module": "$import(./modules/ab-test-outbound)" } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `ab-test-outbound`. * `handler.export` `` - The name of the exported type. Value should be `default`. * `handler.module` `` - The module containing the policy. Value should be `$import(./modules/YOUR_MODULE)`. [​](#using-the-policy) Using the Policy --------------------------------------- Read more about [how policies work](/docs/articles/policies) * * * --- # Access Control List Policy - Zuplo Docs Menu [​](#access-control-list-policy) Access Control List Policy =========================================================== ### Custom Policy Example Zuplo is extensible, so we don't have a built-in policy for Access Control List, instead we've a template here that shows you how you can use your superpower (code) to achieve your goals. To learn more about custom policies [see the documentation](/docs/policies/custom-code-inbound) . ACL policies can be built many ways depending on your requirements. This example shows how to perform an authorization check on a hard-coded list of users. This policy could be extended to fetch data from external sources or even use an authorization service such as [OpenFGA](https://openfga.dev/) . import { HttpProblems, ZuploContext, ZuploRequest } from "@zuplo/runtime"; interface PolicyOptions { users: string\[\]; } export default async function ( request: ZuploRequest, context: ZuploContext, options: PolicyOptions, policyName: string, ) { // Check that an authenticated user is set // NOTE: This policy requires an authentication policy to run before if (!request.user) { context.log.error( "User isn't authenticated. A authorization policy must come before the ACL policy.", ); return HttpProblems.unauthorized(request, context); } // Check that the user has one of the allowed roles if (!options.users.includes(request.user.sub)) { context.log.error( \`The user '${request.user.sub}' isn't authorized to perform this action.\`, ); return HttpProblems.forbidden(request, context); } // If they made it here, they are authorized return request; } ts [​](#configuration) Configuration --------------------------------- The example below shows how to configure a custom code policy in the 'policies.json' document that utilizes the above example policy code. { "name": "my-acl-policy-inbound-policy", "policyType": "acl-policy-inbound", "handler": { "\_name": "basic", "export": "default", "module": "$import(./modules/YOUR\_MODULE)", "options": { "users": \["google|12345", "google|23456"\] } } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `acl-policy-inbound`. * `handler.export` `` - The name of the exported type. Value should be `default`. * `handler.module` `` - The module containing the policy. Value should be `$import(./modules/YOUR_MODULE)`. * `handler.options` `` - The options for this policy. [See Policy Options](/docs/policies/acl-policy-inbound#policy-options) below. ### [​](#policy-options) Policy Options The options for this policy are specified below. All properties are optional unless specifically marked as required. * `users` **(required)** `` - The list of users authorized to access the resource [​](#using-the-policy) Using the Policy --------------------------------------- Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ JWT Scope Validation Policy](/docs/policies/jwt-scopes-inbound "JWT Scope Validation Policy") [Next page →\ \ RBAC Authorization Policy](/docs/policies/rbac-policy-inbound "RBAC Authorization Policy") --- # A/B Test Inbound Policy - Zuplo Docs Menu [​](#ab-test-inbound-policy) A/B Test Inbound Policy ==================================================== ### Custom Policy Example Zuplo is extensible, so we don't have a built-in policy for A/B Test Inbound, instead we've a template here that shows you how you can use your superpower (code) to achieve your goals. To learn more about custom policies [see the documentation](/docs/policies/custom-code-inbound) . This example shows how to perform an action on incoming requests based on the result of a randomly generated number. A/B tests could also be performed on properties such as the `request.user`. A/B tests can also be combined with other policies by passing data to downstream policies. For example, you could save a value in `ContextData` based on the results of the A/B test and use that value in a later policy to modify the request. import { ZuploContext, ZuploRequest } from "@zuplo/runtime"; export default async function (request: ZuploRequest, context: ZuploContext) { // Generate a random number to segment the test groups const score = Math.random(); if (score < 0.5) { // Do something for half the requests } else { // Do something else for the other half } return request; } ts [​](#configuration) Configuration --------------------------------- The example below shows how to configure a custom code policy in the 'policies.json' document that utilizes the above example policy code. { "name": "ab-test-inbound", "policyType": "custom-code-inbound", "handler": { "export": "default", "module": "$import(./modules/ab-test-inbound)" } } json ### [​](#policy-configuration) Policy Configuration * `name` `` - The name of your policy instance. This is used as a reference in your routes. * `policyType` `` - The identifier of the policy. This is used by the Zuplo UI. Value should be `ab-test-inbound`. * `handler.export` `` - The name of the exported type. Value should be `default`. * `handler.module` `` - The module containing the policy. Value should be `$import(./modules/YOUR_MODULE)`. [​](#using-the-policy) Using the Policy --------------------------------------- Read more about [how policies work](/docs/articles/policies) * * * [← Previous page\ \ Readme Metrics Policy](/docs/policies/readme-metrics-inbound "Readme Metrics Policy") [Next page →\ \ Mock API Response Policy](/docs/policies/mock-api-inbound "Mock API Response Policy") ---