Securing Backstage service-to-service auth and external access tokens
This section covers how to let scripts, CI jobs and external systems call a Backstage instance without loosening sign-in for people. The core task is to decide, for each caller, which credential it should hold and what that credential is allowed to reach. Backstage separates two kinds of traffic: calls between its own backend plugins, and calls from outside the portal, such as a pipeline registering a component or a reporting tool reading catalog data. Each needs a different mechanism, and mixing them up is the most common way teams end up with a portal that is open more widely than intended.
Backstage handles plugin-to-plugin calls with service tokens that the backend issues and checks on its own behalf, so plugin authors do not manage those credentials by hand. External callers are a separate case. The authentication documentation describes static tokens for simple machine access and JSON Web Key Set (JWKS) verification for tokens issued by an identity system you already run. Static tokens are easy to set up but are long-lived secrets that someone must store, rotate and revoke. JWKS-based validation fits better when your identity provider already issues short-lived tokens for workloads. Confirm the current configuration keys, the token formats each option accepts, and the default token lifetimes in the Backstage authentication documentation before you write any of them into a config file, because the supplied material does not establish them.
The default auth policy exists because a portal with no authentication requirement exposes catalog data and scaffolder actions to anyone who can reach it. Disabling that policy to make a script work is a last resort, and it should be a decision recorded with an owner and a removal plan. Before changing anything, check whether a scoped external token or a JWKS trust relationship solves the caller's need. Then confirm that each external credential is tied to a single purpose, can be revoked without affecting people, and reaches only the plugins and permissions it needs. Test the result with a caller that has no token and one with a token that lacks the required permission, and keep those checks in your operations runbook.
Which credential fits which caller
Calls between Backstage backend plugins are the traffic that happens inside your portal, such as the catalog backend answering a request from the scaffolder or search collecting entities. Backstage issues these tokens itself through its backend auth service, so no person creates or stores them. Your team configures the backend and the trust between plugins, and the framework handles issuance for each request.
- Issuer: The Backstage backend auth service signs these tokens, using keys the backend manages.
- Rotation: Key handling sits with the backend configuration and deployment process, so confirm how keys rotate in your version before relying on it.
- Who uses it: Only Backstage plugins. Human users and scripts should not hold these tokens.
- Main risk: A plugin that accepts requests without checking the calling plugin or the permission on the request can expose data to any caller that reaches it.
- Upgrade check: Confirm the auth behavior on each upgrade, because plugin authors may change how requests are validated.
Before go-live, confirm which plugins expose endpoints beyond the portal network and which of those endpoints validate the caller.
Static tokens are long-lived secrets that a script or automation job presents to a Backstage endpoint, typically to register entities, read catalog data or trigger a job. They are simple to set up and they are the easiest credential to leak, because anyone who copies the value from a pipeline log or a shared file can use it. Your team, not the framework, decides who creates, stores and retires them.
- Issuer: An administrator defines the token in backend configuration, and the value is the secret you generate.
- Rotation: Rotation is a manual process unless your own tooling automates it, so assign a named owner and a schedule.
- Scope: Give each script its own token and tie it to the least permission it needs, rather than sharing one administrator token.
- Main risk: A leaked token gives the same access as the job that used it, and it stays valid until someone removes it from configuration.
- Storage: Keep values in your secrets manager and inject them at runtime, never in repository files.
Before use, ask who can read the secret store, how a compromised token is revoked, and whether every token has a documented owner.
External systems that need to call Backstage without a shared secret can instead verify a signed JWT. The external system, or the identity provider that issues tokens for it, signs the token, and Backstage checks the signature against public keys published at a JWKS endpoint. This moves trust to a key pair that the issuer controls, so Backstage never holds the signing key.
- Issuer: The external identity provider or system signs the token, and it publishes the public keys at its JWKS endpoint.
- Rotation: The issuer rotates its signing keys, and Backstage must fetch the updated key set. Confirm the refresh behavior and how old keys are retired.
- Configuration: Check the issuer, audience and key-set URL in the backend configuration against the values your identity provider publishes.
- Main risk: A misconfigured issuer or audience can accept tokens meant for another system, so validate both claims explicitly.
- Ownership: Agree in writing which team owns the external identity provider and who approves new trusted issuers.
Before go-live, test that a token from another issuer, or with a wrong audience, is rejected.
Auth options for external and internal callers
This table compares the three ways a caller can reach Backstage backend APIs: static tokens for scripts, JWKS-validated tokens from an external issuer, and tokens Backstage issues between its own plugins. Read each column against who holds the secret or key and how the caller appears in logs. The main takeaway is that plugin-to-plugin tokens need no operator-managed credential, so static tokens should be a narrow exception for external systems.
| Option | Static tokens | JWKS-validated tokens | Plugin-to-plugin tokens |
|---|---|---|---|
| Best use | Scripts or a small number of trusted internal jobs calling a Backstage API | External systems that already issue signed tokens from an identity provider | Backend plugins calling other backend plugins inside the Backstage deployment |
| Who manages the secret or key | Your team generates the token string and stores it in configuration and in each caller | The external issuer owns the signing keys; Backstage only holds the public key set it fetches | Backstage manages the signing keys internally; operators do not hand out credentials |
| Rotation effort | Manual: generate a new value, update the configuration and every caller, then redeploy | Low to moderate: the issuer rotates keys and Backstage must fetch the updated key set | Handled by Backstage; confirm key rotation behavior for your version in the release notes |
| Audit visibility | Callers share one secret, so you see the configured subject, not the individual person or job | Token claims identify the caller, so logs can tie requests to the issuer's subject | Requests are attributed to the calling plugin, which is useful for tracing but not for people |
| When to avoid | Shared credentials for many systems, or any caller that needs individual accountability | When the issuer cannot be kept under your control or cannot publish a stable key set | Not a substitute for external access; these tokens are not issued to outside callers |
Restricting access by plugin and permission
Authentication tells Backstage who is calling, but permissions decide what that caller may do. The cards below cover how to scope each external identity to the plugins and actions it needs, and how to keep people and machines apart when you configure access.
Give each integration its own identity
Create one service identity per external system, such as a CI job, a reporting script or a cost tool, rather than sharing a single token across them. A separate identity lets you see which integration made a call, revoke one without breaking the others, and rotate its credential on its own schedule. Check that every static token or JWKS-backed subject in your configuration maps to exactly one integration owner who can answer for it.
Keep people and services apart
Do not let a service identity inherit a person's catalog group or sign-in session. Machine callers should be granted permissions explicitly, while human users keep the access their group memberships give them. Review whether any external caller can act as a named user, because that blurs audit trails and makes offboarding harder.
Grant permissions by plugin and action
Backstage permissions are evaluated per plugin and per action, such as reading catalog entities or triggering a scaffolder task. Write each external grant against the narrowest action the integration needs, and avoid broad allow-all rules that cover every plugin. Confirm the exact permission names your installed plugin versions expose before you write the policy, because they vary between releases.
Scope the permission policy in code
Keep the permission policy in version-controlled code that is reviewed like any other change. Write explicit allow rules for each service identity and deny by default for everything else, then test the policy with representative requests from each caller. A policy that lives only in a configuration editor is hard to review and easy to widen by accident.
Treat the default auth policy as a last resort
Disabling the default auth policy removes the protection that requires a valid identity on backend routes, so any reachable caller can read or write data. Treat it as a temporary measure for a narrow, documented case, and record who approved it and when it should be removed. Before you disable it, confirm the affected routes are not reachable from outside your network.
Review and remove unused grants
Service identities accumulate permissions as integrations change, and a grant that once served a pipeline may outlive it. Schedule a recurring review that compares each identity's granted permissions with the calls it actually makes in your logs, then remove what is unused. Ask your team to name an owner for every grant so the review has someone to confirm each one with.
Why disabling the default auth policy is a last resort
Disabling the default auth policy in Backstage should be the last step you take, not the first. The default policy is what stops an unauthenticated or unauthorized caller from reaching plugin backend endpoints, so turning it off removes a control that every plugin route relies on. Once it is gone, any caller that can reach the backend port can invoke catalog, scaffolder and other plugin APIs, and the permission checks you configured for users and tokens no longer decide what those calls can do. Treat the change as a security decision that needs an owner, a written reason and a rollback plan, not as a configuration tweak.
Teams are usually tempted by a failing integration. A script that calls the catalog API returns 401, a scaffolder run from a pipeline is rejected, or a proxy in front of Backstage breaks the callback path, and the fastest visible fix is to relax auth for that route or switch the policy off. Try the narrower fixes first. Confirm which caller is failing and which token it sends, issue a static token or a JWKS-backed token for that external system with only the permissions it needs, check that the token audience and issuer match what the backend expects, and confirm the proxy forwards the headers the auth provider reads. The current behavior of the default policy and the supported override points are not described in the facts available to us, so check the authentication and permissions documentation for your release, and the Backstage authentication documentation, before changing anything.
How to set up external token access safely
This sequence takes a Backstage instance from an unknown set of callers to a tested configuration where each external caller holds only the credential and plugin permissions it needs, with rotation and logging in place before go-live.
Inventory callers and the plugin actions they need
List every script, pipeline, service and external system that will call Backstage, and for each one record the plugin routes it reads or writes and the permissions those calls require. Owners of the calling systems should sign off, because the list becomes the scope for every later step. Done means each caller has a row in a written inventory with a named owner and a short list of required actions. Any caller that cannot name its actions is not ready for a credential yet.
Choose a credential type for each caller
For each caller, decide between a static token for simple, tightly controlled scripts, JWKS-based verification for systems that can sign their own tokens, and plugin-to-plugin tokens that stay inside the Backstage backend. Keep interactive users on their identity provider sign-in rather than shared credentials. Confirm the exact token types and configuration keys in the Backstage authentication documentation for your release, since names change between versions. Done means every caller maps to exactly one credential type with a recorded reason.
Configure the backend and permission policy
Platform engineers add the chosen token mechanisms to the backend configuration, then restrict each caller to the permissions from step one through the permission framework. Keep the default auth policy in place and avoid disabling it, because doing so removes the protection that applies to every route. Store static secrets in your secret manager and reference them from configuration rather than committing them. Done means the configuration is reviewed, deployed to a non-production environment, and the permission rules match the inventory.
Verify with one denied and one allowed request
For each caller, send one request to an action it is permitted to use and one to an action outside its inventory row. The allowed call should succeed and the denied call should return an authorization error. Run these checks from the same network path the real caller uses so that proxies and ingress rules are tested too. Done means every caller has a recorded pass for both outcomes, and any unexpected success is treated as a blocking defect.
Define rotation and revocation for each credential
Set a rotation owner and a rotation procedure for every static token and signing key, and document how to revoke a credential quickly if a caller is compromised. For JWKS-based access, confirm how keys are published and how old keys are retired. Test the revocation path once in staging by rotating a token and confirming the old value stops working. Done means a runbook exists, the owner has acknowledged it, and the revocation test is recorded.
Enable logging and confirm events are reviewable
Turn on audit logging for authentication and authorization decisions so that each external call can be traced to a caller and an action. Send those logs to the central store your security team uses and confirm that a denied request from step four appears there with enough detail to identify the caller. Check the Backstage operations documentation for which events are logged by default. Done means a sample denied event is visible in the central store and the log retention period has been confirmed with the owning team.
Approve go-live and schedule the first review
Bring the inventory, permission rules, verification results, rotation runbook and logging evidence to the system owner for sign-off before production use. After go-live, set a recurring review that compares the live caller list with the inventory and removes callers that no longer exist. Record who approved the change and the date. Done means production credentials are issued only after sign-off, and the review is on the team calendar with an owner named.
Security and operational considerations
Once plugin-to-plugin tokens, static tokens and JWKS endpoints are in place, the risk shifts to how they are stored, rotated, logged and kept current. The cards below cover the ongoing decisions that keep external access secure for the life of the portal.
Secret storage for static tokens
Static tokens for scripts and external systems are bearer credentials, so anyone who reads the configuration can call Backstage as that caller. Keep them out of app-config.yaml and out of Git, inject them from your secrets manager at deploy time, and confirm which permissions each token carries. Ask the team who can read the running pod's environment, because that group effectively holds the token.
Rotation ownership
Every static token and signing key needs a named owner who knows which pipeline, script or partner system depends on it. Agree in writing who rotates each credential, how often, and how the consumer is notified before the old value stops working. Tokens with no owner tend to outlive the project that created them and remain valid long after anyone remembers them.
Audit logging of external calls
Calls from scripts and external systems should be traceable to a specific token or identity, not just to an IP address. Confirm that your deployment logs authentication failures and the calling subject for requests that reach sensitive plugins, and forward those logs to your central store. Test the log path with a deliberate bad request before you rely on it for an investigation.
Key rollover for JWKS
When Backstage validates tokens against an external JWKS endpoint, the signing keys will change. Plan an overlap window in which the old and new keys are both published, so tokens issued before the change still verify while consumers pick up the new key. Test the rollover in a non-production environment and confirm how your identity provider publishes its keys.
Keeping the version current
Backstage backports high and critical severity fixes to releases from the last 6 months where feasible, so a portal that falls behind may miss security fixes entirely. Assign an owner for routine upgrades, track the release line you run, and budget time for each bump. The latest release on the GitHub releases page is the reference point for checking how far behind you are.
Questions teams ask before setting up external access
How much effort does securing external access to Backstage take?
The effort depends mostly on how many callers need access and how many plugins they touch. A single script that reads the catalog is a small job, while a set of external systems that write to the catalog and call several plugins takes longer to design, test and monitor. Each caller needs its own identity, a defined set of permissions, and a way to rotate its credential. Teams should list every caller, the plugin endpoints it needs and the actions it performs before estimating. Ask any partner to break the work into the token mechanism, the permission model, the testing and the operating runbook, so each part can be priced and checked separately.
Can an internal platform team set up Backstage service-to-service auth alone?
A team with solid Backstage experience and a working understanding of its authentication model can do much of this internally. The harder parts are usually the design decisions: which callers get which permissions, how keys are issued and rotated, and whether a JWKS endpoint or a static token fits each caller. Teams without prior Backstage backend work often need help with the plugin permission framework and with testing that external calls are denied when they should be. An outside partner can review the design, build the configuration and test the boundaries, while your team keeps ownership of the running system.
What do we need to provide, and who must sign off?
The work needs input from several people. Identity owners confirm which identity provider and groups control access and who may create service identities. Platform administrators provide the Backstage deployment details, the secret storage location and the change process. Application owners of each external system confirm what that system must read or write. Security or risk owners should approve each service identity, its scope and its expiry or rotation plan before it is live. Ask for a written list of these approvers in the scope, so access is not granted on informal agreement.
How long does it take to verify that external access works correctly?
Verification takes as long as it takes to prove two things: that each intended caller succeeds, and that every other request is refused. Test cases should cover valid tokens, expired or rotated tokens, tokens from other callers, requests to plugins outside the caller's scope, and requests without any token. The duration depends on the number of callers and endpoints, and on whether tests run in a staging environment that mirrors production. Ask the partner to show how these tests are automated and repeated after each Backstage upgrade, since upgrades can change plugin behavior.
What drives the cost of this work up?
Costs rise with the number of external callers, the number of plugins and permissions involved, and the amount of custom permission logic required. Integration with an existing secrets manager, a JWKS endpoint hosted by another team, or a multi-environment setup adds work. Compliance evidence, such as documenting who approved each identity and how keys are rotated, also adds effort. Costs are one-time for design and build, and recurring for rotation, monitoring, upgrades and periodic access reviews. When requesting a quote, ask for these items as separate lines and ask which recurring tasks the price covers.
When should we bring in outside help for Backstage external access?
Outside help is most useful when the design is unclear, when external systems need access to sensitive catalog data, or when the team lacks time to test negative cases. It also helps when an internal team has disabled the default auth policy to make a integration work, because that change needs review before it stays in production. DeployOpen plans, implements and hardens self-hosted open-source platforms in your own infrastructure, and runs security testing that can check whether external access is refused where it should be. The work is usually fixed-scope and agreed in writing before it starts.
Why is disabling the default auth policy a risk for external callers?
Disabling the default policy removes the check that every request to a plugin must be authenticated and authorized, so any caller that reaches the endpoint may read or change data it should not see. Teams sometimes do this to get a script working quickly, and the exception stays after the script is finished. The safer approach is to issue a scoped credential to the caller and grant only the permissions it needs. If a temporary exception is unavoidable, record it, limit it to a specific route, and set a removal date that an owner must confirm.
Which parts of this work recur after go-live?
Several parts recur. Static tokens and signing keys need rotation on a schedule that your policy sets, and each rotation must update every caller that depends on it. Access reviews should confirm that each service identity still needs its permissions. Backstage upgrades can change plugin permission names or token handling, so tests must run again. Monitoring of denied and unusual requests should feed your security operations process. Ask whether the support arrangement covers these tasks and who receives alerts when a caller fails.
How DeployOpen works on this
DeployOpen plans, implements, hardens, documents and supports self-hosted open-source platforms inside your own infrastructure. For Backstage service-to-service auth and external access tokens, we start with a written scope that defines which plugins, callers and permissions are in play, then build and test the token model in your environment.
How we scope
- Inventory every caller that reaches Backstage, including scripts, CI jobs and external systems, and the access each one needs.
- Agree in writing which plugin-to-plugin trust, static token and JWKS patterns apply to your deployment.
- Confirm which permission policies, plugin restrictions and environments the fixed-scope engagement covers before work starts.
How we build
- Configure backend-to-backend token handling and external access without disabling the default auth policy.
- Test each caller against its granted permissions, including denied requests, in a non-production instance first.
- Store signing keys, static tokens and JWKS endpoints under your secrets process and record where each one lives.
How we hand over
- Document the token model, caller inventory, permission map and rotation steps in a form your team can maintain.
- Walk your platform and security engineers through the configuration, tests and known exceptions before handover.
- Record each decision where auditors and reviewers can trace it back to a written requirement.
How we support
- Ongoing support, upgrades and continuous testing are available as a retainer, so token and permission changes get reviewed.
- Re-test external access after Backstage version bumps, since upgrades can change auth behavior your callers depend on.
- Confirm the retainer scope, response expectations and upgrade cadence in writing with your quote.

