Features · Sign-in & email

Google minus Google Cloud.

“Continue with Google” and email sign-in for the people who use your app — no Google Cloud project, no OAuth client, no keys. Its sign-up mail goes out in your app’s name, from your own domain once it verifies.

Read the docsAgent setup

What your agent calls

  • appAuthConfigure
  • appAuthStatus
  • appAuthEmailConnect
  • appAuthEmailStatus
claude · ~/franks-kitchenexample

Let staff sign in with Google

Update(app/login/page.tsx)

1 line · Google button → oauth.trytofu.ai/start

Write(app/auth/confirm/route.ts)

new route · verifyOtp for the email link

tofu · appAuthConfigure confirmed: true

configured · Google sign-in, and email sign-in as well

How Google sign-in works

Tofu talks to Google, so your app does not have to.

Tofu’s broker at oauth.trytofu.ai owns one Google client and one permanent callback. Your app sends the browser there; the broker signs the person into your app’s own auth service — the Supabase project behind its managed database.

Sign-up email

Sign-up email, in your app’s name.

Email sign-in is switched on in the same step, so an account always has a way back in if a third-party sign-in is ever unavailable.

Your app’s own auth service sends its confirmation, magic-link, password-reset, invitation, address-change and reauthentication mail through Tofu’s email setup, with your app’s name as the sender. No SMTP password, and no email provider to sign up for.

Every message carries a one-time code as well as a link, because mail scanners that open links first would otherwise spend the token before your user could.

From your domain

Six records, none at your apex.

Once your domain is connected, appAuthEmailConnect creates a sending identity for send.frankskitchen.com and publishes its records — all under send., so the mail your domain already receives is untouched. Remove them, and the domain is exactly as it was.

TypeName, in frankskitchen.comValue
CNAME‹token 1›._domainkey.send‹token 1›.dkim.amazonses.com
CNAME‹token 2›._domainkey.send‹token 2›.dkim.amazonses.com
CNAME‹token 3›._domainkey.send‹token 3›.dkim.amazonses.com
MX 10bounce.sendfeedback-smtp.‹region›.amazonses.com
TXTbounce.sendv=spf1 include:amazonses.com ~all
TXT_dmarc.sendv=DMARC1; p=none; rua=mailto:…

With the Cloudflare approval your domain connection already holds, Tofu writes them itself — no second approval. Anywhere else, it lists them to add, and asks the email provider to check.

Until the email provider reports the domain verified, mail keeps going out from notify.trytofu.app — sign-up never stops while you wait.

The one route your app owns

A link a scanner cannot spend.

Each message links to /auth/confirm on your app’s own address, and the token is spent only when your app calls verifyOtp — so a scanner that opens the link first reaches your app, not the sign-in service.

A new app built through the /tofu skill gets this route; your agent writes it. An app deployed without it still signs people in with the code in each message.

app/auth/confirm/route.tsnext.js
import { createClient } from '@/lib/supabase/server';
import { NextResponse } from 'next/server';

export async function GET(request) {
  const { searchParams, origin } = new URL(request.url);
  const token_hash = searchParams.get('token_hash');
  const type = searchParams.get('type');
  if (token_hash && type) {
    const supabase = await createClient();
    const { error } =
      await supabase.auth.verifyOtp({ type, token_hash });
    if (!error) return NextResponse.redirect(`${origin}/`);
  }
  return NextResponse.redirect(`${origin}/login?error=link`);
}

Limits

What is not here yet

What sign-in and its mail on Tofu do not do.

  • The consent screen shows Tofu’s name. Google shows the verified name of the client it signs in through, so people read “continue to Tofu”. Your own name there needs a Google client of your own, which is not built.

  • Only with a Tofu-managed database. Sign-in is written into the auth service behind your app’s managed database. An app on Clerk, Auth0 or a Supabase project of its own is left exactly as it is.

  • Google and email, nothing else. No GitHub or Apple sign-in for your app’s users.

  • Sign-in mail, not your app’s other mail. Tofu sends the sign-in and sign-up messages; receipts, notifications and anything else your app sends do not go through Tofu.

  • Your own sender needs your own domain. The domain has to be connected to the app first; until it verifies, mail comes from noreply@notify.trytofu.app.

  • The own-domain sender is the newest part. Its records, verification and sender switch have run end to end on Tofu’s own test project, not yet on a customer’s app.

Paste one line. Go live.

Your app, its database, your domain and your sign-in — from the agent you already use, in about 10 minutes.

I want to take my product live with Tofu. Fetch https://app.trytofu.ai/agent/prompt.txt and follow the setup instructions in it, then help me ship this app.
Join Waitlist
Early access · every preview is labelled in your dashboard.