Skip to content

Auth Sso

Enterprise SSO sign-in: email-first step that detects the domain; SSO domains show the org + identity provider and a “Continue with Okta” button, others fall back to a password field.

neo-corporate/layout/auth-sso
Open ↗

Source

"use client";

import { useId, useState, type FormEvent } from "react";
import { ArrowLeft, Building2, Loader2, ShieldCheck } from "lucide-react";
import { cn } from "@/lib/utils";

export interface AuthSsoProps {
  brand?: string;
  brandHref?: string;
  /** Email domains that have SSO configured, mapped to the IdP name. */
  ssoDomains?: Record<string, string>;
  onContinue?: (email: string, method: "sso" | "password") => void;
  className?: string;
}

function LedgerlyMark({ className }: { className?: string }) {
  return (
    <svg aria-hidden viewBox="0 0 28 28" className={cn("size-7 shrink-0", className)}>
      <rect width="28" height="28" rx="7" fill="var(--da-primary)" />
      <path d="M8 8v12h12" stroke="var(--da-primary-fg)" strokeWidth="2.6" fill="none" strokeLinecap="round" />
      <path d="M13 15h7M13 11h7" stroke="var(--da-primary-fg)" strokeWidth="2.2" strokeLinecap="round" opacity=".7" />
    </svg>
  );
}

/** Enterprise SSO sign-in: email-first step that detects the domain; SSO domains show the org + identity provider and a “Continue with Okta” button, others fall back to a password field. */
export function AuthSso({
  brand = "Ledgerly",
  brandHref = "/",
  ssoDomains = { "northwind.com": "Okta", "lumen.health": "Microsoft Entra ID", "parcel.io": "Google Workspace" },
  onContinue,
  className,
}: AuthSsoProps) {
  const id = useId();
  const [email, setEmail] = useState("priya@northwind.com");
  const [step, setStep] = useState<"email" | "checking" | "sso" | "password">("email");
  const domain = email.split("@")[1]?.toLowerCase() ?? "";
  const idp = ssoDomains[domain];
  const next = (e: FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    if (step === "email") {
      setStep("checking");
      setTimeout(() => setStep(idp ? "sso" : "password"), 600);
    } else if (step === "sso" || step === "password") onContinue?.(email, step);
  };
  const field =
    "da-stroke h-10 w-full rounded-da-md bg-da-surface px-3 text-sm shadow-da-sm outline-none focus:border-da-primary focus:ring-3 focus:ring-da-ring/25";
  return (
    <main className={cn("grid min-h-dvh place-items-center bg-da-bg px-4 py-12 text-da-fg", className)}>
      <div className="w-full max-w-sm">
        <a href={brandHref} className="da-focus flex w-fit items-center gap-2 rounded-da-sm font-da-display text-lg font-extrabold">
          <LedgerlyMark />
          {brand}
        </a>
        <h1 className="mt-10 font-da-display text-2xl font-extrabold tracking-da-display">Sign in with your work account</h1>
        <p className="mt-1.5 text-sm text-da-muted-fg">We’ll redirect you to your company’s identity provider if SSO is enabled.</p>
        <form onSubmit={next} className="mt-8 grid gap-4">
          <div className="grid gap-1.5">
            <label htmlFor={`${id}-e`} className="text-sm font-medium">
              Work email
            </label>
            <div className="flex gap-2">
              <input
                id={`${id}-e`}
                type="email"
                required
                autoComplete="email"
                value={email}
                readOnly={step !== "email"}
                onChange={(e) => setEmail(e.target.value)}
                className={cn(field, step !== "email" && "bg-da-surface-2 text-da-muted-fg")}
              />
              {step !== "email" && step !== "checking" && (
                <button
                  type="button"
                  onClick={() => setStep("email")}
                  aria-label="Change email"
                  className="da-focus da-stroke grid size-10 shrink-0 place-items-center rounded-da-md bg-da-surface hover:bg-da-surface-2"
                >
                  <ArrowLeft aria-hidden className="size-4" />
                </button>
              )}
            </div>
          </div>
          <div aria-live="polite">
            {step === "sso" && (
              <div className="da-stroke flex items-center gap-3 rounded-da-md bg-da-accent/60 p-3 text-sm transition-opacity duration-(--da-duration) starting:opacity-0">
                <Building2 aria-hidden className="size-5 text-da-accent-fg" />
                <p>
                  <span className="font-semibold">{domain}</span> uses single sign-on via <span className="font-semibold">{idp}</span>.
                </p>
              </div>
            )}
            {step === "password" && (
              <label className="grid gap-1.5 text-sm font-medium transition-opacity duration-(--da-duration) starting:opacity-0">
                Password
                <input type="password" required autoComplete="current-password" autoFocus className={field} />
              </label>
            )}
          </div>
          <button
            type="submit"
            disabled={step === "checking"}
            className="da-focus da-transition inline-flex h-10 items-center justify-center gap-2 rounded-da-md bg-da-primary text-sm font-semibold text-da-primary-fg hover:bg-da-primary/90 disabled:opacity-70"
          >
            {step === "checking" && <Loader2 aria-hidden className="size-4 animate-spin motion-reduce:animate-none" />}
            {step === "email" ? "Continue" : step === "checking" ? "Checking your domain…" : step === "sso" ? `Continue with ${idp}` : "Sign in"}
          </button>
        </form>
        <p className="mt-10 flex items-center gap-2 border-t border-da-border pt-6 text-xs text-da-muted-fg">
          <ShieldCheck aria-hidden className="size-4 text-da-success" /> SAML 2.0 &amp; OIDC · SCIM provisioning · Enforced MFA
        </p>
      </div>
    </main>
  );
}

export default AuthSso;

modules/neo-corporate/layout/auth-sso/index.tsx

Props

PropTypeDefaultDescription
brandstring—Brand name.
brandHrefstring—Brand link target.
ssoDomainsRecord<string, string>—Email domains that have SSO configured, mapped to the IdP name.
onContinue(email: string, method: "sso" | "password") => void—Callback.
classNamestring—Extra classes on the root.

Other auth screen variants in Neo Corporate

Auth screen in other art directions

Auth Card

Centered login card on a dotted paper background: tilted wordmark sticker, ink title band, GitHub button, email + password with forgot link, error slot and a big pressable yellow submit.

BrutalistAuth screen

Auth Magic Link

Passwordless login split screen: blue product panel with staggered pipeline cards (desktop), huge uppercase headline, single email field and yellow send button, then a 'Check your inbox' state with open-mail and retry actions.

BrutalistAuth screen

Auth Screen

Split sign-in / sign-up page: form column with GitHub & Google buttons, email + password (show/hide), remember-me, error slot and pending state; yellow grid panel with a big customer quote on desktop.

BrutalistAuth screen

Auth Signup Steps

Three-step signup wizard: ruled step tabs (done in ink, current in yellow) fused to a card with account fields, team size and use-case tile choices, Back/Continue and a success state.

BrutalistAuth screen

Auth Floating

Sign-up screen: centered glass card (Google button, divider, email magic-link form with success state) surrounded on desktop by floating, bobbing glass preview cards and a gradient orb.

GlassAuth screen

Auth Onboarding

Three-step onboarding glass card: workspace name with URL preview, role radio chips, calendar connection buttons; gradient progress bar, back/continue and a finish screen.

GlassAuth screen

Auth Passkey

Passkey sign-in glass card: glowing gradient fingerprint orb, account email, ‘Sign in with passkey’ with waiting / success / error states and email-link or password fallbacks.

GlassAuth screen

Auth Screen

Centered 40px-blur glass panel over the mesh and two soft orbs: gradient logo, Google/Microsoft buttons, email + password (show/hide), forgot link, error slot, gradient pill submit. Sign-in and sign-up modes.

GlassAuth screen

Auth Screen

Centered passwordless login in three steps: provider choice (Google, email, SAML SSO) → email form → "check your email" confirmation. Faint indigo glow on top, legal footer.

MinimalAuth screen

Auth Split

Split sign-in screen: form on the left (email, password with reveal, remember me, error alert) and an always-dark brand panel with indigo glow, grid, customer quote and three stats on large screens.

MinimalAuth screen

Auth Sso

SSO-first sign-in card on a tinted page: key icon, Google / GitHub / Microsoft buttons, an ‘or use SAML SSO’ divider and work-email discovery with inline arrow submit, legal links below.

MinimalAuth screen

Auth Verify

Email verification screen: mail icon, six single-digit mono boxes (split 3 + 3) with auto-advance, paste, arrow/backspace navigation, auto-submit, error and success states and a resend countdown.

MinimalAuth screen

Auth Centered

Minimal centered sign-in with lots of air: logo, small title, two hairline-boxed fields stacked edge to edge, ink button, “or continue with” text links and a mono legal line at the very bottom.

Mono CleanAuth screen

Auth Magic

Passwordless: a huge “Enter your email” prompt with a single oversized underline input and ↵ button; after submit, a large confirmation with the address and a mono resend link.

Mono CleanAuth screen

Auth Screen

Split sign-in: the left half is an ink panel with a large statement and mono footer; the right half holds a minimal underline form (email, password), an ink button and text links. Panel hides on mobile.

Mono CleanAuth screen

Auth Steps

Three-step sign-up with an index header “01 / 03 — Your account” and segmented hairline progress; underline fields per step, Back text link and ink Continue; final step shows the site address preview.

Mono CleanAuth screen

Auth Magic

Passwordless sign-in: one rounded email field and “Send me a link”, then a gentle sent state with an open-envelope in a sage circle, the address, resend and change-email links.

Organic SoftAuth screen

Auth Onboarding

Post-signup onboarding: two gentle steps (industry as pill radio cards, goals as check cards) with a leaf progress bar, back/continue pills and a warm “all set” finish.

Organic SoftAuth screen

Auth Screen

Centered sign-in on cream with two soft blobs behind a rounded card: serif welcome, filled inputs, password reveal, sage pill submit, Google alternative and a sign-up link.

Organic SoftAuth screen

Auth Split

Split sign-up: form on cream (name, email, company, team-size pills) and an arch-topped landscape illustration panel with sun and hills plus a quote card (hidden below lg).

Organic SoftAuth screen

Auth Magic

“Check your inbox” screen: flat envelope with a gently bobbing letter, email in bold, Gmail/Outlook shortcut pills, resend with countdown and change-email link.

Soft FlatAuth screen

Auth Screen

Centered friendly sign-in: big rounded white card among pastel shapes, shape logo, Google button, rounded divider, soft email/password fields with reveal, error alert and periwinkle pill.

Soft FlatAuth screen

Auth Split

Sign-up split: lavender panel with a flat illustration of tilted task cards and perk list on large screens, roomy name + email form with a success message on the other side.

Soft FlatAuth screen

Auth Welcome

First-run profile setup: big live avatar preview, grid of pastel emoji avatars (native radios), display-name field with preview chip and a “Let’s go” button enabled once named.

Soft FlatAuth screen