diff --git a/website/docs/how-to/how-to-run-the-unleash-proxy.mdx b/website/docs/how-to/how-to-run-the-unleash-proxy.mdx new file mode 100644 index 0000000000..96c0a5adb4 --- /dev/null +++ b/website/docs/how-to/how-to-run-the-unleash-proxy.mdx @@ -0,0 +1,108 @@ +--- +title: How to run the Unleash Proxy +--- +import ApiRequest from '@site/src/components/ApiRequest' + +:::info Placeholders +Placeholders in the code samples below are delimited by angle brackets (i.e. ``). You will need to replace them with the values that are correct in _your_ situation for the code samples to run properly. +::: + + +The [Unleash Proxy](../sdks/unleash-proxy.md) provides a way for you to consume feature toggles in [front-end clients](../sdks/index.md#front-end-sdks), such as the [JavaScript Proxy client](../sdks/proxy-javascript.md) and [React Proxy client](../sdks/proxy-react.md). + +Depending on your setup, the Proxy is most easily run in one of two ways, depending on your situation: +- [Via Docker](#run-proxy-via-docker) +- [As a Node.js app](#run-proxy-as-node-app) + +If you're using a hosted version of Unleash, we can also run the proxy for you. + +## Prerequisites + +This is what you need before you can run the proxy: + +- A running Unleash server to connect to. You'll need its API path (e.g. `https://app.unleash-hosted.com/demo/api`) to connect the proxy to it. +- A [client API token](../reference/api-tokens-and-client-keys#client-tokens) for the proxy to use. +- If you're running the Proxy via Docker: [the `docker` command line tool](https://www.docker.com/). +- If you're running the Proxy as a Node.js app: [Node.js and its command line tools](https://nodejs.org/). +- A [Proxy client key](../reference/api-tokens-and-client-keys#proxy-client-keys). This can be any arbitrary string (for instance: `proxy-client-key`). Use this key when connecting a client SDK to the Proxy. + +## How to run the Proxy via Docker {#run-proxy-via-docker} + +We provide a [Docker image (available on on Docker Hub)](https://hub.docker.com/r/unleashorg/unleash-proxy) that you can use to run the proxy. + +### 1. Pull the Proxy image + +Use the `docker` command to pull the Proxy image: + +```bash title="Pull the Unleash Proxy docker image" +docker pull unleashorg/unleash-proxy +``` + +### 2. Start the Proxy + +When running the Proxy, you'll need to provide it with at least the configuration options listed below. Check the reference docs for the [full list of configuration options](../sdks/unleash-proxy.md#configuration-options). + +```bash title="Run the Unleash Proxy via Docker" +docker run \ + -e UNLEASH_PROXY_CLIENT_KEYS= \ + -e UNLEASH_URL='' \ + -e UNLEASH_API_TOKEN= \ + -p 3000:3000 \ + unleashorg/unleash-proxy +``` + +If the proxy starts up successfully, you should see the following output: + +```bash +Unleash-proxy is listening on port 3000! +``` + +## How to run the Proxy as a Node.js app {#run-proxy-as-node-app} + +To run the Proxy via Node.js, you'll have to create your own Node.js project and use the Unleash Proxy as a dependency. + +### 1. initialize the project + +If you don't already have an existing Node.js project, create one: + +``` bash npm2yarn +npm init +``` + +### 2. Install the Unleash Proxy package + +Install the Unleash Proxy as a dependency: + +``` shell npm2yarn +npm install @unleash/proxy +``` + +### 3. Configure and start the proxy + +Import the `createApp` function from `@unleash/proxy` and configure the proxy. You'll need to provide at least the configuration options highlighted below. Check the reference docs for the [full list of configuration options](../sdks/unleash-proxy.md#configuration-options). + +Here is an example of what running the Proxy as a Node.js app might look like: + +``` js title="Sample app running the Unleash Proxy" +const port = 3000; + +const { createApp } = require('@unleash/proxy'); + +const app = createApp({ + // highlight-start + unleashUrl: '', + unleashApiToken: '', + clientKeys: [''], + // highlight-end +}); + +app.listen(port, () => + console.log(`Unleash Proxy listening on http://localhost:${port}/proxy`), +); +``` + +## Verify that the proxy is working + +When the proxy process has started up correctly, you can start querying its `/proxy` endpoint. If it's running correctly, you'll get back a JSON object with a list of toggles. The list may be empty if you haven't added any toggles for the corresponding project/environment yet. + + diff --git a/website/docs/reference/api-tokens-and-client-keys.mdx b/website/docs/reference/api-tokens-and-client-keys.mdx new file mode 100644 index 0000000000..7da7559cd1 --- /dev/null +++ b/website/docs/reference/api-tokens-and-client-keys.mdx @@ -0,0 +1,113 @@ +--- +title: API tokens and client keys +--- + +For Unleash to be of any use, it requires at least a server and a [consuming client](../sdks/index.md). +More advanced use cases may call for multiple clients, automated feature toggle updates, the [Unleash proxy](../sdks/unleash-proxy.md) and [Unleash proxy clients](../sdks/index.md#front-end-sdks), and more. To facilitate communication between all these moving parts, Unleash uses a system of API tokens and client keys, all with a specific purpose in mind. + +This document details the three kinds of tokens and keys that you will need to fully connect any Unleash system: +- [Admin tokens](#admin-tokens) for updating resources in Unleash +- [Client tokens](#client-tokens) for connecting server-side client SDKs and the Unleash proxy to the Unleash server +- [Proxy client keys](#proxy-client-keys) for connecting proxy client SDKs to the Unleash proxy. + +## API tokens + +:::tip +This section describes what API tokens are. For information on how to create them, refer to the [how-to guide for creating API tokens](../user_guide/token.md). +::: + +Use API tokens to connect to the Unleash server API. API tokens come in two distinct types: +- [Admin tokens](#admin-tokens) +- [Client tokens](#client-tokens) + +Both types use [the same format](#format) but have different intended uses. API tokens are considered to be *secrets* and should _not_ be exposed to end users. + +### Admin tokens + +**Admin tokens** grant *full read and write access* to all resources in the Unleash server API. Admin tokens have access to all projects, all environments, and all global resources (find out more about [resources in the RBAC document](../user_guide/rbac.md#core-principles)). + +Use admin tokens to: +- Automate Unleash behavior such as creating feature toggles, projects, etc. +- Write custom Unleash UIs to replace the default Unleash admin UI. + +Do **not** use admin tokens for: +- [Client SDKs](../sdks/index.md): You will _not_ be able to read toggle data from multiple environments. Use [client tokens](#client-tokens) instead. + +Support for scoped admin tokens with more fine-grained permissions is currently in the planning stage. + +### Client tokens + +**Client tokens** are intended for use in [server-side client SDKs](../sdks/index.md#server-side-sdks) (including the Unleash Proxy) and grant the user permissions to: +- Read feature toggle information +- Register applications with the Unleash server +- Send usage metrics + +When creating a client token, you can choose which projects it should be able to read data from. You can give it access to a specific list of projects or to all projects (including projects that don't exist yet). Prior to Unleash 4.10, a token could be valid only for a *single project* or *all projects*. + +Each client token is only **valid for a single environment**. + +Use client tokens: +- In [server-side client SDKs](../sdks/index.md#server-side-sdks) +- To connect [the Unleash Proxy](../sdks/unleash-proxy.md) to the Unleash API + +Do **not** use client tokens in: +- [Front-end SDKs](../sdks/index.md#front-end-sdks). You will _not_ be able to connect to the Unleash server due to CORS restrictions. Configure an [Unleash Proxy](../sdks/unleash-proxy.md) and use [Proxy client keys](#proxy-client-keys) instead. + +### Format + +API tokens come in one of two formats. When we introduced [environments](../user_guide/environments.md) in Unleash 4.3, we updated the format of the tokens to provide more human-readable information to the user. Both formats are still valid (you don't need to update a working token of the old format) and are described below. + +#### Version 1 + +The first version of API tokens was a 64 character long hexadecimal string. Example: + +``` +be44368985f7fb3237c584ef86f3d6bdada42ddbd63a019d26955178 +``` + + +#### Version 2 + +API tokens consist of three parts: + +1. Project(s) +2. Environment +3. Hash + +The parts are separated by two different separators: A colon (`:`) between the project(s) and the environment, and a full stop (`.`) between the environment and the hash. + +The **project(s)** part is one of: +- The id of a specific project, for example: `default`. This indicates that the token is **only valid for this project**. +- A pair of opening and closing square brackets: `[]`. This indicates that the token is **valid for a discrete list of projects**. The list of projects is not shown in the token. +- An asterisk: `*`. This indicates that the token is **valid for all projects (current and future)**. + +The **environment** is the name of an environment on your Unleash server, such as `development`. + +The **hash** is 64 character long hexadecimal string. + +Some example client tokens are: +- A token with access to toggles in the "development" environment of a single project, "project-a": + ``` + project-a:development.be44368985f7fb3237c584ef86f3d6bdada42ddbd63a019d26955178 + ``` +- A token with access to toggles in the "production" environment multiple projects: + ``` + []:production.be44368985f7fb3237c584ef86f3d6bdada42ddbd63a019d26955178 + ``` +- A token with access to toggles in the "development" environment of all projects: + ``` + *:development.be44368985f7fb3237c584ef86f3d6bdada42ddbd63a019d26955178 + ``` + +## Proxy client keys {#proxy-client-keys} + +Use proxy client keys to connect [Proxy client SDKs (front-end SDKs)](../sdks/index.md#front-end-sdks) to the [Unleash Proxy](../sdks/unleash-proxy.md). As opposed to the [API tokens](#api-tokens), Proxy client keys are *not* considered secret and are safe to use on any clients (refer to the [the proxy documentation for more about privacy](../sdks/unleash-proxy.md#we-care-about-privacy)). They do _not_ let you connect to the Unleash server API. + +Proxy client keys are arbitrary strings that you *must* provide the Unleash proxy with on startup. Unleash does not generate proxy client keys for you. Because of this, they have no specific format. + +Use Proxy client keys to: +- Connect [Proxy client SDKs](../sdks/index.md#front-end-sdks) to the [Unleash Proxy](../sdks/unleash-proxy.md) +- Connect your own custom Proxy clients (or pure HTTP requests) to the Unleash Proxy + +Do **not** use Proxy client keys to: +- Connect to the Unleash API. It will not work. Use an appropriate [API token](#api-tokens) instead. diff --git a/website/docs/sdks/unleash-proxy.md b/website/docs/sdks/unleash-proxy.md index 20ed110584..018a0b5624 100644 --- a/website/docs/sdks/unleash-proxy.md +++ b/website/docs/sdks/unleash-proxy.md @@ -5,6 +5,10 @@ title: Unleash Proxy > The unleash-proxy is compatible with all Unleash Enterprise versions and Unleash Open-Source v4. You should reach out to **support@getunleash.io** if you want the Unleash Team to host the Unleash Proxy for you. +:::tip +Looking for how to run the Unleash proxy? Check out the [_How to run the Unleash Proxy_ guide](../how-to/how-to-run-the-unleash-proxy.mdx)! +::: + A lot of our users wanted to use feature toggles in their single-page and native applications. To solve this in a performant and privacy concerned way we built The Unleash Proxy The Unleash Proxy sits between the Unleash API and the application. It provides a simple and super-fast API, as it has all the data it needs available in memory. @@ -19,95 +23,44 @@ The proxy solves three important aspects: _The Unleash Proxy uses the Unleash SDK and exposes a simple API_. The Proxy will synchronize with the Unleash API in the background and provide a simple HTTP API for clients. -## How to Run the Unleash Proxy +## Configuration -The Unleash Proxy is Open Source and [available on github](https://github.com/Unleash/unleash-proxy). You can either run it as a docker image or as part of a [node.js express application](https://github.com/Unleash/unleash-proxy#run-with-nodejs). +:::info +You **must configure** these three variables for the proxy to start successfully: +- `unleashUrl` / `UNLEASH_URL` -### Configuration variables +- `unleashApiToken` / `UNLEASH_API_TOKEN` -Regardless of how you choose to run the it, the proxy will need access to these three variables: +- `clientKeys` / `UNLEASH_PROXY_CLIENT_KEYS` +::: -- **`unleashUrl`** / **`UNLEASH_URL`** +The Proxy has a large number of configuration options that you can use to adjust it to your specific use case. The table below lists all the available options. - The URL of your Unleash instance's API. For instance, to connect to the [Unleash demo app](https://app.unleash-hosted.com/demo/), you would use `https://app.unleash-hosted.com/demo/api/` - -- **`unleashApiToken`** / **`UNLEASH_API_TOKEN`** - - The API token to connect to your Unleash project. For more information on how these work and how to create them, check out the [API token documentation](../user_guide/token.md). - -- **`clientKeys`** / **`UNLEASH_PROXY_CLIENT_KEYS`** - - A list of client keys that the proxy will accept. For the proxy to accept an incoming request, the client must use one of these keys for authorization. In client SDKs, this is usually known as a `clientKey` or a `clientSecret`. If you query the proxy directly via HTTP, this is the `authorization` header. - - When using an environment variable to set the proxy secrets, the value should be a comma-separated list of strings, such as `secret-one,secret-two`. - -There are many more configuration options available. You'll find all [available options on github](https://github.com/Unleash/unleash-proxy#available-options). +| Option | Environment Variable | Default value | Required | Description | +|------------------------|----------------------------------|--------------------|:--------:|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `clientKeys` | `UNLEASH_PROXY_CLIENT_KEYS` | n/a | yes | List of [client keys](../reference/api-tokens-and-client-keys.mdx#proxy-client-keys) that the proxy should accept. When querying the proxy, Proxy SDKs must set the request's _client keys header_ to one of these values. The default client keys header is `Authorization`. When using an environment variable to set the proxy secrets, the value should be a comma-separated list of strings, such as `secret-one,secret-two`. | +| | | | | | +| `clientKeysHeaderName` | `CLIENT_KEY_HEADER_NAME` | `"authorization"` | no | The name of the HTTP header to use for client keys. Incoming requests must set the value of this header to one of the Proxy's `clientKeys` to be authorized successfully. | +| `customStrategies` | `UNLEASH_CUSTOM_STRATEGIES_FILE` | `[]` | no | Use this option to inject implementation of custom activation strategies. If you are using `UNLEASH_CUSTOM_STRATEGIES_FILE`: provide a valid path to a JavaScript file which exports an array of custom activation strategies. | +| `environment` | `UNLEASH_ENVIRONMENT` | `undefined` | no | If set this will be the `environment` used by the proxy in the Unleash Context. It will not be possible for proxy SDKs to override the environment if set. | +| `logLevel` | `LOG_LEVEL ` | `"warn"` | no | Used to set `logLevel`. Supported options: `"debug"`, `"info"`, `"warn"`, `"error"` and `"fatal"` | +| `logger` | n/a | `SimpleLogger` | no | Register a custom logger. | +| `metricsInterval` | `UNLEASH_METRICS_INTERVAL` | `30000` | no | How often the proxy should send usage metrics back to Unleash, defined in ms. | +| `namePrefix` | `UNLEASH_NAME_PREFIX` | `undefined` | no | If set, the Proxy will only fetch toggles whose name start with the provided prefix. | +| `projectName` | `UNLEASH_PROJECT_NAME` | `undefined` | no | If set, the Proxy will only fetch toggles belonging to the project with this ID. | +| `proxyBasePath` | `PROXY_BASE_PATH` | `""` | no | The base path to run the proxy from. "/proxy" will be added at the end. For instance, if `proxyBasePath` is `"base/path"`, the proxy will run at `/base/path/proxy`. | +| `proxyPort` | `PORT` | `3000` | no | The port to run the proxy on. | +| `proxySecrets` | `UNLEASH_PROXY_SECRETS` | n/a | no | Deprecated alias for `clientKeys`. Please use `clientKeys` instead. | +| `refreshInterval` | `UNLEASH_FETCH_INTERVAL` | `5000` | no | How often the proxy should query Unleash for updates, defined in ms. | +| `tags` | `UNLEASH_TAGS` | `undefined` | no | If set, the proxy will only fetch feature toggles with these [tags](../advanced/tags.md). The format should be `tagName:tagValue,tagName2:tagValue2` | +| `trustProxy` | `TRUST_PROXY ` | `false` | no | If enabled, the Unleash Proxy will know that it is itself sitting behind a proxy and that the `X-Forwarded-*` header fields (which otherwise may be easily spoofed) can be trusted. The proxy will automatically enrich the IP address in the Unleash Context. Can be `true/false` (trust all proxies) or a string (trust only given IP/CIDR (e.g. `'127.0.0.1'`)). If it is a string, it can also be a list of comma separated values (e.g. `'127.0.0.1,192.168.1.1/24'` | +| `unleashApiToken` | `UNLEASH_API_TOKEN` | n/a | yes | The [client API token](../reference/api-tokens-and-client-keys.mdx#client-tokens) for connecting to Unleash API. | +| `unleashAppName` | `UNLEASH_APP_NAME` | `"unleash-proxy" ` | no | The application name to use when registering with Unleash | +| `unleashInstanceId` | `UNLEASH_INSTANCE_ID` | auto-generated | no | A unique(-ish) identifier for your instance. Typically a hostname, pod id or something similar. Unleash uses this to separate metrics from the client SDKs with the same `unleashAppName`. | +| `unleashUrl` | `UNLEASH_URL` | n/a | yes | The API URL of the Unleash instance you want to connect to. | -### Running the proxy via Docker - -The easiest way to run Unleash is via Docker. We have published a [docker image on docker hub](https://hub.docker.com/r/unleashorg/unleash-proxy). - -1. **Pull the Proxy image** - ```bash - docker pull unleashorg/unleash-proxy - ``` - -2. **Start the proxy** - - ```bash - docker run \ - -e UNLEASH_PROXY_CLIENT_KEYS=some-secret \ - -e UNLEASH_URL='https://app.unleash-hosted.com/demo/api/' \ - -e UNLEASH_API_TOKEN=56907a2fa53c1d16101d509a10b78e36190b0f918d9f122d \ - -p 3000:3000 \ - unleashorg/unleash-proxy - ``` - - You should see the following output: - - ```bash - Unleash-proxy is listening on port 3000! - ``` - -### Running the proxy using Node.js - -To run the Proxy via Node.js, you'll have to create your own Node.js project and use the Unleash Proxy as a dependency. Assuming you've already set up your project, here's the steps to take to start the proxy as part of your app: - -1. **Install the Unleash Proxy package** - ``` shell npm2yarn - npm install @unleash/proxy - ``` - -2. **Initialize and start the proxy in your code.** A fully working sample app that uses the proxy: - ``` js - const port = 3000; - - const { createApp } = require('@unleash/proxy'); - - const app = createApp({ - unleashUrl: 'https://app.unleash-hosted.com/demo/api/', - unleashApiToken: '56907a2fa53c1d16101d509a10b78e36190b0f918d9f122d', - clientKeys: ['some-secret', 'another-proxy-secret', 's1'], - refreshInterval: 1000, - }); - - app.listen(port, () => - console.log(`Unleash Proxy listening on http://localhost:${port}/proxy`), - ); - ``` - -### Verify that the proxy is working - -In order to verify the proxy you can use curl and see that you get a few evaluated feature toggles back. Assuming that the proxy is running on port 3000 and that your proxy client key is `some-secret`, you could run this command : - -```bash -curl http://localhost:3000/proxy -H "Authorization: some-secret" -``` - -The output is of the form described in the [payload section](#payload). - -### Health endpoint +## Health endpoint The proxy will try to synchronize with the Unleash API at startup, until it has successfully done that the proxy will return `HTTP 503 - Not Read?` for all request. You can use the health endpoint to validate that the proxy is ready to recieve requests: diff --git a/website/sidebars.js b/website/sidebars.js index 1a0b97275c..63b6c4b2d2 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -50,6 +50,17 @@ module.exports = { label: 'Using the APIs', items: ['user_guide/api-token', 'advanced/api_access'], }, + { + type: 'category', + link: { + type: 'generated-index', + title: 'How-to: The Unleash Proxy', + description: 'Learn how to work with the Unleash Proxy', + slug: '/how-to/proxy', + }, + label: 'Unleash Proxy guides', + items: ['how-to/how-to-run-the-unleash-proxy'], + }, { label: 'Feature toggles, strategies, context', items: [ @@ -58,6 +69,7 @@ module.exports = { 'user_guide/create_feature_toggle', 'how-to/how-to-define-custom-context-fields', 'how-to/how-to-use-custom-strategies', + 'how-to/how-to-capture-impression-data', 'how-to/how-to-schedule-feature-releases', ], type: 'category', @@ -247,6 +259,7 @@ module.exports = { label: 'Unleash concepts', items: [ 'user_guide/activation_strategy', + 'reference/api-tokens-and-client-keys', 'advanced/archived_toggles', 'advanced/audit_log', 'advanced/impression-data', diff --git a/website/src/components/ApiRequest/ApiRequest.stories.jsx b/website/src/components/ApiRequest/ApiRequest.stories.jsx index 257fc77afc..4c177e42d7 100644 --- a/website/src/components/ApiRequest/ApiRequest.stories.jsx +++ b/website/src/components/ApiRequest/ApiRequest.stories.jsx @@ -53,3 +53,11 @@ DELETE.args = { url: 'api/admin/projects//features/', title: 'Create a feature toggle with impression data enabled.', }; + +export const GETProxy = Template.bind({}); +GETProxy.args = { + verb: 'get', + url: 'proxy', + title: 'Request toggles from the Unleash Proxy', + endpointType: 'Proxy API', +}; diff --git a/website/src/components/ApiRequest/index.tsx b/website/src/components/ApiRequest/index.tsx index de29343edb..4727dd91fc 100644 --- a/website/src/components/ApiRequest/index.tsx +++ b/website/src/components/ApiRequest/index.tsx @@ -18,47 +18,67 @@ import CodeBlock from '@theme/CodeBlock'; const indentation = 2; type Props = { - verb: string, - payload?: any, - url: string, - title?: string -} + verb: string; + payload?: any; + url: string; + title?: string; + endpointType?: 'Proxy API' | 'Unleash server API'; +}; -const Component: React.FC = ({ verb, payload, url, title }) => { +const Component: React.FC = ({ + verb, + payload, + url, + title, + endpointType = 'Unleash server API', +}) => { const verbUpper = verb?.toUpperCase() || ''; const prettyPayload = JSON.stringify(payload, null, indentation); + const [baseUrl, authToken] = + endpointType === 'Unleash server API' + ? ['unleash-url', 'API-token'] + : ['proxy-url', 'proxy-client-key']; - const httpBlock = (payload ? ` -${verbUpper} /${url} -Authorization: + const httpBlock = ( + payload + ? ` +${verbUpper} <${baseUrl}>/${url} +Authorization: <${authToken}> content-type: application/json -${prettyPayload}` :` -${verbUpper} /${url} -Authorization: -content-type: application/json`).trim() +${prettyPayload}` + : ` +${verbUpper} <${baseUrl}>/${url} +Authorization: <${authToken}> +content-type: application/json` + ).trim(); - const curlBlock = (payload ? ` + const curlBlock = ( + payload + ? ` curl -H "Content-Type: application/json" \\ - -H "Authorization: " \\ + -H "Authorization: <${authToken}>" \\ -X ${verbUpper} \\ -d '${prettyPayload}' \\ - /${url}` : ` + <${baseUrl}>/${url}` + : ` curl -H "Content-Type: application/json" \\ - -H "Authorization: " \\ + -H "Authorization: <${authToken}>" \\ -X ${verbUpper} \\ - /${url}` ).trim() + <${baseUrl}>/${url}` + ).trim(); - const httpieBlock = (payload ? - `echo '${prettyPayload}' \\ + const httpieBlock = ( + payload + ? `echo '${prettyPayload}' \\ | http ${verbUpper} \\ - /${url} \\ - Authorization:` - : ` + <${baseUrl}>/${url} \\ + Authorization:<${authToken}>` + : ` http ${verbUpper} \\ - /${url} \\ - Authorization:`.trim() - ).trim() + <${baseUrl}>/${url} \\ + Authorization:<${authToken}>`.trim() + ).trim(); return ( @@ -69,7 +89,7 @@ http ${verbUpper} \\ - {curlBlock} + {curlBlock}