Skip to main content
Backstage.io is a popular open-source framework for building internal developer portals. In this guide, we show the minimal configuration to integrate Backstage with the Conduktor Console API. This integration requires a backend proxy configuration and a custom frontend Javascript/Typescript plugin in Backstage.

Prerequisites

  • Backstage v1.28 or later
  • Conduktor Console with delegated JWT authentication configured
  • Backstage and Conduktor Console use the same identity provider (IdP)
  • The IdP uses OIDC to issue signed JWTs with email and groups claims (e.g. Keycloak, Okta, Auth0, Jumpcloud, etc.)

How auth works

Authentication is split across three components:
  • Your IdP handles user authentication (login, MFA, credential issuance)
  • Backstage handles the interactive login UX and acquires the JWT from the IdP
  • Conduktor Console validates the token and handles authorization
When a request arrives from Backstage, Conduktor Console verifies the JWT’s signature against your IdP’s JWKS public keys, checks the issuer, and confirms the token hasn’t expired. Console does not authenticate the user directly; it trusts the IdP’s assertion. Once the token is validated, Console extracts the email and groups claims, maps them to internal permissions, and filters the API response accordingly. Requests without a valid JWT are rejected with a 401 unauthorized error code.

Configure the Backstage proxy

Add the Conduktor proxy endpoint to your Backstage app-config.yaml:
proxy:
  endpoints:
    '/conduktor':
      target: https://<your-conduktor-url>
      credentials: dangerously-allow-unauthenticated
      allowedHeaders:
        - Authorization
      changeOrigin: true
This forwards requests from /api/proxy/conduktor/* to your Conduktor Console, passing through the Authorization header containing the user’s JWT. The proxy is needed because the Backstage frontend and Conduktor run on different origins, and browser CORS policies would block direct cross-origin requests.
The dangerously-allow-unauthenticated setting tells the Backstage proxy to skip its own token validation and forward requests as-is, allowing the Authorization header to pass through to Conduktor unchanged. This is safe because Conduktor validates the JWT and enforces permissions on every request. Requests without a valid token are rejected by Conduktor with a 401.

Call the Conduktor API from a frontend plugin

In your Backstage frontend plugin, get the user’s access token from the existing sign-in session and call Conduktor through the proxy. The authApiRef below is whatever auth provider API ref your Backstage app uses for sign-in (for example, the ref you pass to the SignInPage component). If you use a different IdP, replace it with the corresponding ref (such as microsoftAuthApiRef, oktaAuthApiRef or a custom ref you created with createApiRef).
const authApi = useApi(authApiRef); // your app's auth provider API ref
const discoveryApi = useApi(discoveryApiRef);

const token = await authApi.getAccessToken();
const proxyBase = await discoveryApi.getBaseUrl('proxy');

const response = await fetch(
  `${proxyBase}/conduktor/public/console/v2/kafka-cluster`,
  { headers: { Authorization: `Bearer ${token}` } }
);

const clusters = await response.json();
// Render the response and display as you see fit
Use the browser’s native fetch(), not Backstage’s fetchApi.fetch(). The Backstage fetchApi automatically injects its own identity token into the Authorization header, which would overwrite your IdP token.
For the full API reference and response structure, see the API portal or access /docs on your Conduktor deployment.

Optional: add Conduktor API to the Backstage catalog

You can register the Conduktor API spec as a catalog entity so developers can browse the API documentation directly in Backstage. Add this to your catalog:
apiVersion: backstage.io/v1alpha1
kind: API
metadata:
  name: conduktor-console
  description: Conduktor Console API for Kafka management
  tags:
    - kafka
    - rest
spec:
  type: openapi
  lifecycle: production
  owner: platform-team
  definition:
    $text: https://<your-conduktor-url>/public/docs/docs.yaml
This is purely for documentation browsing and doesn’t affect authentication or permissions.

Permissions

No permission logic is needed in Backstage. Conduktor enforces all authorization server-side. When a request arrives with a valid JWT, Conduktor:
  1. Validates the token (signature via JWKS, issuer, expiration)
  2. Extracts the user’s email from the configured claim
  3. Maps the groups claim to internal Conduktor groups
  4. Auto-provisions the user if they don’t exist yet
  5. Applies RBAC and filters the API response
If a user can see a resource in the Conduktor UI, they can see it through Backstage. If they can’t, the API either omits it from the response or returns a 403.