Claude Code Boilerplate
FeaturesPricingBlogDocs
Get started →

Product

  • Features
  • Pricing
  • Skills

Compare

  • vs ShipFast
  • vs MakerKit
  • vs supastarter

Resources

  • Docs
  • Blog
  • Discord

Legal

  • License
  • Privacy Policy
  • Terms of Service
Claude Code Boilerplate

© 2026 Claude Code Boilerplate. All rights reserved.

← All posts

Social Login in Your Next.js SaaS -- Add Google and GitHub Sign-In Without Auth0

October 17, 2026
nextjsauthsaasoauthboilerplate

Most visitors who land on a signup form have a simple question before they fill it out: do I really need another password?

The answer they want is no. Social login -- sign in with Google, sign in with GitHub -- removes that friction. Fewer fields, no password to forget, and trust borrowed from a brand they already use. Conversion research consistently shows it lifts signup rates by 20-40% for consumer-facing products.

Yet most Next.js tutorials stop at email and password. If you built your auth with JWT and bcrypt, adding OAuth can feel like a separate project. This post explains the tradeoff and the practical path forward.

Auth0 or Clerk vs. rolling your own

Three realistic options exist when you want social login:

Managed auth (Auth0, Clerk). They handle OAuth providers for you. Fast to start, but $25-100 per month once you grow past their free tier -- and your users live in their database, not yours. Every migration later is painful.

DIY OAuth from scratch. You control everything. You also write everything: PKCE flows, token exchange, provider-specific quirks, refresh token rotation. That is a week of work with a lot of ways to get security wrong.

A boilerplate with OAuth built into the existing auth pattern. The Next.js SaaS Boilerplate ships with JWT-based auth you own outright. Social login slots into the same service layer -- no third-party auth service, no migration cost, no recurring seat fee.

If you need to move in an afternoon and are happy to pay ongoing fees, a hosted solution is fine for early users. If you want to own your auth stack as you scale, the boilerplate path costs you one setup session and nothing after that.

What OAuth actually does (in plain language)

When a user clicks "Sign in with Google", they are redirected to Google, which asks them to confirm they want to share their name and email with your app. Google then sends your app a short-lived authorization code. Your server exchanges that code for the user's profile in one more request.

Your job is to take the email from Google's response and either:

  1. Find an existing account with that email and issue your own JWT, or
  2. Create a new account and issue a JWT

You do not store a Google access token long-term. You do not depend on Google's session management. Your auth layer stays the same JWT system you already have -- you just added a new way to identify a user.

The two tables you need

To support social login cleanly, store provider information separately from the user record:

users         -- id, email, name, avatar_url, created_at
oauth_accounts -- id, user_id, provider, provider_account_id, created_at

This lets one user have multiple sign-in methods: Google and GitHub, both linked to the same account. It is also the pattern that prevents the classic duplicate-account bug -- when a user signed up with their Google email address before OAuth existed, then tries Google later and your app creates a second account for them.

The boilerplate's database layer gives you Drizzle ORM and Neon DB. Adding two tables and a relation is one db:generate away.

The three cases your callback must handle

The most confusing part of OAuth is that a single callback endpoint handles both first-time signups and returning logins. Your callback route needs to get all three cases right:

  • New user, new email -- create a user row and an oauth_accounts row, issue JWT
  • Returning user, known provider -- look up oauth_accounts, issue JWT
  • Returning user, known email, new provider -- link to the existing user, create a new oauth_accounts row

Case three is where most implementations break. A user signs up with email and password, then tries Google six months later with the same address. Without the lookup-by-email fallback, your app creates a duplicate account and the user has two separate histories.

The authentication docs show how the boilerplate structures the auth service layer so all three cases live in one place and stay testable.

Which providers to add first

Two providers are worth supporting at launch:

  • Google -- almost every user has an account, and the "Sign in with Google" button is the most-recognized trust signal in the world
  • GitHub -- developers expect it; if your product serves technical users, its absence is noticeable

Each provider needs three things:

  1. An OAuth app registered in their developer console (Google Cloud Console for Google, GitHub Settings for GitHub)
  2. A callback URL pointing to your domain: https://yourdomain.com/api/auth/callback/google
  3. A client ID and client secret stored as environment variables

The names follow the same pattern as the rest of the boilerplate stack. Add them alongside JWT_SECRET and DATABASE_URL. No new config files.

Why this is worth shipping before you launch

The signup form is the highest-friction moment in your funnel. A visitor who clicks your call to action is already interested -- anything that shortens the next step is worth doing early.

Password reset, email verification, and 2FA all matter, but they affect users who have already signed up. Social login affects whether they sign up at all.

The password reset flow and magic link auth posts on this blog cover what comes after signup. This is the piece that gets you there.

Get started

The Next.js SaaS Boilerplate ships with JWT auth, Drizzle ORM, and a service-layer architecture that makes adding OAuth a clean extension rather than a retrofit. Register your OAuth apps in Google Cloud and GitHub, add two environment variables, and ship social login before your next deploy.