docs/plugins/proxying.md
:::caution Legacy Documentation
This section is part of the legacy plugins documentation. The proxy configuration and usage described here applies to both the old and new backend systems. For creating backend plugins and modules, see Building Backend Plugins and Modules.
:::
This page describes how to configure and use the built-in HTTP proxy functionality in your Backstage backend.
The Backstage backend comes packaged with a basic HTTP proxy, that can aid in reaching backend service APIs from frontend plugin code. See Call Existing API for a description of when the proxy can be the best choice for communicating with an API.
The plugin is already added to a default Backstage project.
To add it to a project, add the following line in packages/backend/src/index.ts:
backend.add(import('@backstage/plugin-proxy-backend'));
In packages/backend/src/index.ts:
backend.add(import('@backstage/plugin-proxy-backend'));
Configuration for the proxy plugin lives under a proxy root key of your
app-config.yaml file.
Example:
# in app-config.yaml
proxy:
reviveConsumedRequestBodies: true
endpoints:
/simple-example: http://simple.example.com:8080
'/larger-example/v1':
target: http://larger.example.com:8080/svc.v1
credentials: require
headers:
Authorization: ${EXAMPLE_AUTH_HEADER}
# ...or interpolating a value into part of a string,
# Authorization: Bearer ${EXAMPLE_AUTH_TOKEN}
Each key under the proxy configuration entry is a route to match, below the
prefix that the proxy plugin is mounted on. If it does not start with a slash,
one will be prefixed automatically. For example, if the backend mounts the proxy
plugin as /proxy, the above configuration will lead to the proxy acting on
backend requests to /api/proxy/simple-example/... and
/api/proxy/larger-example/v1/....
The value inside each route is either a simple URL string, or an object on the
format accepted by
http-proxy-middleware.
Additionally, it has an optional credentials key which can have the following
values:
require: Callers must provide Backstage user or service credentials with
each request. The credentials are not forwarded to the proxy target. This is
the default.forward: Callers must provide Backstage user or service credentials with
each request, and those credentials are forwarded to the proxy target.dangerously-allow-unauthenticated: No Backstage credentials are required to
access this proxy target. The target can still apply its own credentials
checks, but the proxy will not help block non-Backstage-blessed callers. If
you also add allowedHeaders: ['Authorization'] to an endpoint configuration,
then the Backstage token (if provided) WILL be forwarded.Note that if you have backend.auth.dangerouslyDisableDefaultAuthPolicy set to
true, the credentials value does not apply; the proxy will behave as if all
endpoints were set to dangerously-allow-unauthenticated.
If the value is a string, it is assumed to correspond to:
target: <the string>
changeOrigin: true
pathRewrite:
'^<url prefix><the string>/': '/'
credentials: require
When the target is an object, it is given verbatim to http-proxy-middleware
except with the following caveats for convenience:
changeOrigin is not specified, it is set to true. This is the most
commonly useful value.pathRewrite is not specified, it is set to a single rewrite that removes
the entire prefix and route. In the above example, a rewrite of
'^/api/proxy/larger-example/v1/': '/' is added. That means that a request to
/api/proxy/larger-example/v1/some/path will be translated to a request to
http://larger.example.com:8080/svc.v1/some/path.credentials is not specified, it is set to require.There are also additional settings:
allowedMethods: Limit the forwarded HTTP methods. For example
allowedMethods: ['GET'] enforces read-only access.allowedHeaders: A list of headers that should be forwarded to and received
from the target.By default, the proxy will only forward safe HTTP request headers to the target.
These are based on the headers that are considered safe for CORS and include
headers like content-type or last-modified, as well as all headers that are
set by the proxy. If the proxy should forward other headers, like
authorization, this must be enabled by the allowedHeaders config, for
example allowedHeaders: ['Authorization']. This should help to not
accidentally forward confidential headers (cookie, X-Auth-Request-User) to
third parties.
The same logic applies to headers that are sent from the target back to the frontend.
To fix the issue with missing request body passed by proxy to the target, set proxy.reviveConsumedRequestBodies: true, so the fixRequestBody handler of http-proxy-middleware will be used.
In that case, mind setting the Content-Type header to either application/json or application/x-www-form-urlencoded.
The proxy plugin additionally supports a proxyEndpointsExtensionPoint which a
proxy plugin module can utilize in order to programmatically register
additional endpoints, whose payloads are specified exactly as in app-config
(described above). Note that endpoints configured in app-config will always
override those registered in this manner.
To scaffold a module package, run yarn new, select backend-module, and
fill out the prompts with proxy as the plugin ID. This will create
plugins/proxy-backend-module-<moduleId> with src/module.ts and
src/index.ts files. The scaffolded package only depends on
@backstage/backend-plugin-api, so add the @backstage/plugin-proxy-node
package that provides the extension point:
yarn --cwd plugins/proxy-backend-module-demo-additional-endpoints add @backstage/plugin-proxy-node
Then replace the generated src/module.ts with the example below:
import { createBackendModule } from '@backstage/backend-plugin-api';
import { proxyEndpointsExtensionPoint } from '@backstage/plugin-proxy-node/alpha';
export const proxyModuleDemoAdditionalEndpoints = createBackendModule({
pluginId: 'proxy',
moduleId: 'demo-additional-endpoints',
register(reg) {
reg.registerInit({
deps: {
proxyEndpoints: proxyEndpointsExtensionPoint,
},
async init({ proxyEndpoints }) {
// Replace with however your setup obtains the credential.
const largerExampleAuth = 'Bearer <token>';
proxyEndpoints.addProxyEndpoints({
'/simple-example': 'http://simple.example.com:8080',
'/larger-example/v1': {
target: 'http://larger.example.com:8080/svc.v1',
credentials: 'require',
headers: {
Authorization: largerExampleAuth,
},
},
});
},
});
},
});
export { proxyModuleDemoAdditionalEndpoints as default } from './module';
Then install the module alongside the proxy plugin in your backend entry
point (usually packages/backend/src/index.ts):
backend.add(import('@backstage/plugin-proxy-backend'));
backend.add(
import('@internal/plugin-proxy-backend-module-demo-additional-endpoints'),
);