# Login with OAuth providers

> Provider-first sign-in — Google, GitHub, and Apple buttons above an email fallback.

A shadcn/ui block from the [@quill](https://www.quilldesignsystem.com) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/quill/login-oauth).

- Page, with a live preview: https://shadcn.exchange/r/quill/login-oauth
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/quill/login-oauth-light-411017028ec66a93.png
- Registry item: https://www.quilldesignsystem.com/r/login-oauth.json
- Categories: auth
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://www.quilldesignsystem.com/r/login-oauth.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- Registry items: `input`, `label`, `button`, `separator`

## Notes from the registry

Provider-first sign-in — Google, GitHub, and Apple buttons above an email fallback. Do: Treat the provider buttons as the primary path; keep the email form below the rule as a fallback, not the headline. Don't: Give the email field equal visual weight to the provider buttons when most users have a provider account. Do: Keep provider marks as their official inlined artwork, with GitHub and Apple taking currentColor so they invert correctly in Dusk. Don't: Restyle a provider mark to match your palette — that breaks the brand guidelines you agree to by using their sign-in. Use signup-social when this is account creation, not sign-in — signup-social also leads with OAuth providers. Use login when you store first-party passwords and don't want a provider-first order at all. Use login-minimal when you don't have OAuth providers configured and just need a single email field.

## Files

### `registry/blocks/login-oauth.tsx`

```tsx
'use client'
import { Button } from '@/components/ui/button'
import { Separator } from '@/components/ui/separator'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'

/**
 * Provider-first sign-in — the shape you need when identity comes from Google,
 * GitHub or Apple rather than a password you store. The provider buttons are
 * the primary path; the email field below the rule is the fallback, not the
 * headline (delete it for provider-only apps).
 *
 * The marks are inlined rather than pulled from the icon set: brand logos are
 * trademarked artwork on their own grids, not UI glyphs, and each provider's
 * brand guidelines expect its own colour. Google keeps its four-colour mark;
 * GitHub and Apple are monochrome by their own guidelines and take
 * currentColor so they invert correctly in Dusk.
 */

function GoogleMark() {
  return (
    <svg viewBox="0 0 18 18" width="16" height="16" aria-hidden focusable="false">
      {/* quill-check: allow raw-color — Google "G" mark, blue — fixed by Google's brand guidelines */}
      <path
        fill="#4285F4"
        d="M17.64 9.2c0-.64-.06-1.25-.16-1.84H9v3.48h4.84a4.14 4.14 0 0 1-1.8 2.72v2.26h2.92c1.7-1.57 2.68-3.88 2.68-6.62Z"
      />
      {/* quill-check: allow raw-color — Google "G" mark, green — fixed by Google's brand guidelines */}
      <path
        fill="#34A853"
        d="M9 18c2.43 0 4.47-.8 5.96-2.18l-2.92-2.26c-.8.54-1.84.86-3.04.86-2.34 0-4.32-1.58-5.03-3.7H.96v2.33A9 9 0 0 0 9 18Z"
      />
      {/* quill-check: allow raw-color — Google "G" mark, yellow — fixed by Google's brand guidelines */}
      <path
        fill="#FBBC05"
        d="M3.97 10.72a5.4 5.4 0 0 1 0-3.44V4.95H.96a9 9 0 0 0 0 8.1l3.01-2.33Z"
      />
      {/* quill-check: allow raw-color — Google "G" mark, red — fixed by Google's brand guidelines */}
      <path
        fill="#EA4335"
        d="M9 3.58c1.32 0 2.5.45 3.44 1.35l2.58-2.58C13.46.9 11.43 0 9 0A9 9 0 0 0 .96 4.95l3.01 2.33C4.68 5.16 6.66 3.58 9 3.58Z"
      />
    </svg>
  )
}

function GitHubMark() {
  return (
    <svg viewBox="0 0 24 24" width="16" height="16" fill="currentColor" aria-hidden focusable="false">
      <path d="M12 .3a12 12 0 0 0-3.8 23.4c.6.1.8-.3.8-.6v-2.2c-3.3.7-4-1.6-4-1.6-.6-1.4-1.4-1.8-1.4-1.8-1-.7.1-.7.1-.7 1.2.1 1.8 1.2 1.8 1.2 1 1.8 2.8 1.3 3.5 1 .1-.8.4-1.3.7-1.6-2.7-.3-5.5-1.3-5.5-5.9 0-1.3.5-2.4 1.2-3.2-.1-.3-.5-1.5.1-3.2 0 0 1-.3 3.3 1.2a11.5 11.5 0 0 1 6 0C17.3 4.7 18.3 5 18.3 5c.6 1.7.2 2.9.1 3.2.8.8 1.2 1.9 1.2 3.2 0 4.6-2.8 5.6-5.5 5.9.4.4.8 1.1.8 2.2v3.3c0 .3.2.7.8.6A12 12 0 0 0 12 .3Z" />
    </svg>
  )
}

function AppleMark() {
  return (
    // viewBox cropped to the glyph's own bounds (centred): in a 0 0 24 24 box it drew 12px tall beside a 16px Google and GitHub mark.
    <svg viewBox="2.17 2.4 18.51 18.51" width="16" height="16" fill="currentColor" aria-hidden focusable="false">
      <path d="M16.4 12.8c0-2.4 2-3.6 2-3.6-1.1-1.6-2.8-1.8-3.4-1.9-1.4-.1-2.8.9-3.5.9-.7 0-1.8-.8-3-.8-1.5 0-2.9.9-3.7 2.3-1.6 2.7-.4 6.8 1.1 9 .8 1.1 1.7 2.3 2.9 2.2 1.1 0 1.6-.7 3-.7s1.8.7 3 .7c1.2 0 2-1.1 2.8-2.2.9-1.2 1.2-2.4 1.2-2.5 0 0-2.4-.9-2.4-3.4ZM14.2 5.3c.6-.8 1-1.8.9-2.9-.9 0-2 .6-2.6 1.4-.6.7-1.1 1.8-.9 2.8 1 .1 2-.5 2.6-1.3Z" />
    </svg>
  )
}

/** Provider-first sign-in — Google, GitHub, and Apple buttons above an email fallback. */
export function LoginOauth() {
  return (
    <div className="flex w-[340px] flex-col gap-5">
      <div className="flex flex-col items-center gap-2 text-center">
        <span className="flex size-9 items-center justify-center rounded-md bg-primary text-sm font-medium text-primary-foreground">
          Q
        </span>
        <h1 className="fraunces-text font-heading text-lg text-foreground">Sign in to Quill</h1>
        <p className="text-sm text-muted-foreground">
          Use the account you already have.
        </p>
      </div>

      {/* Each label is at least as wide as the longest, so the three centred logos line up in one column. */}
      <div className="flex flex-col gap-2">
        <Button variant="outline" className="w-full justify-center gap-2">
          <GoogleMark /> <span className="min-w-[8.75rem] text-left">Continue with Google</span>
        </Button>
        <Button variant="outline" className="w-full justify-center gap-2">
          <GitHubMark /> <span className="min-w-[8.75rem] text-left">Continue with GitHub</span>
        </Button>
        <Button variant="outline" className="w-full justify-center gap-2">
          <AppleMark /> <span className="min-w-[8.75rem] text-left">Continue with Apple</span>
        </Button>
      </div>

      <div className="flex items-center gap-3">
        <Separator className="flex-1" />
        <span className="text-xs text-muted-foreground">or</span>
        <Separator className="flex-1" />
      </div>

      <form
        className="flex flex-col gap-3"
        onSubmit={(e) => e.preventDefault()}
      >
        <div className="flex flex-col gap-1.5">
          <Label htmlFor="oauth-email">Email</Label>
          <Input id="oauth-email" type="email" placeholder="you@example.com" />
        </div>
        <Button className="w-full">Continue with email</Button>
      </form>

      <p className="text-center text-xs leading-relaxed text-muted-foreground">
        By continuing you agree to the Terms and Privacy Policy.
      </p>
    </div>
  )
}
```
