Skip to content

feat(hub): add GitHub user authentication - #120

Open
Copilot wants to merge 6 commits into
copilot/hub-identity-systemfrom
copilot/hub-identity-behavior
Open

Copilot wants to merge 6 commits into
copilot/hub-identity-systemfrom
copilot/hub-identity-behavior

Conversation

Copilot AI commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Why

Hub needs a production sign-in path that preserves the current GitHub-based experience without treating GitHub identity as permission to use Hub. GitHub proves who the user is; Hub applies a separate admission policy, and repository authorization remains a separate product boundary.

What changes

Hub now supports GitHub user authorization with OAuth state, a browser binding, and PKCE. Successful authorization creates a long-lived provider-neutral Hub session, while provider credentials and source-integration credentials remain independent.

The API sets protected session and CSRF cookies, checks the Hub origin for state-changing requests, omits authentication payloads from logs, and rate-limits authentication endpoints using the configured trusted-proxy boundary. Users can sign out, require fresh verification for sensitive actions, or revoke every session. Fresh verification expires after five minutes.

Admission is an explicit policy hook. The compatibility policy can admit a GitHub user under the configured rule, but authentication does not grant repository access and does not make repository permission checks the default admission mechanism.

flowchart LR
  Browser -->|OAuth + PKCE| GitHub
  GitHub -->|Verified user| HubAuth[Hub authentication]
  HubAuth -->|Identity context| Admission[Hub admission policy]
  Admission -->|Admitted user| Session[Hub session]
  Session -. separate boundary .-> RepositoryAuth[Repository authorization]
Loading

Storybook screenshots

Hub/Pages/Identity/Sign in / Signed out — dark theme, 1280 × 720

Hub sign-in page signed out

Hub/Pages/Identity/Sign in / Signed in — dark theme, 1280 × 720

Hub sign-in page signed in

Hub/Pages/Identity/Sign in / Unconfigured — dark theme, 1280 × 720

Hub sign-in page with GitHub authentication unconfigured

Hub/Pages/Identity/Sign in / Authorization failed — dark theme, 1280 × 720

Hub sign-in page after GitHub authorization fails

Copilot AI requested review from a team and nshki as code owners October 26, 2026 23:31
Copilot AI max review requested due to automatic review settings October 26, 2026 23:31

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because there is no eligible user to bill.

An enterprise owner can allow the organization to be billed for reviews like this by enabling Copilot code review for users without a license.

Copilot AI added this pull request to stack #122 October 26, 2026 23:31
@alliscode
alliscode force-pushed the copilot/hub-identity-behavior branch from aa35eb3 to b4b9597 Compare October 28, 2026 18:25
@alliscode alliscode changed the title feat(hub): add GitHub identity and session policies feat(hub): add GitHub user authentication Oct 28, 2026
@alliscode
alliscode requested a max review from Copilot October 28, 2026 21:53

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread hub/schema/migrations/20261026195151_identity/migration.sql Outdated
Comment thread hub/server/domains/authentication/create-runtime/index.ts
Comment thread hub/server/domains/authentication/ensure-provider-revision/index.ts Outdated
Comment thread hub/server/integrations/github/check-repository-admission/index.ts
Comment thread hub/server/utils/authentication-error/index.ts
Comment thread hub/app/javascript/application/authentication/index.tsx Outdated
Comment thread hub/app/javascript/application/authentication/index.tsx Outdated
Comment thread hub/server/integrations/github/check-repository-admission/index.ts Outdated
Comment thread hub/server/routes/authentication.test.ts
Ben Thomas and others added 5 commits October 29, 2026 08:39
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@alliscode
alliscode force-pushed the copilot/hub-identity-behavior branch from b4b9597 to 8aa3ea2 Compare October 29, 2026 15:50
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Comment thread hub/docs/identity.md

The callback consumes an attempt once, checks the same-browser binding and current provider and revocation state, exchanges the code with PKCE, and reads the authenticated GitHub profile. Hub maps GitHub's immutable numeric account ID to `ExternalIdentity.subject`. The user access token exists only while requesting that profile; Hub never stores it.

Hub sessions use a random opaque cookie and store only its digest. Authentication and session cookies are `HttpOnly`, `SameSite=Lax`, path-scoped, and `Secure` on HTTPS. State-changing routes require the configured origin and a matching CSRF cookie and header. Authentication routes omit request payloads from logs.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you could run documentation through a doc convention pass, that would be great. Lots of AI language here that makes it hard to read.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The directory name and function name don't line up. Let's make sure they align here and across this PR.

On an unrelated note, factory functions can get confusing to reason about, so I'd prefer simplifying by just calling these bound functions at their respective call sites. The test files for this function have also ballooned unnecessarily. I'd argue that this factory function (and others) aren't needed unless there's a clear reason we should include them.

import { readTrustedProxyHops } from "#server/integrations/express/read-trusted-proxy-hops"
import { prisma } from "#server/integrations/prisma"

function readOrigin(environment: NodeJS.ProcessEnv): URL {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's extract nested helpers into their own function directories. They don't need their own corresponding test files if the parent function covers important cases.

This applies across this PR.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could arguably live at domains/authentication/constants.ts instead of a nested directory with nothing else in it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants