fix(coderd): explain default GitHub app org visibility on login rejection (#27374)

## Problem

On a fresh deployment with no custom GitHub OAuth app, Coder falls back
to the default Coder-managed GitHub app. That app can only see
organization memberships in organizations where it has been installed.
If `CODER_OAUTH2_GITHUB_ALLOWED_ORGS` is set but the app isn't installed
in the allowed organizations, the membership list comes back empty and
every login, including the first admin login, is rejected with a bare
"You aren't a member of the authorized Github organizations!" with no
hint about the actual cause. This leaves fresh deployments in an
apparently broken state.

## Fix

* Append a remediation hint to the login rejection when the default
provider is configured, pointing at the [app installation
page](<https://github.com/apps/coder/installations/select_target>) and
at configuring a custom GitHub OAuth app.
* Log a startup warning when the default provider is combined with
`CODER_OAUTH2_GITHUB_ALLOWED_ORGS`, listing the allowed orgs and the
install URL.
* Document the installation requirement next to the
`CODER_OAUTH2_GITHUB_ALLOWED_ORGS` step in the GitHub auth docs.

Access-control behavior is unchanged; the org check still rejects logins
as before, it just explains why and how to fix it.

## Testing

* New `TestUserOAuth2Github/NotInAllowedOrganizationDefaultProvider`
asserts the hint appears when `DefaultProviderConfigured` is set; the
existing `NotInAllowedOrganization` subtest asserts it does not leak
into the custom-app path.

Fixes coder/coder#17752
This commit is contained in:
Atif Ali
2026-07-21 20:43:10 +05:00
committed by GitHub
parent a9a1dcc65d
commit 48e9bb3391
4 changed files with 101 additions and 2 deletions
+12 -2
View File
@@ -1006,7 +1006,7 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
}
options.WebPushDispatcher = webpusher
githubOAuth2ConfigParams, err := getGithubOAuth2ConfigParams(ctx, options.Database, vals)
githubOAuth2ConfigParams, err := getGithubOAuth2ConfigParams(ctx, options.Logger, options.Database, vals)
if err != nil {
return xerrors.Errorf("get github oauth2 config params: %w", err)
}
@@ -2213,7 +2213,7 @@ func maybeAppendDefaultGithubExternalAuthProvider(
}), nil
}
func getGithubOAuth2ConfigParams(ctx context.Context, db database.Store, vals *codersdk.DeploymentValues) (*githubOAuth2ConfigParams, error) {
func getGithubOAuth2ConfigParams(ctx context.Context, logger slog.Logger, db database.Store, vals *codersdk.DeploymentValues) (*githubOAuth2ConfigParams, error) {
params := githubOAuth2ConfigParams{
accessURL: vals.AccessURL.Value(),
clientID: vals.OAuth2.Github.ClientID.String(),
@@ -2250,6 +2250,16 @@ func getGithubOAuth2ConfigParams(ctx context.Context, db database.Store, vals *c
params.deviceFlow = GithubOAuth2DefaultProviderDeviceFlow
if len(params.allowOrgs) == 0 {
params.allowEveryone = GithubOAuth2DefaultProviderAllowEveryone
} else {
// The default provider is a GitHub App, which can only see memberships
// in organizations that have installed it. If the app isn't installed
// in an allowed organization, every login from that organization is
// rejected as "not a member".
logger.Warn(ctx, "the default GitHub OAuth provider can only see memberships in organizations that have installed the Coder GitHub app; "+
"users cannot log in until the app is installed in each allowed organization, or a custom GitHub OAuth app is configured",
slog.F("allowed_orgs", params.allowOrgs),
slog.F("install_url", coderd.GithubOAuth2DefaultProviderInstallURL),
)
}
return &params, nil