Switch Language
Toggle Theme

Complete Guide to OAuth Login in Next.js: Configuring Google, GitHub, and WeChat Authentication

Click “Sign in with Google,” the page redirects to Google, you authorize, it redirects back, and boom—you’re logged in.

You’ve experienced this countless times. But when you try to add third-party login to your own project, suddenly you’re lost: Why two redirects? What’s a callback URL? What the heck is redirect_uri_mismatch? Works locally but breaks in production?

To be honest, I felt the same way when I first configured OAuth. Stared at documentation full of terms like “authorization code,” “access_token,” “client_secret”—got more confused the more I read. Took me two days and countless mistakes to barely figure it out.

In this article, I want to explain OAuth login in the simplest way possible. No jargon overload, no abstract theory—just how it actually works and how to configure Google, GitHub, and WeChat login in Next.js. You’ll realize it’s not that complicated after all.

What Is OAuth 2.0? (In Plain English)

Start with a Real-Life Example

Imagine you live in a gated community. One day you order something online and want the delivery person to bring it to your door. Problem: there’s a security gate, and the delivery person can’t get in.

Traditional approach? Give the delivery person your access card. But that’s risky—what if they use your card to enter anytime they want later?

Smarter approach: You go to the security guard and say “I have a delivery coming.” The guard gives the delivery person a temporary pass that says “Valid only 2-4pm today, access to Building A only.” After the delivery, the pass expires.

That’s the core idea behind OAuth.

In this analogy:

  • You = The user (the person logging in)
  • Delivery person = Third-party app (your website)
  • Security guard = OAuth provider (Google, WeChat, GitHub, etc.)
  • Access card = Your password (can’t share it)
  • Temporary pass = access_token (time-limited, permission-restricted)

You don’t give your password to the third-party app—you just authorize it to get a “temporary pass” from the OAuth provider.

The 5-Step OAuth Flow (Authorization Code Grant)

Now let’s see how this applies to Next.js OAuth login.

Step 1: User clicks “Sign in with Google” on your website.

Step 2: Your website redirects the user to Google’s authorization page with a URL like this:

https://accounts.google.com/o/oauth2/auth?
  client_id=YourAppID
  &redirect_uri=http://localhost:3000/api/auth/callback/google
  &response_type=code
  &scope=openid email profile
  &state=RandomString

At this step, your website is telling Google: “Hey, I’m App XYZ (client_id), the user wants to log in using your account. Please ask them to confirm. When done, send them back to this address (redirect_uri).”

Step 3: User sees “App XYZ wants to access your basic info” on Google’s page and clicks “Allow.”

Step 4: Google redirects the user back to your website (redirect_uri) with an authorization code in the URL:

http://localhost:3000/api/auth/callback/google?code=ABCD1234&state=RandomString

Note: This code is just a voucher, not the final pass. It has a short expiration (usually 10 minutes) and can only be used once.

Step 5: Your website’s backend takes this code, along with your client_secret (password), and exchanges it for the real access_token from Google:

// Backend code (simplified)
const response = await fetch('https://oauth2.googleapis.com/token', {
  method: 'POST',
  body: JSON.stringify({
    code: 'ABCD1234',
    client_id: 'YourAppID',
    client_secret: 'YourAppPassword',
    redirect_uri: 'http://localhost:3000/api/auth/callback/google',
    grant_type: 'authorization_code',
  }),
})

const { access_token } = await response.json()

With the access_token, your website can now fetch user info (email, avatar, name, etc.) from Google.

Step 6 (optional): Use access_token to get user info:

const userInfo = await fetch('https://www.googleapis.com/oauth2/v2/userinfo', {
  headers: {
    Authorization: `Bearer ${access_token}`,
  },
})

Once this flow completes, your website knows “who this user is” and can create a session to keep them logged in.

Key Concepts Explained (In Human Terms)

Still a bit confused about the terminology? Let me break it down:

  • client_id: Your app’s “ID number” at Google. It’s public—no harm if others see it.

  • client_secret: Your app’s “password.” Must never be leaked—only use it on the backend. If someone gets your client_secret, they can impersonate your app and access user data.

  • redirect_uri: Where Google sends the user after authorization. This URL must be pre-registered in Google Cloud Console. Google strictly validates it—even an extra slash will cause a redirect_uri_mismatch error (yeah, that frustrating one).

  • state: A random string to prevent CSRF attacks. You generate this state when initiating authorization, and Google returns it unchanged. You verify the returned state matches what you sent—if not, the request might be forged.

  • code: Temporary authorization code. Short-lived (around 10 minutes), single-use. Its purpose is to prove “the user has granted authorization at Google.”

  • access_token: The actual “pass.” With it, your website can access user info on behalf of the user. Access tokens also have expiration, usually 1 hour to a few days.

Why Split Into code and access_token?

You might wonder: Why not return access_token directly instead of using a code first?

It’s about security. The code is passed through browser redirects (visible to the frontend), while access_token is exchanged server-to-server (hidden from frontend). If access_token were directly in the URL, browser history, logs, and network monitoring could leak it. Exchanging code for token requires client_secret, which only exists on the backend—much more secure.

Setting Up Google Login with Next.js + NextAuth.js (Easiest Start)

Why Choose NextAuth.js?

Implementing OAuth manually is tedious: handling callbacks, managing sessions, preventing CSRF attacks, storing tokens… lots of details.

Good news: there’s a library called NextAuth.js (now Auth.js v5) that does exactly this. It has 15k+ stars on GitHub, active community, supports 50+ OAuth providers (Google, GitHub, WeChat, Twitter, etc.) out of the box. The latest version supports Next.js 14+ App Router and is easier to configure than before.

Simply put, NextAuth.js saves you 80% of the repetitive work.

Step 1: Create App in Google Cloud

Before writing code, you need to “register” your app with Google to get client_id and client_secret.

  1. Open Google Cloud Console and log in with your Google account.

  2. If you haven’t used it before, create a Project first. Name it anything, like “My Next.js App.”

  3. In the left menu, go to “APIs & Services” → “Credentials.”

  4. Click “Create Credentials” → select “OAuth client ID.”

  5. If it’s your first time, you’ll be asked to configure the “OAuth consent screen.” Fill in app name and support email, skip the rest for now (choose “External” user type, no review needed for testing).

  6. Back to creating OAuth client ID, choose application type “Web application.”

  7. Here’s the key part: Configure “Authorized redirect URIs.” Add two addresses:

    • Local development: http://localhost:3000/api/auth/callback/google
    • Production (add after deployment): https://yourdomain.com/api/auth/callback/google

    Note: This address must exactly match what’s in your code. One extra or missing slash triggers redirect_uri_mismatch. I made this mistake when starting out.

  8. Click “Create,” and a dialog shows your Client ID and Client Secret. Copy these values—you’ll need them soon.

Step 2: Install NextAuth.js and Configure Environment Variables

In your Next.js project, install the package:

npm install next-auth@beta

Note: Install the @beta version—this is v5 (the latest).

Then create .env.local file in project root and add the Client ID and Secret you just got:

GOOGLE_CLIENT_ID=YourClientID.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=YourClientSecret
NEXTAUTH_SECRET=GenerateARandomString
NEXTAUTH_URL=http://localhost:3000

Generate NEXTAUTH_SECRET with this command:

openssl rand -base64 32

When deploying to production, remember to change NEXTAUTH_URL to your domain.

Step 3: Create NextAuth Configuration File

Create file at app/api/auth/[...nextauth]/route.ts (if using Pages Router, path is pages/api/auth/[...nextauth].ts):

import NextAuth from "next-auth"
import GoogleProvider from "next-auth/providers/google"

export const authOptions = {
  providers: [
    GoogleProvider({
      clientId: process.env.GOOGLE_CLIENT_ID!,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
    }),
  ],
  callbacks: {
    async signIn({ user, account, profile }) {
      // Callback on successful login, save user info to database here
      console.log("User logged in:", user)
      return true // Return true to allow login
    },
    async session({ session, token }) {
      // Customize session content
      if (session.user) {
        session.user.id = token.sub // Add user id to session
      }
      return session
    },
  },
}

const handler = NextAuth(authOptions)
export { handler as GET, handler as POST }

That’s it—NextAuth.js automatically handles the entire OAuth flow. The /api/auth/callback/google route is auto-generated, no extra code needed.

Step 4: Create Login Button

In any component, you can write a login button like this:

'use client' // App Router requires client component notation

import { signIn, signOut, useSession } from "next-auth/react"

export default function LoginButton() {
  const { data: session } = useSession()

  if (session) {
    // User is logged in
    return (
      <div>
        <p>Welcome, {session.user?.name}</p>
        <img src={session.user?.image || ''} alt="Avatar" />
        <button onClick={() => signOut()}>Sign Out</button>
      </div>
    )
  }

  // User is not logged in
  return <button onClick={() => signIn('google')}>Sign in with Google</button>
}

signIn('google') automatically redirects to Google’s authorization page, and after authorization, redirects back to log the user in. Super easy.

Step 5: Wrap Root Layout with SessionProvider

To make useSession available in all components, wrap a Provider in the root layout:

// app/layout.tsx
import { SessionProvider } from "next-auth/react"

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html>
      <body>
        <SessionProvider>{children}</SessionProvider>
      </body>
    </html>
  )
}

Done! Now you have a Next.js app with Google login.

Troubleshooting Common Issues

Issue 1: redirect_uri_mismatch

This is the most common error—I encountered it my first time too.

Error message looks like: Error 400: redirect_uri_mismatch

Cause: The callback address configured in Google Cloud Console doesn’t match the actual request.

Solution:

  1. Check if “Authorized redirect URIs” in Google Cloud Console is http://localhost:3000/api/auth/callback/google (watch for extra slashes)
  2. Check if NEXTAUTH_URL in your .env.local is http://localhost:3000
  3. If you changed the port (e.g., 3001), update both places

Issue 2: Works Locally but Fails After Deployment

I’ve made this mistake too. Local testing works perfectly, but after deploying to Vercel, clicking login does nothing or errors out.

Cause: Forgot to update production environment variables.

Solution:

  1. In Google Cloud Console’s “Authorized redirect URIs,” add production domain: https://yourdomain.com/api/auth/callback/google
  2. In Vercel (or your hosting platform) environment variables settings, change NEXTAUTH_URL to https://yourdomain.com
  3. Redeploy

Issue 3: Session Is null After Login

If useSession() always returns null for session, check if you forgot to wrap <SessionProvider> in the root layout.

Issue 4: TypeError: Cannot read property ‘user’ of null

Usually because the session is still loading when you try to access session.user.

Solution: Check if session exists first:

const { data: session, status } = useSession()

if (status === 'loading') {
  return <div>Loading...</div>
}

if (!session) {
  return <div>Not logged in</div>
}

// Safe to access session.user here

Configuring GitHub Login (Understanding the Differences)

With Google login experience, configuring GitHub login is easier. But GitHub and Google have some differences worth discussing.

Differences Between GitHub and Google OAuth

Similarities: Both use standard OAuth 2.0 authorization code flow—the process is identical.

Differences:

  1. Finer permission control: GitHub’s scope (permission range) is more complex. By default, you only get public info. To get user email (especially private email), you need to request user:email permission separately.
  2. More flexible callback URL configuration: Google requires the full callback URL, GitHub only needs the domain.
  3. Application types: GitHub supports both personal and organization OAuth Apps.

Step 1: Create OAuth App on GitHub

  1. Log into GitHub, click profile avatar → Settings → find “Developer settings” in left menu.

  2. Click “OAuth Apps” → “New OAuth App.”

  3. Fill in application info:

    • Application name: Your app name (users will see this during authorization)
    • Homepage URL: Your website homepage, like http://localhost:3000
    • Authorization callback URL: Enter http://localhost:3000/api/auth/callback/github
  4. Click “Register application,” then click “Generate a new client secret,” and copy the Client ID and Client Secret.

Step 2: Configure Environment Variables

Add GitHub configuration to .env.local:

GITHUB_CLIENT_ID=YourGitHubClientID
GITHUB_CLIENT_SECRET=YourGitHubClientSecret

Step 3: Update NextAuth Configuration

In the previous route.ts file, add GitHubProvider:

import NextAuth from "next-auth"
import GoogleProvider from "next-auth/providers/google"
import GitHubProvider from "next-auth/providers/github"

export const authOptions = {
  providers: [
    GoogleProvider({
      clientId: process.env.GOOGLE_CLIENT_ID!,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
    }),
    GitHubProvider({
      clientId: process.env.GITHUB_CLIENT_ID!,
      clientSecret: process.env.GITHUB_CLIENT_SECRET!,
      // To get user's private email, add this configuration
      authorization: {
        params: {
          scope: 'read:user user:email'
        }
      }
    }),
  ],
  callbacks: {
    // ... previous callbacks
  },
}

const handler = NextAuth(authOptions)
export { handler as GET, handler as POST }

Step 4: Update Login Button

Add GitHub login option to the login button component:

return (
  <div>
    <button onClick={() => signIn('google')}>Sign in with Google</button>
    <button onClick={() => signIn('github')}>Sign in with GitHub</button>
  </div>
)

That’s it—done!

About scope (Permission Range)

GitHub’s scope controls what user info your app can access. Common ones:

  • read:user: Read user’s public and private info (name, avatar, bio, etc.)
  • user:email: Read user’s email (including private email)
  • public_repo: Access user’s public repositories
  • repo: Access all user repositories (public + private, powerful permission, use carefully)

For login scenarios, read:user user:email is sufficient.

If you don’t include user:email scope, NextAuth.js can only get the user’s public email. If the user hid their email in GitHub settings, session.user.email will be null. I was confused about this for a while, thinking I had a code bug.

A Small Gotcha: GitHub Users May Not Have Public Email

Unlike Google (which requires email), GitHub users can choose not to make their email public. If your app requires user email (e.g., for notifications), check in the signIn callback:

async signIn({ user, account }) {
  if (account?.provider === 'github' && !user.email) {
    // User didn't provide email, can reject login or prompt user
    console.log("GitHub user didn't provide email")
    return false // Reject login
  }
  return true
}

Configuring WeChat Login (Special Case in China)

Now let’s talk about WeChat login. To be honest, WeChat login is more complex than Google and GitHub, mainly because its ecosystem is quite different from international platforms.

Why Is WeChat Login Special?

First, key differences:

  1. Requires QR code scanning: For PC website WeChat login, users need to take out their phone and scan a QR code to authorize (unlike Google/GitHub where you just click on the webpage).
  2. No official NextAuth.js Provider: NextAuth.js doesn’t have built-in WeChat provider—you have to write a custom one.
  3. More callback URL restrictions: WeChat requires callback domains to be registered with authorities, can’t use localhost, making local development tricky.
  4. Has openid and unionid: WeChat’s user identifier is special—same user has different openid in different apps. If you have multiple apps and want to share user data, you need unionid.

Step 1: Register on WeChat Open Platform

  1. Open WeChat Open Platform and register an account.

  2. Create a “Website Application” (not Official Account or Mini Program).

  3. Fill in website info, upload screenshots, wait for review. Review usually takes 1-3 business days.

  4. After approval, you’ll get AppID and AppSecret (equivalent to client_id and client_secret).

  5. In “Development Info,” configure authorization callback domain (only enter domain name, no full path needed, e.g., yourdomain.com).

Step 2: Custom WeChat Provider

Since NextAuth.js doesn’t have built-in WeChat provider, we need to write our own. Create lib/wechat-provider.ts in your project:

import type { OAuthConfig, OAuthUserConfig } from "next-auth/providers"

export interface WeChatProfile {
  openid: string
  nickname: string
  headimgurl: string
  sex: number
  province: string
  city: string
  country: string
  unionid?: string
}

export default function WeChatProvider<P extends WeChatProfile>(
  options: OAuthUserConfig<P>
): OAuthConfig<P> {
  return {
    id: "wechat",
    name: "WeChat",
    type: "oauth",
    
    // WeChat authorization URL (for PC website apps)
    authorization: {
      url: "https://open.weixin.qq.com/connect/qrconnect",
      params: {
        scope: "snsapi_login",
        appid: options.clientId,
        response_type: "code",
      },
    },
    
    // URL to exchange authorization code for access_token
    token: {
      url: "https://api.weixin.qq.com/sns/oauth2/access_token",
      params: {
        appid: options.clientId,
        secret: options.clientSecret,
        grant_type: "authorization_code",
      },
    },
    
    // URL to get user info
    userinfo: {
      url: "https://api.weixin.qq.com/sns/userinfo",
      async request({ tokens, provider }) {
        const res = await fetch(
          `${provider.userinfo?.url}?access_token=${tokens.access_token}&openid=${tokens.openid}&lang=zh_CN`
        )
        return await res.json()
      },
    },
    
    // Convert WeChat user info to NextAuth standard format
    profile(profile) {
      return {
        id: profile.openid,
        name: profile.nickname,
        email: null, // WeChat doesn't provide email
        image: profile.headimgurl,
      }
    },
    
    options,
  }
}

Step 3: Configure Environment Variables

Add WeChat configuration to .env.local:

WECHAT_CLIENT_ID=YourWeChatAppID
WECHAT_CLIENT_SECRET=YourWeChatAppSecret

Step 4: Use in NextAuth

Update route.ts:

import WeChatProvider from "@/lib/wechat-provider"

export const authOptions = {
  providers: [
    GoogleProvider({...}),
    GitHubProvider({...}),
    WeChatProvider({
      clientId: process.env.WECHAT_CLIENT_ID!,
      clientSecret: process.env.WECHAT_CLIENT_SECRET!,
    }),
  ],
}

Step 5: How to Test Locally?

This is a pain point. Since WeChat doesn’t allow localhost as callback domain, you can’t test directly in local development.

Two solutions:

Solution 1: Use Tunneling Tool

Use ngrok or cpolar to expose your local service to the public internet:

# Install ngrok
brew install ngrok

# Start tunnel
ngrok http 3000

ngrok gives you a temporary domain like https://abc123.ngrok.io. Add this domain to WeChat Open Platform’s authorization callback domain, then update NEXTAUTH_URL in .env.local:

NEXTAUTH_URL=https://abc123.ngrok.io

Solution 2: Configure hosts File

Add a line to local hosts file (Mac/Linux: /etc/hosts, Windows: C:\Windows\System32\drivers\etc\hosts):

127.0.0.1 dev.yourdomain.com

Then access http://dev.yourdomain.com:3000 and configure callback domain in WeChat Open Platform as dev.yourdomain.com.

But there’s a problem: WeChat requires callback domains to be registered with authorities, so dev.yourdomain.com still won’t work. Solution 1 is more reliable.

Special Handling for WeChat Login

WeChat users don’t have email. If your app depends on email, handle it accordingly:

async signIn({ user, account }) {
  if (account?.provider === 'wechat') {
    // WeChat user has no email, can ask user to fill it in
    // or use openid as unique identifier in database
    console.log("WeChat user openid:", user.id)
  }
  return true
}

Security Best Practices (Avoiding Common Pitfalls)

After configuring OAuth login, there are security details to watch out for. I’ve made these mistakes—learned the hard way.

1. client_secret Must Never Be Leaked

Wrong approach:

// ❌ Never do this!
const clientSecret = "abc123def456" // Hardcoded in code

If you put client_secret in frontend code or commit it to Git, anyone who gets it can impersonate your app to access user data.

Right approach:

  • Store in environment variables, add .env.local to .gitignore
  • Only use client_secret on backend (NextAuth.js API routes are backend, so that’s fine)
  • Use platform’s environment variable management for deployment (Vercel’s Settings → Environment Variables)

2. Purpose of state Parameter (Prevent CSRF Attacks)

OAuth flow has a state parameter to prevent CSRF attacks.

Attack scenario: Hacker constructs a malicious link with a forged authorization code and tricks you into clicking it. If your app doesn’t verify state, it might be fooled into using the fake code to exchange for token.

Good news: NextAuth.js automatically handles state verification—no extra code needed.

If you implement OAuth yourself (without NextAuth.js), remember to:

  1. Generate a random state when initiating authorization, save it to session or cookie
  2. Check if the returned state matches what you sent during callback
  3. Reject if they don’t match

3. Callback URL Whitelist

In OAuth provider (Google, GitHub, WeChat) backends, configure all possible callback addresses:

  • Development: http://localhost:3000/api/auth/callback/[provider]
  • Preview: https://preview.yourdomain.com/api/auth/callback/[provider]
  • Production: https://yourdomain.com/api/auth/callback/[provider]

Don’t use wildcards (like https://*.yourdomain.com)—while convenient, it’s insecure. Explicitly list all domains to prevent exploitation by attackers.

4. Token Storage Security

NextAuth.js uses JWT by default to store sessions, with tokens saved in HttpOnly Cookies. This is excellent design:

  • HttpOnly: Frontend JavaScript can’t read this cookie, preventing XSS attacks from stealing tokens
  • Secure (production): Only transmitted via HTTPS, preventing man-in-the-middle attacks

What you need to do:

  • Don’t return access_token to frontend (NextAuth.js doesn’t return it by default, don’t manually return it either)
  • If you need to persist user info, save to database in signIn callback, only store necessary info in session (user id, email)

5. Authorization Code Expiration

OAuth authorization codes have short expiration (10 minutes) and single-use only.

This is a security design: Even if a hacker intercepts your code, by the time they react and try to use it, the code might be expired or already used by you.

If users stay on the authorization page too long (e.g., went to make coffee), the code might expire when they return. NextAuth.js automatically handles this scenario and re-initiates authorization.

6. Production Environment Checklist

Before deployment, check these configurations:

  • Are all environment variables set (NEXTAUTH_URL, NEXTAUTH_SECRET, client_id and client_secret for each provider)?
  • Is NEXTAUTH_URL changed to production domain (not localhost)?
  • Are production callback addresses configured in OAuth provider backends?
  • Is .env.local in .gitignore (ensuring secrets aren’t committed to Git)?
  • Is production NEXTAUTH_SECRET randomly generated (not using development one)?

Conclusion

Let’s quickly recap everything.

The essence of OAuth is really just a “temporary pass”: You don’t give your password to third-party apps—you just authorize them to get a time-limited, permission-restricted pass (access_token) from the OAuth provider. The flow has two steps: first use authorization code to prove user consent, then exchange code + client_secret for the actual token.

For configuring third-party login in Next.js, Google is easiest—best choice for beginners; GitHub is slightly more complex—need to pay attention to scope configuration and users may not have public email; WeChat is most special—requires QR scanning, custom provider, domain registration with authorities, and local testing is tricky.

For security, remember three principles:

  1. Only use client_secret on backend—never leak it
  2. Always verify state parameter (NextAuth.js does this for you)
  3. Use callback URL whitelist—no wildcards

If this is your first time configuring OAuth, I suggest starting with Google login and following the code in this article step by step. The sense of achievement when it works is pretty awesome.

Don’t panic when you hit issues—90% of errors are due to incorrect redirect_uri configuration or missing environment variables. Double-check and you’ll usually solve it.

Finally, I recommend checking out NextAuth.js official docs for more advanced features (database session storage, custom login pages, JWT configuration, etc.). The OAuth 2.0 standard specification (RFC 6749) is also worth reading. Once you understand the principles, troubleshooting becomes much easier.

Give it a try—good luck with your configuration!

FAQ

How does OAuth 2.0 work?
OAuth 2.0 allows users to authorize third-party apps to access their resources without providing passwords.

Flow:
1. User clicks login → redirects to OAuth provider
2. User authorizes → returns authorization code
3. Exchange code + client_secret for access_token
4. Use token to get user information
How do I fix redirect_uri_mismatch error?
This error means the callback URL doesn't match.

Solutions:
1) Ensure the callback URL in OAuth provider backend exactly matches the code (including protocol, domain, port, path)
2) Use http://localhost:3000 for local development, actual domain for production
3) Check for extra slashes or parameters
What's the difference between NextAuth.js and manual OAuth implementation?
NextAuth.js:
• Pre-packaged OAuth solution
• Supports 50+ providers
• Automatically handles authorization flow, session management, CSRF protection

Manual implementation:
• Need to handle authorization code exchange, token storage, state validation yourself
• Large codebase and error-prone

Recommendation: Use NextAuth.js.
How do I get user email addresses?
Different providers handle emails differently:
• Google: Returns email by default
• GitHub: Need user:email in scope, and user must set email as public
• WeChat: Need to query via unionid

If unavailable, let users manually fill in after login.
Works locally but breaks in production?
Usually a callback URL configuration issue.

Check:
1) Is NEXTAUTH_URL correct in production?
2) Does OAuth provider backend callback URL include production domain?
3) Are environment variables set correctly?
4) Are there firewall or proxy issues?
Can I support multiple login methods simultaneously?
Yes. NextAuth.js supports configuring multiple providers, users can choose Google, GitHub, WeChat, etc.

Specify the provider name in the signIn() function.
Is OAuth login secure?
OAuth 2.0 is an industry standard and relatively secure.

But note:
1) client_secret must be kept secret, only use on server side
2) Use state parameter to prevent CSRF attacks (NextAuth.js handles automatically)
3) Use whitelist for callback URLs, don't use wildcards
4) Regularly update dependencies

15 min read · Published on: Dec 19, 2025 · Modified on: Jan 22, 2026

Comments

Sign in with GitHub to leave a comment

Related Posts