Skip to content
File

Blob: src/client/pages/AuthSignInPage.tsx

typescript61 lines
1import { ShieldCheck } from "lucide-react";
2 
3import { Button, Card, ErrorBanner, PageHeader } from "@/client/components/ui";
4 
5export type AuthSignInPageProps = {
6 errorCode?: string;
7};
8 
9const ERROR_MESSAGES: Record<string, string> = {
10 invalid_request: "The sign-in callback was missing required parameters. Start a fresh sign-in.",
11 missing_state:
12 "The sign-in transaction expired before tessera redirected back. Start a fresh sign-in.",
13 invalid_state:
14 "The tab where you started signing in was closed before tessera redirected back. Start a fresh sign-in.",
15 token_exchange_failed:
16 "tessera could not be reached during the token exchange. Try again, then check your network if it persists.",
17 invalid_id_token: "tessera returned an ID token that did not validate. Contact your operator.",
18 oidc_unavailable: "tessera sign-in is not configured for this deployment. Contact your operator.",
19 session_create_failed:
20 "Could not create your session after sign-in. Try again, then check the worker logs if it persists.",
21};
22 
23function describeError(code: string | undefined): string | null {
24 if (!code) return null;
25 return ERROR_MESSAGES[code] ?? "Sign-in failed. Start a fresh sign-in.";
26}
27 
28export function AuthSignInPage({ errorCode }: AuthSignInPageProps) {
29 const errorText = describeError(errorCode);
30 return (
31 <div className="mx-auto max-w-md py-10">
32 <PageHeader className="!mb-4">
33 <div>
34 <h1 className="m-0 font-display text-3xl font-semibold text-zinc-900 dark:text-zinc-100">
35 Sign in
36 </h1>
37 <p className="m-0 mt-2 text-sm text-zinc-500 dark:text-zinc-400">
38 Authenticate with tessera to manage your namespaces.
39 </p>
40 </div>
41 </PageHeader>
42 {errorText ? <ErrorBanner>{errorText}</ErrorBanner> : null}
43 <Card>
44 <div className="flex flex-col items-stretch gap-5">
45 <pre className="m-0 overflow-x-auto rounded-lg border border-zinc-200 bg-zinc-50/60 p-3 font-mono text-xs leading-relaxed text-zinc-500 dark:border-zinc-800/60 dark:bg-zinc-950/40">
46 <code className="bg-transparent p-0 font-mono text-xs">
47 <span className="select-none">$ </span>tessera authorize{"\n"}
48 <span className="select-none">→ </span>verify id_token{"\n"}
49 <span className="select-none">→ </span>claim @namespace
50 </code>
51 </pre>
52 <Button href="/auth/start" variant="primary">
53 <ShieldCheck className="h-4 w-4" aria-hidden="true" />
54 Continue with tessera
55 </Button>
56 </div>
57 </Card>
58 </div>
59 );
60}