Docs / Authentication / Auth providers
Auth providers
Auth in Keel runs on Better Auth, configured once in lib/auth.ts. Four sign-in methods ship wired up: email/password, magic links, Google, and GitHub. Everything below is toggled by env vars, nothing needs code changes to turn on.
Email and password
Enabled by default (emailAndPassword.enabled in lib/auth.ts). Sign-up and sign-in run through authClient.signUp.email and authClient.signIn.email (see app/auth/sign-in/sign-in-form.tsx). A new sign-up fires a verification email, but verification is not mandatory, emailVerification.requireEmailVerification is left off on purpose so a typo'd address never permanently locks someone out. The link expires after 24 hours, and a welcome email follows once it's clicked.
Sending any of these emails needs RESEND_API_KEY. Without it, the verify/reset/magic-link mails log to the console instead of sending, so local dev works with no email setup.
Magic links
Registered via the magicLink plugin in lib/auth.ts, links expire after 15 minutes. On the sign-in page it's a second tab next to password (authClient.signIn.magicLink), which mails a one-click link and sends the user to /auth/magic-link-sent.
Password reset
authClient.requestPasswordReset({ email, redirectTo }) mails a reset link (app/auth/forgot-password), and authClient.resetPassword({ newPassword, token }) sets the new password (app/auth/reset-password). The request step always reports success even for unknown emails, so it never leaks whether an account exists.
Method names differ from Better Auth's docs
This project's Better Auth version uses authClient.requestPasswordReset, not the forgetPassword name you'll see in older docs and most training data. Check the actual method names in app/auth/** before assuming a client call exists.
OAuth (Google and GitHub)
Both are registered conditionally: a provider only turns on once both of its env vars are set, so a buyer who hasn't created OAuth apps yet can leave them blank and the rest of auth still runs.
- Google:
GOOGLE_CLIENT_ID,GOOGLE_CLIENT_SECRET - GitHub:
GITHUB_CLIENT_ID,GITHUB_CLIENT_SECRET
Register the redirect URI {BETTER_AUTH_URL}/api/auth/callback/google (or /github) with each provider. Also set BETTER_AUTH_SECRET (generate with npx @better-auth/cli secret) and BETTER_AUTH_URL, both are required for any auth flow, not just OAuth.
Social sign-in and sign-up are the same call, authClient.signIn.social({ provider, callbackURL }) creates the account on first use, so there's no separate "sign up with Google" path.
Adding another provider
Better Auth ships many more social providers than Keel exposes buttons for. To add one (GitLab here), extend the socialProviders map in lib/auth.ts the same way Google and GitHub are added:
if (process.env.GITLAB_CLIENT_ID && process.env.GITLAB_CLIENT_SECRET) {
socialProviders.gitlab = {
clientId: process.env.GITLAB_CLIENT_ID,
clientSecret: process.env.GITLAB_CLIENT_SECRET,
};
}
Then add a button to components/auth/oauth-buttons.tsx (extend the OAuthProvider union and the providers array) and register the {BETTER_AUTH_URL}/api/auth/callback/gitlab redirect URI with the provider.