Join our Newsletter — 33% off our NHI Course
Home› Guides› Backstage Developer Portal Security Guide: Plugins, Tokens and…
Guide Application Security

Backstage Developer Portal Security Guide: Plugins, Tokens and Permissions

← All guides
By NHI Mgmt Group, edited by Lalit Choda Updated 27 October 2026 14 min read
On this page

A Backstage developer portal holds integration credentials for source control, CI, cloud and monitoring systems, runs plugins with no boundary between them, and by default lets every signed-in user do everything. That combination turns an internal convenience into one of the most connected systems in the engineering estate. This guide explains how identity works in Backstage (sign-in resolvers, Backstage tokens and plugin-to-plugin auth), how to lock down the permission framework, catalog and Scaffolder, how to handle the integration secrets plugins depend on, and what to log. It is for platform engineering teams who run Backstage and the security engineers who review it. Behaviour below was checked against the Backstage documentation in the backstage/backstage repository on 27 October 2026 and assumes the new backend system (release 1.24 or later).

Key takeaways

  • Signed in means full access until you add a policy. The Backstage threat model states that signed-in users generally have full access to all information and actions; endpoints are unprotected by authorisation and an allow-all policy ships by default.
  • Plugins are not sandboxed. Any plugin on the same host, or with access to another plugin's database, should be treated as having full access to that plugin, its configuration and its secrets. Vet plugins like any npm dependency.
  • The sign-in resolver is the identity boundary. A wrong mapping from identity provider to User entity is account takeover. Use one resolver, never guest sign-in in production, and only signature-verifying proxy providers.
  • External tokens need access restrictions. A static token in backend.auth.externalAccess with no accessRestrictions has unlimited access to all functionality of all plugins.
  • Keep it off the internet. Backstage is designed for a protected environment. Put it behind an authenticating proxy and restrict backend.reading.allow so the backend cannot be used to read cloud metadata endpoints.

How identity and access work in Backstage

The project's threat model divides people into trust groups, and it is worth adopting the same language in your own risk register.

GroupWhoTrust level in the threat modelYour control
Internal userAuthenticated members of the organisationNot expected to attack availability, but not trusted to protect confidentiality or integrityPermission policy, catalog rules, Scaffolder restrictions
OperatorPeople who configure and run the instanceFully trusted; effectively root on the host and databasePAM for hosts, Kubernetes and database; change review on config
BuilderInternal or external code contributors, including plugin authorsSimilar access to operators, because plugin code runs with full accessCode review, dependency vetting, separate deployments for sensitive plugins
External userAnyone outside the organisationAssumed to have no direct access at allNetwork isolation and an authenticating proxy

Sign-in and Backstage tokens

  • Auth providers: the auth plugin acts as an OAuth 2.0 authorisation server for provider integrations (GitHub, Microsoft, Okta, Google and others). All providers are disabled by default; enable only those you use.
  • Sign-in resolvers: each provider used for sign-in needs a resolver that maps the external identity to a User entity in the catalog, for example userIdMatchingUserEntityAnnotation, emailMatchingUserEntityProfileEmail or emailLocalPartMatchingUserEntityName. Email-based resolvers are only safe if the provider verifies that the user controls the address. The documentation is explicit: use the minimum number of resolvers, ideally one, to avoid account hijacking.
  • Proxy providers: awsAlb, cfAccess and gcpIap verify the signature of the identity the proxy passes on. oauth2Proxy does not, so an internal user who can reach the backend directly can forge an identity. Restrict those endpoints or choose a verifying provider. See the Identity-Aware Proxy Guide.
  • Guest provider: makes all users share one guest identity. Useful for local development, never for production.
  • Backstage token: an asymmetrically signed JWT carrying the user's entity reference and ownership claims. Signing keys rotate continuously and are unique per installation. Any plugin in the same backend, or sharing the auth plugin's database, can forge tokens, so high-security deployments should run auth as a separate service with its own database. See the JWT Security Guide.
  • Limited user token: the uip (user identity proof) claim lets a token be reduced to a proof of identity that most endpoints reject. Plugins that accept limited tokens widen the attack surface, so avoid accepting them except for cases such as cookie auth of static assets.

What is not protected

Built-in protection against unauthenticated access only applies with the new backend system and without backend.auth.dangerouslyDisableDefaultAuthPolicy. Even then, the frontend bundle (all frontend plugin code, minified) is served to anyone who can reach the site unless you use the experimental public entry point, which builds a separate bundle for unauthenticated visitors.

Admin roles and privileged access

Backstage has no built-in administrator role. Privilege comes from the permission policy you write, the ability to change configuration, and control over the catalog's organisational data.

PrivilegeWhere it comes fromWhy it mattersControl
Policy authorThe permission policy module (code) in the backendDecides every authorisation resultCode owners and mandatory review on the policy module
Config authorapp-config.yaml, app-config.production.yaml and secret injectionCan disable auth, add proxy routes with credentials, change reading allow listsSeparate repository or protected path, review by security
Org data sourceThe entity provider that ingests User and Group entities (for example from Entra ID or LDAP)Group membership drives ownership and therefore permissionsIngest only from a trusted provider; block user-registered User and Group entities
Template authorTemplate entities in the catalogTemplates run actions on backend hosts with the Scaffolder's credentialsRestrict who can register and change Template entities
Platform operatorHost, Kubernetes namespace and database accessFully trusted by design; can read every secretTreat as privileged access with session logging

Turning on the permission framework

  1. Set permission.enabled: true in app-config.
  2. Remove @backstage/plugin-permission-backend-module-allow-all-policy from the backend and add your own policy module (scaffolded with yarn new --select permission-policy-module), or a shared RBAC implementation.
  3. Start with a policy that denies catalog entity deletion, location creation and Scaffolder template execution for everyone except owning groups, then widen by need.
  4. Test in a staging instance with real group data: sign in as a member of each key group and check catalog, TechDocs and Scaffolder behaviour. Rollback is redeploying the previous policy module version.

Permissions only protect endpoints whose plugins call the permission framework. Check each third-party plugin for permission support before relying on the policy; a plugin without it is open to every signed-in user. TechDocs visibility follows catalog read permissions, so restricting catalog reads also restricts documentation.

Catalog rules

By default the catalog only ingests Component, API and Location kinds from user-registered locations. Keep User, Group and Template out of catalog.rules for user-registered locations. The threat model warns that letting users register User and Group entities opens impersonation and confused group membership. Entities emitted directly by an entity provider are always trusted and are not subject to rules, so that provider's source is part of your identity trust chain.

Integrations, API tokens and service accounts

Backstage's value comes from integrations, and every integration is a non-human identity held by the backend.

CredentialConfigured inTypical reachReduce it by
GitHub App (app ID, client ID, client secret, webhook secret, private key)integrations.github, often via an included YAML fileOrganisation repositories; CLI-created apps default to metadata:read and contents:readKeep read-only; give the Scaffolder user OAuth for repository creation instead of write on the app
GitLab, Azure DevOps, Bitbucket tokensintegrations.*Every repository the token's account can readDedicated bot accounts, narrow scopes, expiry
Auth provider client secretsauth.providers.* (for example ${AUTH_GITHUB_CLIENT_SECRET})Ability to complete sign-in flowsOne provider; secret in a vault
Proxy credentialsproxy.endpoints with injected headersAnyone who can reach Backstage can call the upstream with those credentialsReplace with a backend plugin; if unavoidable use allowedMethods and minimal scope
Plugin tokens (CI, cloud, monitoring, incident tools)Each plugin's config blockVaries; often admin API keysRead-only keys per plugin; inventory owner and expiry
Static external access tokensbackend.auth.externalAccess type staticUnlimited without accessRestrictionsRestrict by plugin, permission and permissionAttribute
JWKS external accessexternalAccess type jwks with url, issuer, algorithm, audienceAny workload that can get a token from that issuerPin issuer, algorithm and audience; add access restrictions
Plugin signing keysDatabase by default, or backend.auth.pluginKeyStore static ES256 keysCan mint plugin-to-plugin tokensPrefer the default; for static keys rotate by adding a new key at the top of the array
  • Keep secrets out of YAML: app-config supports $env and $file substitution; inject values from a secrets manager at deploy time, never commit them. Mark sensitive schema fields with visibility: secret, and never mark a credential frontend, since frontend-visible config is shipped to the browser. See the Secrets Management Guide.
  • Prefer JWKS over static tokens for CI and automation that can obtain workload tokens, so there is no long-lived shared secret. Static tokens should be at least 24 random bytes, one per caller with a distinct subject so logs show who called.
  • Scaffolder identity: the Scaffolder often has elevated rights, such as creating repositories. The threat model recommends running actions with the user's own credentials where possible, so a template cannot do more than its user could.
  • The reading allow list: backend.reading.allow lists the hosts the backend may read on behalf of users. It runs with service context and ignores the permission system, so a $text placeholder in catalog-info.yaml can read a repository the user cannot. Keep the list to named source control hosts and never include metadata addresses such as 169.254.169.254: server-side reads of the metadata service were the route in the Capital One breach. See the SSRF Prevention Guide.

For managing these as accountable non-human identities, see the GitHub and GitHub Actions Security Guide and the API Key Management Guide.

Logging and detection

Backstage provides an Auditor core service for security-relevant events. It writes through the root logger by default, with events named by eventId (for example entity-fetch, entity-mutate, location-mutate), a meta object with fields such as actionType, entityRef and locationRef, and a success or failure outcome with actor details. Ship the backend's JSON logs to your SIEM and add the sources below.

SourceSignalDetection idea
Auditor eventslocation-mutate create, entity-mutate deleteLocations registered pointing to unknown hosts; bulk deletions
Scaffolder task logsTemplate runs, actions, parametersNew or changed Template entities followed by runs; actions that delete resources
Auth backend logs and IdP sign-in logsSign-ins, resolver failuresSign-in resolved to a different user than the IdP subject; spikes in resolver errors
Ingress or authenticating proxyRequests and source addressesDirect requests to backend ports bypassing the proxy; calls to /api/proxy paths from unusual users
Integration providers (GitHub audit log, cloud trails)Actions by the Backstage App or bot tokensBackstage credentials used from addresses other than the Backstage egress
Dependency scanningAdvisories against yarn.lockNew critical advisory in a Backstage or plugin package

Relevant ATT&CK techniques are T1195.002 Compromise Software Supply Chain (malicious plugin or dependency), T1552.005 Cloud Instance Metadata API (abuse of the reading allow list), T1550.001 Application Access Token (reuse of integration tokens) and T1199 Trusted Relationship.

Metrics

  • Policy coverage: share of installed backend plugins that enforce permissions.
  • Unrestricted external access entries: externalAccess entries without accessRestrictions (target 0).
  • Credential inventory: integration and plugin credentials with a named owner and expiry date (target 100 percent).
  • Write-capable integrations: count of integration credentials with write scope.
  • Dependency lag: days between a Backstage release with a security fix and your deployment.

Hardening baseline

  1. Network: no public exposure. Front Backstage with an authenticating proxy (AWS ALB with OIDC, Google IAP or Cloudflare Access) and the matching verifying provider. Backstage offers only rudimentary denial of service protection, so rate limit at the proxy.
  2. Backend auth: run the new backend system on a supported release, confirm dangerouslyDisableDefaultAuthPolicy is not set, and use the public entry point if the frontend bundle itself is sensitive.
  3. Sign-in: one provider, one resolver, no guest in production, MFA at the identity provider.
  4. Authorisation: enable permissions, replace the allow-all policy, and restrict catalog mutations and Scaffolder execution.
  5. Catalog: organisational data only from a trusted entity provider; catalog rules that exclude User, Group and Template from user locations; disable or replace placeholder resolvers if $text reads are a concern.
  6. Secrets: all credentials injected from a vault, read-only scopes, inventory with owners, rotation dates.
  7. Isolation: split sensitive plugins (auth, Scaffolder, plugins with admin keys) into separate backend deployments with separate databases and credentials. Shared databases mean shared trust.
  8. Supply chain: vet every plugin and Scaffolder action before installing, pin versions, run Dependabot or Renovate on yarn.lock, and follow the project's GitHub Security Advisories. See the npm Install-Time Security Guide.

Small team or large platform

  • Small deployments: a single backend is acceptable if it is behind an authenticating proxy, uses read-only integration credentials, and has the permission framework on. Avoid installing plugins that need admin API keys.
  • Large platforms: separate auth and Scaffolder services, per-plugin databases, JWKS-based external access, and policy as code with tests in CI. Treat the Backstage platform team's deploy pipeline as privileged.

Common misconfigurations

  • Allow-all policy left in place: teams enable SSO and assume that is access control. Every signed-in user can delete catalog entities and run every template.
  • Unverified proxy identity: oauth2Proxy with the backend reachable directly, so a header supplied by an internal user is trusted as identity.
  • Several loose resolvers: an email local-part resolver plus a username resolver lets [email protected] sign in as the employee User entity jsmith.
  • Credentials in the proxy plugin: an admin API key for a monitoring tool injected as an Authorization header, usable by anyone who can reach Backstage.
  • Write-scoped GitHub App for the Scaffolder: any template, or any user who can author one, can create, change or delete repositories across the organisation.
  • Wide reading allow list: wildcard hosts in backend.reading.allow that let the backend read internal services or metadata endpoints on a user's behalf.

Framework mapping

Control areaNIST SP 800-53 Rev 5NIST CSF 2.0CIS Controls v8.1ISO/IEC 27001:2022 Annex A
Permission policy and least privilegeAC-3, AC-6PR.AA-056.8A.5.15, A.8.3
Integration and external access credentialsIA-5, IA-9PR.AA-015.2, 3.11A.5.17
Network isolation and reading allow listSC-7, CM-7PR.PS-014.4, 12.2A.8.20, A.8.22
Plugin and dependency vettingSR-3PR.PS-0116.4A.5.21, A.8.28
Audit eventsAU-2DE.CM-098.2A.8.15

Practitioner checklist

  • Confirm Backstage is unreachable from the internet and fronted by a signature-verifying authenticating proxy.
  • Check that backend.auth.dangerouslyDisableDefaultAuthPolicy is absent and the new backend system is in use.
  • Reduce sign-in to one provider and one resolver; remove guest sign-in from production config.
  • Set permission.enabled: true, remove the allow-all policy module, and test the policy per group.
  • Exclude User, Group and Template kinds from user-registered locations in catalog.rules.
  • Inventory every integration and plugin credential with owner, scope and expiry; make them read-only where possible.
  • Add accessRestrictions to every externalAccess entry, and prefer JWKS over static tokens.
  • Remove credentials injected through proxy endpoints, or restrict them with allowedMethods and minimal scope.
  • Restrict backend.reading.allow to named source control hosts.
  • Forward Auditor events and Scaffolder logs to the SIEM and track plugin and dependency advisories.

Standards and references

Related NHI Mgmt Group resources: GitHub and GitHub Actions Security Guide · CI/CD Pipeline Identity Security Guide · Secrets Management Guide · DevSecOps Guide

Free weekly newsletter

Subscribe to the NHI & AI Identity Journal

The latest on NHI and Agentic AI security – articles, research, breaches, news and events every week.

Bonus 33% off our NHI Course when you subscribe.

NHIMG Editorial Note
Researched and written by the NHI Mgmt Group editorial team using AI tools, under the editorial direction of Lalit Choda. Facts are drawn from the sources listed on this page and checked by our automated quality process. Last updated 27 October 2026. Spotted an error? Use our contact page.
NHI Mgmt Group, the independent authority on Non-Human Identity, IAM and Agentic AI security. nhimg.org