diff --git a/docs/articles/securing-backend-shared-secret.md b/docs/articles/securing-backend-shared-secret.md new file mode 100644 index 00000000..943461a4 --- /dev/null +++ b/docs/articles/securing-backend-shared-secret.md @@ -0,0 +1,81 @@ +--- +title: Securing your Backend with a Shared Secret +--- + +When using a gateway, it's important to ensure that your backend API only +accepts traffic from the gateway. This ensures that policies and security are +applied to all traffic. Zuplo offers +[multiple options for securing your backend](./securing-your-backend.md) API. +This article will show you the simplest option, which is using a shared secret +via a header. + +## 1/ Set an Environment Variable + +The first step is to set an +[environment variable](https://zuplo.com/docs/articles/environment-variables) in +your Zuplo project. This variable will be a secret that only your Zuplo project +and your backend know. This secret will be sent as a header on every request to +your backend API. + +Open the _Settings_ section of your project and select _Environment Variables_. +Create a new variable and name it `BACKEND_SECRET`. Set the value to a secure, +random value. Ensure that the value is marked as a secret. + +![Set Environment Variable](../../public/media/securing-backend-shared-secret/image.png) + +## 2/ Create a Set Header Policy + +The next step is to create a policy that sets the `BACKEND_SECRET` as a header +on the request to your backend API. This policy will be an outbound policy that +runs before the request is sent to your backend. + +Navigate to the route you want to secure and add a new policy. Select the **Add +or Set Request Headers** policy type and configure it as follows: + +![Set Header Policy](../../public/media/securing-backend-shared-secret/image-1.png) + +The configuration uses the environment variable via the `$env(BACKEND_SECRET)` +selector as shown below. + +```json +{ + "name": "set-backend-secret", + "policyType": "set-headers-inbound", + "handler": { + "export": "SetHeadersInboundPolicy", + "module": "$import(@zuplo/runtime)", + "options": { + "headers": [ + { + "name": "backend-secret", + "value": "$env(BACKEND_SECRET)" + } + ] + } + } +} +``` + +Add this policy to any of the routes in your API that are calling your secure +backend. + +# 3/ Verify the Secret on your Backend + +Finally, you need to verify the secret on your backend. The way you implement +this depends on the framework and language you are using, but the typical +pattern is to use a middleware to check the header value. If the header does not +match the secret, you would typically return a 401 Unauthorized response. + +An example of this using a Node.js connect middleware is shown below. + +```js +const express = require("express"); +const app = express(); + +app.use((req, res, next) => { + if (req.headers["backend-secret"] !== process.env.BACKEND_SECRET) { + return res.status(401).send("Unauthorized"); + } + next(); +}); +``` diff --git a/docs/articles/securing-your-backend.md b/docs/articles/securing-your-backend.md index 2a7ce203..a043ec1f 100644 --- a/docs/articles/securing-your-backend.md +++ b/docs/articles/securing-your-backend.md @@ -18,9 +18,9 @@ Firebase, and Stripe to secure their own APIs. In this solution the backend requires a secret that is known only by the gateway. This is usually an opaque key sent as a header on every request to the origin. Zuplo adds this to the request - the client is never aware of the secret. An example of how to set this -up, including using [Environment Variables](./environment-variables.md) to store -the secret is included in -[Step 1 - Setup a Basic Gateway](./step-1-setup-basic-gateway.md). +up, is show in the +[Securing your Backend with a Shared Secret](./securing-backend-shared-secret.md) +article. ## 2/ Federated Authentication diff --git a/policies/custom-code-inbound/doc.md b/policies/custom-code-inbound/doc.md index 3c2f91ea..104f15e3 100644 --- a/policies/custom-code-inbound/doc.md +++ b/policies/custom-code-inbound/doc.md @@ -78,7 +78,7 @@ Here's how we could wire up our new auth route: "policies": [ { "name": "my-first-policy", - "policyType": "custom-code", + "policyType": "custom-code-inbound", "handler": { "export": "default", "module": "$import(./modules/my-first-policy)" diff --git a/public/media/securing-backend-shared-secret/image-1.png b/public/media/securing-backend-shared-secret/image-1.png new file mode 100644 index 00000000..48e0aa93 Binary files /dev/null and b/public/media/securing-backend-shared-secret/image-1.png differ diff --git a/public/media/securing-backend-shared-secret/image.png b/public/media/securing-backend-shared-secret/image.png new file mode 100644 index 00000000..3482ad8d Binary files /dev/null and b/public/media/securing-backend-shared-secret/image.png differ