Skip to content

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

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

Copilot wants to merge 4 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

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.

Ben Thomas and others added 4 commits October 27, 2026 12:58
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 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.

-- CreateTable
CREATE TABLE "identity_store_states" (
"id" UUID NOT NULL,
"session_generation" INTEGER NOT NULL DEFAULT 0,
Comment on lines +57 to +68
const store = createIdentityStore(prisma)
const providerRevision = configuration
? await ensureGitHubProviderRevision(store, configuration)
: null
const admissionPolicy = createAdmissionPolicy(environment, store)
const settings: AuthenticationSettings = {
origin: origin.origin,
secureCookies: origin.protocol === "https:",
configured: configuration !== null,
admissionPolicy: admissionPolicy.name,
trustedProxyHops: readTrustedProxyHops(environment),
}
key: "github",
type: "github",
enabled: true,
revision: (current?.revision ?? 0) + 1,
"The repository permission identity did not match.",
)
}
return permission.permission !== "none"
Comment on lines +1 to +9
export class AuthenticationError extends Error {
constructor(
readonly status: number,
readonly code: string,
message: string,
) {
super(message)
}
}

export function AuthenticationApplication() {
const [session, setSession] = useState<SessionResponse | null>(null)
const [error, setError] = useState<string | null>(null)
Comment on lines +39 to +59
headers: { "X-CSRF-Token": session.csrfToken },
})
if (!response.ok) throw new Error("Sign-in request failed")
const data = (await response.json()) as { authorizationUrl: string }
window.location.assign(data.authorizationUrl)
} catch {
setError("Hub could not start GitHub sign-in.")
setLoading(false)
}
}

async function signOut() {
if (!session) return
setLoading(true)
setError(null)
try {
const response = await fetch("/api/session", {
method: "DELETE",
credentials: "same-origin",
headers: { "X-CSRF-Token": session.csrfToken },
})
Comment on lines +47 to +48
for (const repository of response.repositories) {
if (await hasPermission(token, profile, repository.full_name)) return true
expect(runtime.service.revokeAll).toHaveBeenCalledWith(sessionToken)
})

it("redirects callback failures generically and never logs OAuth secrets", async () => {
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.

2 participants