1.1.4 Google OAuth provider — Better-Auth config, auto-link semantics
Estimate: 15m · Depends on: 1.1.2, 1.1.3
Add Google OAuth as a peer sign-in method to the Better-Auth instance configured in 1.1.2. Wires the provider's config block, the OAuth callback handler (Better-Auth mounts it automatically once the provider is registered), and the auto-link semantics so that a Google sign-in with an email matching an existing password account links into the same User row. No UI work in this subtask — the "Continue with Google" button on the sign-in/sign-up pages lands in 1.1.5, which depends on this.
Why auto-link, not require-verification: Decided in Story-1.1 planning conversation (recorded in MOTIR.md). Same email → same user; both methods work afterward. Lowest-friction UX; the security trade-off (Google-account compromise → full account takeover) is acceptable for v1 because Google already verified the email and most users use Google with 2FA on. If a future Story needs require-verification semantics for compliance reasons, swap the accountLinking Better-Auth option there.
Why env-var-driven with no shipped defaults: Per the planner-as-consumer principle (MOTIR.md "Current state" + notes.html mistake #22), each Motir-planned project owns its own Google Cloud OAuth app. The starters ship GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET as required env vars with no defaults; the planner adds a "Set up Google Cloud OAuth credentials" Story in pre-plan for each project, parallel to the email-provider Story. In dev, missing creds make the Google button render but error visibly when clicked — no silent fallback.
What you'll do: Extend /lib/auth/index.ts (from 1.1.2) to register the Google social provider with clientId / clientSecret read from env, and enable accountLinking with the trustedProviders: ["google"] option so matching emails auto-link. Wire the OAuth callback to use findOrCreateOAuthUser from /lib/users/repo.ts (from 1.1.3). Document GOOGLE_CLIENT_ID + GOOGLE_CLIENT_SECRET in .env.example with a comment explaining where to obtain them (Google Cloud Console → APIs & Services → Credentials → OAuth 2.0 Client ID, web application, authorized redirect URI {BETTER_AUTH_URL}/api/auth/callback/google).
Acceptance criteria
- Better-Auth's Google social provider registered in
/lib/auth/index.ts; readsGOOGLE_CLIENT_ID+GOOGLE_CLIENT_SECRETfrom env. accountLinking.trustedProvidersincludes"google"; auto-link by matching email is enabled.- OAuth callback handler at
/app/api/auth/[...all]/route.ts(mounted by 1.1.2) handles Google's callback round-trip; on success the user is created or linked viafindOrCreateOAuthUserfrom 1.1.3. - OAuth-created users have
passwordHash: nullandemailVerifiedAtset to the OAuth callback time (Google has already verified the email). - If a user already exists with the Google email (created via email/password) and signs in with Google for the first time, a new
OAuthAccountrow is created linking to the existing User; the existingpasswordHashis unchanged; both sign-in methods work afterward. .env.exampledocumentsGOOGLE_CLIENT_ID+GOOGLE_CLIENT_SECRETwith a comment pointing to Google Cloud Console + the redirect URI shape.- Smoke test (manual; full E2E lands in 1.1.7): with valid Google creds in
.env, hitting/api/auth/sign-in/social?provider=googledirectly (no UI) redirects to Google's consent screen, then after consent redirects back, creates a session cookie, and the protected route renders. - Tests: unit test for
findOrCreateOAuthUser's auto-link branch (called above in 1.1.3's AC list — verify here that the OAuth callback actually invokes it correctly via a stubbed Google response).
Context refs
/lib/auth/index.ts— Better-Auth instance from 1.1.2 (to extend)/lib/users/repo.ts— user repository withfindOrCreateOAuthUserfrom 1.1.3/prisma/schema.prisma—OAuthAccountmodel from 1.1.3.env.example— env-var pattern to extend- Better-Auth social-providers docs (fetched at prompt-gen time): Google provider config, account-linking options, callback handler shape
- Google Cloud Console OAuth 2.0 setup docs (URL, fetched at prompt-gen): authorized redirect URIs, OAuth consent screen