How Backstage sign-in with GitHub works and what it covers
A platform team that wants engineers to sign in to Backstage with their GitHub or GitHub Enterprise accounts, and to land on the catalog entities they own, needs two separate pieces configured. The supported method is the built-in GitHub authentication provider that ships with Backstage. It handles the OAuth sign-in flow, so the person is identified as a GitHub user. It does not, by itself, tell Backstage which software the person owns or which repositories to read. That is the job of a different credential, the GitHub integration, which Backstage uses to discover catalog descriptors from repositories. Keeping these two credentials apart is the first design decision on this page: sign-in answers who is at the keyboard, while the integration answers what Backstage may read.
This page covers both github.com and GitHub Enterprise Server hosts. The provider configuration, the callback and the way the GitHub user ID is resolved to a catalog user follow the same pattern on both, but the host URLs, the OAuth application or GitHub App registration, and the network path back to Backstage differ. Before you start, confirm which host your engineers actually use, whether your organization already runs a GitHub App or OAuth application for other tools, and who in your identity or source control team can approve a new registration. Those answers decide whether you create an OAuth app or a GitHub App, and they determine who must sign off on the scopes requested.
Sign-in also depends on catalog data. A GitHub identity only resolves to a catalog user if a matching User entity exists, so the sign-in resolver and the catalog ingestion design have to agree. The Backstage authentication documentation advises that every provider resolve to the same identity and that guest access not be offered in production, so this page treats guest access as something to disable before go-live. The Backstage authentication documentation is the reference to check against the version of Backstage you are running, since provider options and resolver names can change between releases.
What you need before configuring GitHub sign-in
Sign-in to Backstage with GitHub depends on a few things being in place before any configuration file is touched. Confirm the Backstage and Node.js versions first, then make sure the GitHub side, the public URL and the catalog data are ready so the first sign-in succeeds on the first attempt.
A supported Backstage and Node.js release
Confirm the current Backstage release and the Node.js versions it supports against the release and versioning policy before you start. The policy lists Node.js 22 and 24 as of Backstage 1.46.0, but newer releases may change that list. Pin your Node.js version to one the policy supports, since sign-in code paths and build tooling both depend on it.
A GitHub organization or Enterprise host
Decide whether users sign in through github.com or a GitHub Enterprise Server host, and confirm that your team administers that organization or host. The host name you choose becomes part of the OAuth or GitHub App configuration and is hard to change later without re-registering the app and updating every user's sign-in path.
Rights to register an OAuth app or GitHub App
Confirm that the account you will use can register either an OAuth app or a GitHub App under the owning organization. Ask who approves registrations in your organization, because the choice between the two app types affects permissions, token behavior and who can rotate the client secret. Record the owner so the app does not end up tied to one person.
A stable HTTPS URL with a valid certificate
Backstage builds its OAuth callback from the backend base URL, so that address must be fixed before registration. Use a stable DNS name with a certificate that GitHub and your users' browsers trust. Changing the host later means updating the callback URL in GitHub and the base URL in configuration together, or sign-in will fail with redirect errors.
PostgreSQL for production
Plan a PostgreSQL database for any environment that other people will sign in to. The architecture overview describes PostgreSQL as the production choice and SQLite as a development option. Sessions and auth-related plugin state are stored per plugin, so an unplanned SQLite setup can lose state on restart and complicate later backup and recovery work.
Catalog users and groups in place
Make sure the people who will sign in already exist as User entities in the software catalog, with the identifiers your resolver will match on, such as the GitHub username or email. Without a matching catalog user, the default resolvers reject the sign-in. Agree in advance which GitHub teams map to which Backstage groups, so access is correct on the first login.
Choosing between an OAuth app and a GitHub App
An OAuth app is registered under a personal GitHub account or an organization, and its client ID and secret are tied to that registration. A GitHub App is a separate entity with its own identity, installed on specific organizations or repositories. For sign-in, the question is who should own the credential when the person who created it leaves the team. An organization-owned registration keeps sign-in working through staff changes, while a personal registration creates a single point of failure.
- Owner of record: OAuth apps usually belong to the user who registered them, while GitHub Apps belong to the organization that creates them.
- Continuity: Confirm that more than one administrator can manage the registration before go-live.
- Installation scope: GitHub Apps are installed per organization, which makes the boundary explicit.
- Audit trail: Record who created and last changed the registration in your change management system.
- Transfer: Ask how ownership can be transferred if the sponsoring team reorganizes.
Before committing, check which registration type the current Backstage authentication documentation describes for GitHub sign-in.
Sign-in needs only enough access to identify the user and read the membership data your resolvers use. OAuth apps request scopes that apply to the whole account the user authorizes, so broad scopes can grant more access than sign-in needs. GitHub Apps request fine-grained permissions and are installed on chosen resources, which gives a narrower permission model. Either way, the permissions requested for sign-in should be reviewed separately from those used for catalog reads.
- Requested scopes: List every scope or permission the sign-in flow requests and remove any the resolver does not use.
- Organization membership: Decide whether group or team membership is read at sign-in or taken from the catalog.
- Consent: Determine whether organization owners must approve the app before members can authorize it.
- Least privilege: Compare the sign-in permissions with your security baseline and record the justification.
- Changes over time: Plan a review when Backstage or your identity policy changes the requested permissions.
Confirm the exact scopes or permissions against the GitHub documentation for the version of Backstage you run.
Both registration types hold a client secret or key material that must be rotated, and both need an administrator who can change callback URLs when the Backstage hostname changes. GitHub Apps also rely on a private key, which is a separate artifact from the client secret and needs its own storage and rotation process. The operational difference is mostly in how credentials are issued, displayed and revoked, so align the process with your secrets management tooling and record each rotation date.
- Secret storage: Keep client secrets and private keys in your secrets manager, not in configuration files in source control.
- Rotation procedure: Write down how to rotate the credential without a sign-in outage, including the overlap period if your deployment supports it.
- Callback URL changes: Update the registered callback URL in the same change window as any Backstage hostname change.
- Revocation: Know how to revoke a compromised credential and what sign-in impact follows.
- Monitoring: Alert on failed sign-in callbacks after a rotation.
Ask your identity or platform team which rotation mechanism they already run for other OAuth clients, and reuse it where possible.
When sign-in targets a GitHub Enterprise Server or Enterprise Cloud host rather than github.com, the registration must be created on that host, and the authorization and API base URLs in the Backstage configuration must point to it. Registrations created on github.com do not authenticate users on a separate enterprise host. Enterprise administrators may also control which apps can be registered or installed, which affects the approval path and lead time.
- Host-specific registration: Create the app on the enterprise host that holds your users.
- Endpoint configuration: Set the host and API base URLs to match that enterprise instance.
- Administrator approval: Ask whether enterprise policy restricts app registration or installation.
- Network reachability: Confirm that Backstage can reach the enterprise endpoints from its deployment network.
- Certificates: Verify that the enterprise certificate chain is trusted by the Backstage runtime.
Confirm with your GitHub Enterprise administrator which host and endpoints apply to your organization before creating any registration.
The registration you choose for sign-in does not decide how the Backstage catalog reads repositories and organization data. Catalog discovery uses a separate integration credential configured in the integrations section, which may be a personal access token or an app installation, depending on the integration method you choose. Keeping the two credentials separate lets you rotate or scope each one independently and avoids giving the sign-in flow access it does not need.
- Separate credentials: Store the sign-in client credentials and the integration credential under different configuration keys and owners.
- Independent scope: Grant the integration credential only the repository read access that discovery requires.
- Independent rotation: Rotate sign-in and integration credentials on their own schedules.
- Failure isolation: A broken integration token should not block sign-in, and a broken sign-in should not stop catalog ingestion.
- Documentation: Record which credential serves which purpose in your runbook.
Review the integration guidance for GitHub discovery before setting the catalog credential, since it is a separate decision from the one on this tab.
Why sign-in and catalog discovery need separate credentials
Sign-in and catalog discovery use GitHub credentials for two different questions, so they should not share one credential. The sign-in credential, configured through the GitHub auth provider with an OAuth app or GitHub App, answers who the person is. The integration token, set under the integrations section of the app configuration, answers what Backstage may read from GitHub or GitHub Enterprise when the catalog processor fetches catalog-info.yaml files. Sign-in only needs to confirm identity and, where you use group membership, read the user's organization details. Catalog discovery needs read access to every repository the catalog should index, which is usually far broader than any one person's sign-in scope.
The risk of reusing one credential is that sign-in inherits discovery's breadth. A token that can read every repository in an organization, held in the backend for catalog ingestion, becomes the same secret that can establish a user session if it is misused or misconfigured. Rotation also gets harder: changing the discovery token to address a leak or a policy change would break sign-in for all users at once, and changing the OAuth client secret would stop catalog ingestion. Keeping the two apart lets you scope each to its job, rotate each on its own schedule, and audit each in your GitHub organization's audit log. Confirm with your GitHub or GitHub Enterprise administrators which apps and tokens already exist in your organization before you create new ones.
Once the two credentials are separate, decide the discovery side on its own terms: which hosts, organizations and repository patterns the catalog reads, and whether a GitHub App installation is the right owner for that access. The Backstage integrations documentation covers the discovery configuration, and the Backstage integrations pages in this series cover the GitHub-specific setup. Treat the sign-in configuration here as a separate review item, and record in your access documentation which credential serves which purpose.
Configuring GitHub sign-in in the order that avoids rework
This sequence registers the sign-in application on the right GitHub host, wires it into the Backstage backend, and confirms that only people with a matching catalog user can get a session. Each step ends with a check so that errors surface before users depend on sign-in.
Register the sign-in app on the correct host
The platform owner registers the sign-in application on the host your people use: github.com for a cloud organization, or your GitHub Enterprise Server instance for a self-hosted one. Confirm with the GitHub documentation which registration type fits sign-in, and keep that credential separate from the integration credential that reads repositories for catalog discovery. Done when the registration shows the Backstage hostname and you have recorded the client ID and secret.
Set the callback URL to the backend auth path
Set the authorization callback URL to the GitHub sign-in handler on the Backstage backend, using the exact path in the authentication documentation for your Backstage version. The host and scheme must match the backend base URL that users reach in the browser, because a mismatch is a frequent cause of failed redirects. Check: start sign-in from a browser with a test account and confirm GitHub returns the user to Backstage without an error page.
Store the client secret in the secrets store
The platform engineer places the client ID and client secret in your secrets store and injects them into the backend at runtime, so neither value sits in a file committed to Git or baked into the container image. Confirm that the frontend bundle and rendered configuration logs do not expose the secret. Check: search the repository and the built image for the secret value and confirm there are no matches, then confirm the backend starts with the injected values.
Add the GitHub provider for the chosen host
In the auth providers section of the app configuration, add a GitHub provider block that references the stored client ID and secret. If you use GitHub Enterprise Server, set the host and its URLs to your instance so that sign-in goes to the correct server. Keep this block separate from the integration section that holds the token used for catalog discovery. Check: restart the backend, open the sign-in page, and confirm GitHub appears as a sign-in option for the environment.
Set the GitHub user ID resolver
Choose the resolver that maps the GitHub identity to a catalog User entity. The GitHub-specific resolver matches the GitHub username to the catalog user name, so catalog entries must use the same handle. Agree with the identity owner how usernames change, are renamed or are reused, because a mismatch can attach a session to the wrong person. Check: sign in with a test account that has a matching User entity and confirm the session shows that entity's name and group memberships.
Keep guest access off and test refusal
Confirm that guest sign-in is disabled in the production configuration, then test sign-in with a GitHub account that has no matching catalog user. The expected result is a refused sign-in with an error and no session created. Record the test accounts, the outcome and the configuration version in your change record so that the result can be repeated after upgrades. Check: the refused attempt appears in the backend logs and the catalog is unchanged.
Mapping GitHub identities to Backstage catalog users
This table compares the GitHub identity attributes Backstage can match against catalog users, the catalog field each one is checked against, the resolver that uses it, and what happens when no match exists. Read each row as a decision point: confirm the resolver name and any required annotation in the authentication documentation for your Backstage version, then fix the resolution order before the first user signs in.
| GitHub identity attribute | Catalog field matched | Resolver that uses it | Failure when no match exists |
|---|---|---|---|
| Login name (username) | metadata.name of a User entity, if your resolver maps the GitHub login to it | Username-based lookup in a custom or annotation-driven resolver; confirm the built-in option for your version | Sign-in fails with NotFoundError unless a later resolver in the chain matches |
| Numeric user ID | An annotation on the User entity that stores the GitHub user ID, such as the gitlab.com/user-id style annotation pattern for GitHub, if the resolver supports it | ID-based annotation resolver; confirm the exact annotation key in the docs for your version | Renamed or recreated GitHub accounts can fail to match by name, so the user sees a not-found error |
| Primary verified email | spec.profile.email or the email entry used by the built-in email resolver | Email resolver; pair with allowedDomains to limit which addresses can sign in | If the primary email is private or unverified, no match is found and sign-in is refused |
| Organization membership | Group entities or spec.memberOf values populated by catalog ingestion | Used for authorization and group mapping rather than matching the user; confirm whether your resolver checks it | A member of an allowed org may still sign in with no catalog User, so the resolver must reject them explicitly |
| Resolver order | Ordered list in the sign-in configuration | The first resolver that returns a user wins; later resolvers only run after NotFoundError | An unplanned order can match a user to the wrong identity, so decide the order before any user signs in |
| GitHub Enterprise host | The host and OAuth app configured per environment, with the catalog entity owner reference | Same resolver logic, applied to the Enterprise host's user IDs and emails | Users from the wrong host can be matched to accounts they do not own if hosts share identifiers |
Security settings for GitHub sign-in
These six controls decide who can reach your Backstage portal and which catalog identity they become. Sign-in is the front door for every plugin, so each control below should be set in configuration, checked in a test environment, and reviewed whenever the GitHub app or the people who manage it change.
Keep guest access off
Guest sign-in lets anyone reach the portal without an identity provider check, so it must stay disabled in production. Confirm that no guest provider is configured in the production app-config.production.yaml and that the sign-in page offers only GitHub. Test with a private browser session: the only path in should be the GitHub prompt.
One identity per person
If GitHub, another provider or a proxy resolves the same person to different catalog users, permissions and ownership split across duplicate identities. Choose a single resolver outcome, such as matching on the GitHub username or verified email, and apply it consistently. Verify by signing in with the same account from each path and confirming the same user:default entity is returned.
Restrict to the intended host
A GitHub OAuth app accepts sign-in from any GitHub account unless you limit it. Use an organization or enterprise membership check, and for GitHub Enterprise confirm the configured host points at your own instance rather than github.com. Test with an account outside the organization and confirm it is refused before a catalog user is created.
Store the client secret outside Git
The OAuth client secret grants the ability to impersonate the sign-in flow, so it must not appear in a repository or container image. Reference it through an environment variable or a secret manager, and inject it at runtime. Verify by searching the repository history and built images for the secret value and confirming the config file contains only a variable reference.
Rotate on staff changes
When someone who knew the client secret leaves or changes role, the secret should be replaced so their copy stops working. Schedule a rotation as part of offboarding, update the secret in your store, and restart the backend so the new value loads. Verify by confirming the old value no longer completes a sign-in after the restart.
Review who manages the app
Anyone who can register or edit the GitHub OAuth or GitHub App can change the callback URL or redirect sign-ins to an attacker-controlled host. Limit ownership to a named group, keep the list of owners in your access records, and review it on a fixed cycle. Verify by listing the app owners and comparing them with the current approved group membership.
Common GitHub sign-in failures and how to fix them
This table maps the sign-in failures teams most often hit with GitHub and GitHub Enterprise to their likely causes and fixes. Start with the Backstage backend logs and the callback URL registered on the GitHub OAuth app, since most symptoms trace back to one of those two. Work down the rows only after confirming the callback URL and host match exactly.
| Symptom | Likely cause | Fix |
|---|---|---|
| Browser shows a callback URL mismatch error from GitHub | The authorization callback URL on the OAuth app does not match the backend auth route, including scheme, host, port or path | Check the backend logs for the redirect URI Backstage sent, then set the same value as the authorization callback URL on the GitHub OAuth app and in the app config |
| Sign-in succeeds on GitHub but Backstage shows an error and no user session starts | The sign-in resolver found no matching catalog User entity for the GitHub identity | Confirm the User entity exists and matches the resolver's key, such as the email or the github.com/user-id annotation, then review the resolver order in the GitHub provider config |
| GitHub Enterprise host is rejected during sign-in | The configured enterpriseInstanceUrl or host differs from the host where the app was registered, such as a trailing slash, http versus https, or a different hostname | Make the host value in app-config match the registered OAuth app host exactly, and confirm the enterprise instance URL is reachable from the Backstage backend |
| Sign-in fails after a client secret was rotated | The new secret was generated on GitHub but the deployment still reads the old value from its secret store or environment | Update the secret in the store the backend reads, redeploy or restart the backend so it loads the new value, and confirm the old secret is revoked |
| Sign-in reuses the token used for catalog discovery | The integrations token for source control was configured as the sign-in credential, so the two roles are mixed | Keep the OAuth client for sign-in separate from the integration token used for catalog reads, and scope each credential only to the purpose it serves |
| Users sign in but see no catalog entities or permissions | The OAuth flow returned a token with insufficient scope, or the GitHub identity does not map to the group or entity the portal expects | Check requested scopes in the provider config, confirm the user's GitHub identity matches the catalog entry, and verify the integration token can read the required repositories |
Questions teams ask before configuring GitHub sign-in
How long does setting up GitHub sign-in for Backstage take?
The duration depends on how many GitHub hosts are involved, whether you choose an OAuth app or a GitHub App, how your GitHub organization approves new apps, and how many sign-in resolvers you need to test. A single github.com host with one OAuth app and the default resolver is the shortest path. Adding GitHub Enterprise Server, a custom resolver for users who do not match by email, or a separate integration token for catalog discovery adds review and testing steps. No duration figure has been published for this work, so ask any provider for a written scope with a timeline tied to the items above, and confirm the approval steps for your GitHub organization before the schedule is fixed.
Can our team set up GitHub sign-in without outside help?
Yes, a team with Backstage experience and access to a GitHub organization owner can complete the basic setup alone. The work is configuration in the app-config.yaml file, an OAuth or GitHub App registration, and a sign-in resolver in the backend. The risk lies in resolver logic and in mixing sign-in credentials with the integration token used for catalog discovery, because a mistake can let the wrong identity sign in or leave the catalog unable to read repositories. If your team has not tested these paths before, a fixed-scope review or implementation with written acceptance tests reduces that risk. DeployOpen implements, hardens and documents self-hosted platforms in your own infrastructure, so the choice between internal and external work should rest on your staff's capacity.
What does GitHub sign-in cost, and what do we pay for?
The cost has three components. Internal engineering time covers planning, configuration, testing and the follow-up when users cannot sign in. A fixed-scope engagement is a one-time fee set by a written scope that lists deliverables, environments and acceptance criteria. Ongoing support, upgrades and testing are recurring and are offered as retainers. DeployOpen does not publish a price list, so a quote follows from the written scope. Ask for the hosts in scope, the number of identity mappings to test, the environments covered, who approves the GitHub app registrations, and which items recur after go-live. Backstage itself is open source under the Apache License 2.0, so software licensing is not a line item in this work.
What do we need from GitHub administrators and identity owners?
You need a GitHub organization owner who can register an OAuth app or GitHub App and approve its permissions, and an identity owner who can confirm how people map between GitHub accounts and your catalog users. The GitHub side requires the callback URL for each Backstage environment, the client credentials stored in a secrets manager, and an agreed list of organizations whose members may sign in. Identity owners should confirm whether users have verified email addresses in GitHub, whether your catalog users carry matching emails, and whether any users must be excluded. Plan these approvals before implementation starts, because an unreviewed app registration often delays the whole project.
Should we register a GitHub OAuth app or a GitHub App for sign-in?
Backstage's GitHub authentication provider works with an OAuth app for sign-in, and the choice affects how permissions are granted and reviewed. An OAuth app is simpler to register and is the common starting point for sign-in alone. A GitHub App gives finer control over repository permissions and installation scope, which matters when the same registration also supports catalog discovery. Keep the sign-in credential separate from the integration token used to read repositories, so that a leak or rotation of one does not break the other. Confirm the current options and permission model in the Backstage authentication documentation and in GitHub's own registration screens before you choose, because both can change between releases.
How does GitHub Enterprise change the sign-in work?
GitHub Enterprise adds a host you must configure separately, with its own base URL, OAuth registration and certificate chain. Your Backstage backend must reach that host from its network, and the TLS trust store must include any internal certificate authority. You also need to confirm how your enterprise maps users and organizations, whether it uses SAML single sign-on that restricts token access, and whether a GitHub Enterprise Cloud or Server instance is the target. Each host needs its own resolver logic and its own tests, so the effort grows with the number of hosts. Confirm these details with your GitHub Enterprise administrators and the Backstage configuration reference for your release before work begins.
Which sign-in mistakes do engineers hit most with GitHub?
The most common problems are a callback URL that does not match the registered value, a resolver that matches users by name rather than by a verified identifier, and a guest or fallback path left enabled in production. Another frequent issue is reusing the sign-in client secret as the catalog integration token, which couples two access paths that should be rotated independently. Backstage's authentication documentation advises that every provider resolves to the same catalog identity and that guest access is not offered in production. Test each resolver with a user who has no catalog entity, a user with a changed email address and a user from an unapproved organization before you go live.
How DeployOpen scopes and delivers GitHub sign-in for Backstage
DeployOpen is a Chainscore Labs company that plans, implements, hardens and supports self-hosted open-source platforms in infrastructure you control. For Backstage sign-in with GitHub and GitHub Enterprise, we scope the OAuth or GitHub App choice, the host configuration, the user resolver and the separation from catalog integration tokens in one written plan before any build starts.
How we scope
- Written scope names each GitHub host, including any GitHub Enterprise Server instance, and who may sign in.
- Scope records whether sign-in uses an OAuth app or a GitHub App, with the reason stated for your organization.
- Scope lists the resolver rules, the catalog user mapping and the owners who approve them before build.
How we build
- Configuration is built in your environment, with the sign-in provider separated from the integration token used for catalog discovery.
- Each resolver is tested with known accounts, including users without a matching catalog entity, before go-live.
- Guest access is confirmed disabled for production and resolver errors are checked against the written design.
How we hand over
- Deliverables include the configuration files, secret locations and a runbook describing each sign-in path.
- Test records show which GitHub accounts were tested, which resolvers matched them and which were rejected.
- Engagements are fixed-scope, and the handover checklist is agreed in writing at the start of the work.
How we support
- Ongoing support, upgrades and continuous testing are available as a retainer for Backstage and its sign-in configuration.
- Upgrade work covers the @backstage package set and re-checks the GitHub provider after each version change.
- Ask your DeployOpen contact to confirm the support scope, response terms and any retainer details in your quote.

