Repository navigation
Conversation
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>
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>
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>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved critical authentication flaws can permit expired proof consumption, misidentify users across GitHub instances, and expose callback code and state values in request logs.
14 open issues
Suppress auth payloads before JSON parsing · New Reject callbacks when the selected revision differs from this replica · New Bind the issuer to a validated GitHub instance · New Lock the handoff row before checking expiry and consuming · New Check attempt expiry after locking with PostgreSQL time · New Wait for observable database lock waits in concurrency tests · New Test wrong binding before successful attempt consumption · New Bound or rate-limit durable denial auditing · New Use database time for both expiry cleanup predicates · New Require an exact origin for the browser origin setting · New Use an indexed, statement-stable cutoff for bucket cleanup · New Keep the binding cookie valid through handoff expiry · New Add direct tests for encryption and decryption helpers · New Pass the Prisma config to migrate resolve · New
What changed in this PR
Adds GitHub identity proof to Hub while keeping authentication separate from admission, sessions, and product access. Successful callbacks resolve an external identity and return a short-lived, browser-bound admission handoff.
Changes:
- Adds OAuth start and callback routes with state, PKCE, browser binding, and provider request deadlines.
- Adds database-backed one-use attempts, handoffs, rate limits, revocation state, and security audits.
- Adds runtime configuration, documentation, and unit, migration, and concurrency test coverage.
| File | Description |
|---|---|
hub/test/database/reset-database/index.ts |
Restores global revocation state after resets. |
hub/test/database/identity-foundation/index.db.test.ts |
Adds authentication schema and constraint checks. |
hub/test/database/authentication-proof-migration/index.db.test.ts |
Adds an identity-foundation upgrade test. |
hub/server/utils/http/read-cookie/index.ts |
Reads bounded cookie values. |
hub/server/utils/authentication/parse-browser-binding/index.ts |
Validates browser-binding values. |
hub/server/utils/authentication/hash-authentication-value/index.ts |
Hashes authentication artifacts. |
hub/server/utils/authentication/encrypt-authentication-value/index.ts |
Encrypts stored PKCE verifiers. |
hub/server/utils/authentication/decrypt-authentication-value/index.ts |
Decrypts stored PKCE verifiers. |
hub/server/utils/authentication/create-opaque-value/index.ts |
Generates random authentication values. |
hub/server/run-api/index.ts |
Initializes optional authentication before server startup. |
hub/server/run-api/index.test.ts |
Covers authentication startup ordering and failures. |
hub/server/routes/types.ts |
Adds authentication route dependencies. |
hub/server/routes/index.ts |
Registers configured authentication endpoints. |
hub/server/routes/api/auth/github/types.ts |
Defines authentication route dependency types. |
hub/server/routes/api/auth/github/start/post/index.ts |
Starts OAuth and sets browser binding. |
hub/server/routes/api/auth/github/index.test.ts |
Covers route validation, responses, and logging. |
hub/server/routes/api/auth/github/callback/get/index.ts |
Completes proof and returns a pending handoff. |
hub/server/repositories/security-audits/parse-security-audit-event/index.ts |
Validates authentication audit events. |
hub/server/repositories/security-audits/get-security-audit-data/index.ts |
Maps authentication events to audit records. |
hub/server/repositories/security-audits/create-security-audit/types.ts |
Adds typed authentication audit events. |
hub/server/repositories/security-audits/create-security-audit/index.test.ts |
Covers authentication audit mappings. |
hub/server/repositories/authorization-attempts/delete-expired-authorization-attempts/index.ts |
Deletes expired authorization attempts. |
hub/server/repositories/authorization-attempts/create-authorization-attempt/types.ts |
Defines authorization-attempt creation inputs. |
hub/server/repositories/authorization-attempts/create-authorization-attempt/index.ts |
Validates and stores authorization attempts. |
hub/server/repositories/authorization-attempts/consume-authorization-attempt/types.ts |
Defines attempt-consumption inputs. |
hub/server/repositories/authorization-attempts/consume-authorization-attempt/index.ts |
Implements one-use attempt consumption. |
hub/server/repositories/authentication-revocation-generations/lock-authentication-revocation-generation/index.ts |
Locks global revocation state. |
hub/server/repositories/authentication-revocation-generations/increment-authentication-revocation-generation/index.ts |
Advances global revocation state. |
hub/server/repositories/authentication-revocation-generations/get-authentication-revocation-generation/index.ts |
Reads the global revocation generation. |
hub/server/repositories/authentication-rate-limits/reserve-authentication-rate-limit/types.ts |
Defines rate-limit reservation inputs. |
hub/server/repositories/authentication-rate-limits/reserve-authentication-rate-limit/index.ts |
Reserves shared database-backed request capacity. |
hub/server/repositories/authentication-rate-limits/reserve-authentication-rate-limit/index.db.test.ts |
Covers rate-limit concurrency and rollback. |
hub/server/repositories/authentication-providers/lock-authentication-provider-selection/index.ts |
Locks provider selection during handoff decisions. |
hub/server/repositories/admission-handoffs/find-admission-handoff/index.ts |
Finds handoffs by token digest. |
hub/server/repositories/admission-handoffs/delete-expired-admission-handoffs/index.ts |
Deletes expired handoffs. |
hub/server/repositories/admission-handoffs/create-admission-handoff/types.ts |
Defines handoff persistence inputs. |
hub/server/repositories/admission-handoffs/create-admission-handoff/index.ts |
Validates and stores handoff evidence. |
hub/server/repositories/admission-handoffs/consume-admission-handoff/types.ts |
Defines handoff-consumption results. |
hub/server/repositories/admission-handoffs/consume-admission-handoff/index.ts |
Implements database-timed handoff consumption. |
hub/server/integrations/github/errors.ts |
Adds a safe provider-request error. |
hub/server/integrations/github/create-user-authentication-adapter/types.ts |
Defines GitHub configuration and identity evidence. |
hub/server/integrations/github/create-user-authentication-adapter/index.ts |
Implements OAuth exchange and current-user lookup. |
hub/server/integrations/github/create-user-authentication-adapter/index.test.ts |
Covers OAuth arguments, identity mapping, and deadlines. |
hub/server/integrations/express/read-trusted-proxy-hops/index.ts |
Parses explicit proxy trust settings. |
hub/server/integrations/express/read-trusted-proxy-hops/index.test.ts |
Covers proxy-setting defaults and bounds. |
hub/server/domains/authentication/types.ts |
Defines shared authentication contracts. |
hub/server/domains/authentication/start-authentication-proof/types.ts |
Defines proof-start dependencies and results. |
hub/server/domains/authentication/start-authentication-proof/index.ts |
Creates bound authorization attempts and provider URLs. |
hub/server/domains/authentication/start-authentication-proof/index.test.ts |
Covers attempt storage and revision denial. |
hub/server/domains/authentication/run-admission-handoff-transaction/types.ts |
Defines transaction-scoped handoff repositories. |
hub/server/domains/authentication/run-admission-handoff-transaction/index.ts |
Composes serializable handoff transactions. |
hub/server/domains/authentication/record-authentication-denial/index.ts |
Preserves denial and audit failures. |
hub/server/domains/authentication/record-authentication-denial/index.test.ts |
Covers denial audit outcomes. |
hub/server/domains/authentication/read-github-authentication-configuration/index.ts |
Parses explicit authentication configuration. |
hub/server/domains/authentication/read-github-authentication-configuration/index.test.ts |
Covers disabled, complete, and invalid configuration. |
hub/server/domains/authentication/errors.ts |
Defines typed authentication failures. |
hub/server/domains/authentication/create-github-authentication-services/types.ts |
Defines service configuration inputs. |
hub/server/domains/authentication/create-github-authentication-services/index.ts |
Connects provider, identity, persistence, and audits. |
hub/server/domains/authentication/create-admission-handoff/index.ts |
Creates handoffs under revision and revocation locks. |
hub/server/domains/authentication/create-admission-handoff/index.test.ts |
Covers drift rejection and bounded retries. |
hub/server/domains/authentication/consume-admission-handoff/index.ts |
Validates and consumes admission handoffs. |
hub/server/domains/authentication/complete-authentication-proof/types.ts |
Defines proof-completion contracts. |
hub/server/domains/authentication/complete-authentication-proof/index.ts |
Resolves provider evidence into a pending handoff. |
hub/server/domains/authentication/complete-authentication-proof/index.test.ts |
Covers completion ordering and failure boundaries. |
hub/server/domains/authentication/authentication-proof.db.test.ts |
Covers one-use, expiry, binding, and revocation behavior. |
hub/server/domains/authentication/authentication-proof-races.db.test.ts |
Adds provider-selection and revocation race cases. |
hub/server/create-app/types.ts |
Adds authentication and proxy options. |
hub/server/create-app/index.ts |
Injects authentication services and proxy settings. |
hub/schema/migrations/20261030170000_authentication_proof/migration.sql |
Adds authentication tables, constraints, and protection triggers. |
hub/schema/external-identity.prisma |
Links external identities to handoffs. |
hub/schema/authorization-attempt.prisma |
Models persisted authorization attempts. |
hub/schema/authentication-revocation-generation.prisma |
Models global authentication revocation state. |
hub/schema/authentication-rate-limit.prisma |
Models shared request-limit buckets. |
hub/schema/authentication-provider-revision.prisma |
Links provider revisions to authentication artifacts. |
hub/schema/admission-handoff.prisma |
Models browser-bound admission handoffs. |
hub/docs/README.md |
Links the authentication proof guide. |
hub/docs/development.md |
Documents local authentication setup. |
hub/docs/database.md |
Describes the expanded identity schema. |
hub/docs/authentication.md |
Documents proof flow, storage, and non-goals. |
hub/docs/architecture.md |
Places authentication proof within Hub’s architecture. |
hub/.env.example |
Adds authentication and proxy configuration examples. |
Review effort: Max (auto)
| app.disable("x-powered-by") | ||
| app.set("trust proxy", trustedProxyHops) | ||
| app.use(createRequestLogger(logger)) | ||
| app.use(express.json()) |
Comment on lines
+56
to
+60
| function getRevision() { | ||
| return getSelectedProviderRevision(adapter.providerKey, { | ||
| findAuthenticationProvider: (key) => findAuthenticationProvider(prisma, key), | ||
| }) | ||
| } |
|
|
||
| return { | ||
| provider: "github", | ||
| issuer: "https://github.com", |
| database: ConsumeAdmissionHandoffDatabase, | ||
| input: { browserBindingDigest: string; id: string }, | ||
| ): Promise<ConsumeAdmissionHandoffResult> { | ||
| const rows = await database.$queryRaw<Array<{ status: ConsumeAdmissionHandoffResult }>>` |
Comment on lines
+26
to
+28
| expiresAt: { gt: parsed.consumedAt }, | ||
| }, | ||
| data: { consumedAt: parsed.consumedAt }, |
|
|
||
| const configurationSchema = z | ||
| .object({ | ||
| appOrigin: z.url(), |
Comment on lines
+33
to
+34
| WHERE "window_started_at" + make_interval(secs => ${parsed.windowSeconds * 2}) | ||
| <= clock_timestamp() |
| code: parsed.data.code, | ||
| state: parsed.data.state, | ||
| }) | ||
| response.status(200).json({ |
| @@ -0,0 +1,18 @@ | |||
| import { createDecipheriv } from "node:crypto" | |||
|
|
|||
| export function decryptAuthenticationValue(value: string, key: Buffer): string { | |||
| } | ||
| await promisify(execFile)( | ||
| process.execPath, | ||
| [prisma, "migrate", "resolve", "--applied", migrationName], |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Why
Hub needs to prove who a person is before a later layer decides whether that person may use Hub. This adds a GitHub authentication proof flow while keeping identity proof separate from membership, admission, sessions, and product access.
What changes
Hub can now start and complete GitHub's OAuth authorization-code flow with state, PKCE, an exact callback URI, and a browser-binding cookie. GitHub's numeric user ID becomes the immutable external identity subject; login, name, avatar, and email remain display attributes.
A successful callback resolves the external identity through the identity kernel and returns a short-lived, opaque, one-use admission handoff. The handoff is explicitly pending admission and cannot be used as a Hub session. PostgreSQL enforces one-use transitions and uses database time for expiry. Database-backed start and callback rate limits work across Hub replicas, provider requests have fixed deadlines, and provider tokens are discarded after the current-user lookup without being persisted, logged, or audited.
This change does not issue a usable session, evaluate membership or admission, add OIDC or Entra support, grant repository permissions or product authority, publish prototypes, or change the UI.
Storybook screenshots
No Storybook screenshots are required because this change does not alter presentation or stories.