Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

g1t.sh
82 linesCodeBlameRaw

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1import { Link, data, redirect } from "react-router";
2
3import type { Route } from "./+types/auth-github-callback";
4import { AuthCard } from "../components/auth-card";
5import { ContinueWithGithub } from "../components/github";
Merge main (membership, two-factor, GitHub repo roles) into tokens6import { PENDING_COOKIE, STATE_COOKIE, TWO_FACTOR_COOKIE, TWO_FACTOR_SECONDS, cookie, readCookie, stateMatches } from "../lib/github";
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily7import { githubSignIn } from "../lib/github.server";
8import { page } from "../lib/meta";
9import { safeNext } from "../lib/next";
10import { startSession } from "../lib/session.server";
11
12export function meta(args: Route.MetaArgs) {
13 return page(args, { title: "Signing in with GitHub · g1t" });
14}
15
16/**
17 * Where GitHub returns. The state must match the cookie this browser was
18 * given; identity then redeems it once, exchanges the code with the PKCE
19 * verifier, and says what happens next.
20 */
21export async function loader({ request }: Route.LoaderArgs) {
22 const url = new URL(request.url);
23 const clear = cookie(STATE_COOKIE, "", 0);
24 const failed = (error: string) => data({ error }, { headers: { "set-cookie": clear } });
25 if (url.searchParams.get("error")) {
26 // access_denied: the person cancelled on GitHub.
27 return failed("GitHub sign-in was cancelled.");
28 }
29 const code = url.searchParams.get("code");
30 const state = url.searchParams.get("state");
31 if (!code || !stateMatches(readCookie(request.headers.get("cookie"), STATE_COOKIE), state)) {
32 return failed("This sign-in did not start in this browser, or took too long. Start again.");
33 }
34 const finished = await githubSignIn.finish(state!, code);
35 if (!finished.ok) return failed(finished.error.message);
36 const done = finished.value;
37 const headers = new Headers({ "set-cookie": clear });
38 switch (done.kind) {
Merge main (membership, two-factor, GitHub repo roles) into tokens39 case "signed_in": {
40 // Two-factor authentication on: GitHub proved the account, a code
41 // from the app comes next.
42 const challenge = done.signedIn.twoFactorChallenge;
43 if (challenge) {
44 headers.append("set-cookie", cookie(TWO_FACTOR_COOKIE, challenge, TWO_FACTOR_SECONDS));
45 const next = safeNext(done.next);
46 throw redirect(`/login/two-factor${next === "/" ? "" : `?next=${encodeURIComponent(next)}`}`, { headers });
47 }
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily48 headers.append("set-cookie", startSession(done.signedIn.sessionToken));
49 throw redirect(safeNext(done.next), { headers });
Merge main (membership, two-factor, GitHub repo roles) into tokens50 }
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily51 case "linked":
52 throw redirect(safeNext(done.next === "/" ? "/settings/github" : done.next), { headers });
53 case "needs_link":
54 headers.append("set-cookie", cookie(PENDING_COOKIE, done.pending, 1800));
55 throw redirect(`/login?github=link${done.next === "/" ? "" : `&next=${encodeURIComponent(done.next)}`}`, { headers });
56 case "needs_username":
57 headers.append("set-cookie", cookie(PENDING_COOKIE, done.pending, 1800));
58 throw redirect("/auth/github/username", { headers });
59 }
60}
61
62export default function GithubCallback({ loaderData }: Route.ComponentProps) {
63 const error = loaderData?.error;
64 return (
65 <AuthCard
66 title="Signing in with GitHub"
67 subtitle="That did not work"
68 footer={
69 <Link to="/login" className="text-fg underline underline-offset-4">
70 Sign in another way
71 </Link>
72 }
73 >
74 <p className="text-sm text-danger" role="alert">
75 {error}
76 </p>
77 <div className="mt-6">
78 <ContinueWithGithub href="/auth/github" label="Try again with GitHub" />
79 </div>
80 </AuthCard>
81 );
82}

This file's history is long; its oldest lines are credited to the oldest commit read.