Skip to main content

Next.js Social Login

Social login (also called social sign-in or social authentication) allows users to authenticate using their existing accounts from platforms like Google, GitHub, Facebook, or Twitter. This provides a streamlined user experience by eliminating the need to create and remember another username and password.

In this tutorial, we'll learn how to implement social login in a Next.js application using NextAuth.js, a complete authentication solution for Next.js apps.

Why Use Social Login?

Before we dive into the implementation, let's understand the benefits:

  • Improved User Experience: Users don't need to fill out registration forms or remember additional passwords
  • Higher Conversion Rates: Reduces friction during signup, potentially leading to more registered users
  • Enhanced Security: Leverages security measures already implemented by major platforms
  • Access to User Data: With user permission, you can access profile data from social providers

Prerequisites

To follow along with this tutorial, you'll need:

  • Basic knowledge of Next.js and React
  • Node.js installed on your system
  • A Next.js project set up (version 13+ recommended)

Setting Up NextAuth.js

NextAuth.js is the most popular authentication library for Next.js. Let's start by installing it:

npm install next-auth
# or
yarn add next-auth

Creating API Route for Authentication

For Next.js 13+ with App Router:

  1. Create a new file at app/api/auth/[...nextauth]/route.js:
import NextAuth from 'next-auth';
import GoogleProvider from 'next-auth/providers/google';
import GitHubProvider from 'next-auth/providers/github';

const handler = NextAuth({
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
}),
GitHubProvider({
clientId: process.env.GITHUB_ID,
clientSecret: process.env.GITHUB_SECRET,
}),
],
// Additional configuration options
pages: {
signIn: '/auth/signin', // Custom sign-in page (optional)
},
callbacks: {
async session({ session, token }) {
// Send properties to the client
session.user.id = token.sub;
return session;
},
},
});

export { handler as GET, handler as POST };

For Next.js with Pages Router:

// pages/api/auth/[...nextauth].js
import NextAuth from 'next-auth';
import GoogleProvider from 'next-auth/providers/google';
import GitHubProvider from 'next-auth/providers/github';

export default NextAuth({
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
}),
GitHubProvider({
clientId: process.env.GITHUB_ID,
clientSecret: process.env.GITHUB_SECRET,
}),
],
// Additional configuration options
});

Environment Variables

Create a .env.local file in the root of your project to store your credentials:

NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=your_nextauth_secret

# Google Provider
GOOGLE_CLIENT_ID=your_google_client_id
GOOGLE_CLIENT_SECRET=your_google_client_secret

# GitHub Provider
GITHUB_ID=your_github_client_id
GITHUB_SECRET=your_github_client_secret

The NEXTAUTH_SECRET is used to encrypt cookies and tokens. You can generate a secure random string using:

openssl rand -base64 32

Obtaining OAuth Credentials

To implement social login, you need to register your application with the providers you want to support. Let's go through the process for the most common ones:

Google OAuth Setup

  1. Go to the Google Cloud Console
  2. Create a new project or select an existing one
  3. Navigate to "APIs & Services" > "Credentials"
  4. Click "Create Credentials" and select "OAuth client ID"
  5. Configure the consent screen if prompted
  6. Select "Web application" as the application type
  7. Add your application's domain to "Authorized JavaScript origins"
  8. Add your redirect URL (typically http://localhost:3000/api/auth/callback/google for development)
  9. Copy the Client ID and Client Secret to your environment variables

GitHub OAuth Setup

  1. Go to GitHub Developer Settings
  2. Click "New OAuth App"
  3. Fill in the application name and homepage URL
  4. Set the authorization callback URL to http://localhost:3000/api/auth/callback/github
  5. Click "Register application"
  6. Copy the Client ID and generate a Client Secret
  7. Add them to your environment variables

Creating a Sign-In Component

Now let's create a component to handle user authentication:

// components/SignInButtons.jsx
"use client"; // If using the App Router

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

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

if (session && session.user) {
return (
<div className="flex flex-col items-center gap-4">
<p>Signed in as {session.user.email}</p>
<img
src={session.user.image}
alt={session.user.name}
className="rounded-full w-12 h-12"
/>
<button
className="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded"
onClick={() => signOut()}
>
Sign out
</button>
</div>
);
}

return (
<div className="flex flex-col gap-4">
<button
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded flex items-center gap-2"
onClick={() => signIn('google')}
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
{/* Google icon SVG */}
<path fill="#FFFFFF" d="M12.545,10.239v3.821h5.445c-0.712,2.315-2.647,3.972-5.445,3.972c-3.332,0-6.033-2.701-6.033-6.032 s2.701-6.032,6.033-6.032c1.498,0,2.866,0.549,3.921,1.453l2.814-2.814C17.503,2.988,15.139,2,12.545,2 C7.021,2,2.543,6.477,2.543,12s4.478,10,10.002,10c8.396,0,10.249-7.85,9.426-11.748L12.545,10.239z"/>
</svg>
Sign in with Google
</button>

<button
className="bg-gray-800 hover:bg-gray-900 text-white font-bold py-2 px-4 rounded flex items-center gap-2"
onClick={() => signIn('github')}
>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
{/* GitHub icon SVG */}
<path fill="#FFFFFF" d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
</svg>
Sign in with GitHub
</button>
</div>
);
}

Setting Up NextAuth Provider

For NextAuth to work properly, you need to wrap your application with a session provider. For Next.js App Router projects:

// app/providers.jsx
"use client";

import { SessionProvider } from "next-auth/react";

export function Providers({ children }) {
return <SessionProvider>{children}</SessionProvider>;
}

Then use it in your root layout:

// app/layout.jsx
import { Providers } from "./providers";

export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
<Providers>{children}</Providers>
</body>
</html>
);
}

For Pages Router:

// pages/_app.js
import { SessionProvider } from "next-auth/react";

export default function App({ Component, pageProps: { session, ...pageProps } }) {
return (
<SessionProvider session={session}>
<Component {...pageProps} />
</SessionProvider>
);
}

Building a Login Page

Let's create a simple login page using our sign-in component:

// app/login/page.jsx (App Router)
import SignInButtons from '@/components/SignInButtons';

export default function LoginPage() {
return (
<div className="min-h-screen flex items-center justify-center bg-gray-50 py-12 px-4 sm:px-6 lg:px-8">
<div className="max-w-md w-full space-y-8">
<div>
<h2 className="mt-6 text-center text-3xl font-extrabold text-gray-900">
Sign in to your account
</h2>
<p className="mt-2 text-center text-sm text-gray-600">
Or continue with your social accounts
</p>
</div>
<div className="mt-8 space-y-6">
<SignInButtons />
</div>
</div>
</div>
);
}

Protecting Routes

Now let's create a protected route that only authenticated users can access:

// app/dashboard/page.jsx (App Router)
"use client";

import { useSession } from "next-auth/react";
import { redirect } from "next/navigation";

export default function Dashboard() {
const { data: session, status } = useSession();

if (status === "loading") {
return <p>Loading...</p>;
}

if (status === "unauthenticated") {
redirect("/login");
return null;
}

return (
<div className="p-8">
<h1 className="text-2xl font-bold">Dashboard</h1>
<p>Welcome {session.user.name}!</p>
<div className="mt-4">
<h2 className="text-xl">Your Profile Information:</h2>
<pre className="bg-gray-100 p-4 mt-2 rounded">
{JSON.stringify(session, null, 2)}
</pre>
</div>
</div>
);
}

For server components in App Router, you can use the getServerSession function:

// app/profile/page.jsx
import { getServerSession } from "next-auth/next";
import { redirect } from "next/navigation";
import { options } from "../api/auth/[...nextauth]/route";

export default async function ProfilePage() {
const session = await getServerSession(options);

if (!session) {
redirect("/login");
}

return (
<div className="p-8">
<h1 className="text-2xl font-bold">Profile</h1>
<p>Welcome {session.user.name}!</p>
{/* Profile content */}
</div>
);
}

Adding Facebook Login

Let's extend our solution by adding Facebook as a login provider:

  1. First, register your app on Facebook Developers
  2. Add the provider to your NextAuth configuration:
// app/api/auth/[...nextauth]/route.js or pages/api/auth/[...nextauth].js
import FacebookProvider from "next-auth/providers/facebook";

// Add this to your providers array
FacebookProvider({
clientId: process.env.FACEBOOK_CLIENT_ID,
clientSecret: process.env.FACEBOOK_CLIENT_SECRET,
}),
  1. Add the environment variables:
FACEBOOK_CLIENT_ID=your_facebook_client_id
FACEBOOK_CLIENT_SECRET=your_facebook_client_secret
  1. Add a Facebook sign-in button to your component:
<button
className="bg-blue-800 hover:bg-blue-900 text-white font-bold py-2 px-4 rounded flex items-center gap-2"
onClick={() => signIn('facebook')}
>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
{/* Facebook icon SVG */}
<path fill="#FFFFFF" d="M22.675 0h-21.35c-.732 0-1.325.593-1.325 1.325v21.351c0 .731.593 1.324 1.325 1.324h11.495v-9.294h-3.128v-3.622h3.128v-2.671c0-3.1 1.893-4.788 4.659-4.788 1.325 0 2.463.099 2.795.143v3.24l-1.918.001c-1.504 0-1.795.715-1.795 1.763v2.313h3.587l-.467 3.622h-3.12v9.293h6.116c.73 0 1.323-.593 1.323-1.325v-21.35c0-.732-.593-1.325-1.325-1.325z"/>
</svg>
Sign in with Facebook
</button>

Handling Callbacks and Custom Logic

NextAuth.js provides several callbacks to customize the authentication process. Here's an example of storing user data in a database when they sign in:

// app/api/auth/[...nextauth]/route.js
import NextAuth from 'next-auth';
import { PrismaAdapter } from '@auth/prisma-adapter';
import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient();

export const options = {
adapter: PrismaAdapter(prisma),
providers: [
// Your providers here
],
callbacks: {
async signIn({ user, account, profile }) {
// Do something when a user signs in
return true;
},
async session({ session, token, user }) {
// Send additional properties to the client
session.user.id = user.id;
return session;
},
async jwt({ token, user, account, profile }) {
// Add custom properties to the JWT
if (user) {
token.userId = user.id;
}
return token;
},
},
events: {
async createUser({ user }) {
// Do something when a new user is created
console.log("New user created:", user.email);
},
},
};

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

Error Handling

To handle authentication errors gracefully:

// components/SignInButtons.jsx
"use client";

import { useState } from 'react';
import { signIn } from 'next-auth/react';

export function SignInButton({ provider, children, className }) {
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(null);

const handleSignIn = async () => {
try {
setIsLoading(true);
setError(null);

const result = await signIn(provider, {
redirect: false,
callbackUrl: '/dashboard'
});

if (result?.error) {
setError(`Authentication failed: ${result.error}`);
}
} catch (err) {
setError(`Sign in error: ${err.message}`);
} finally {
setIsLoading(false);
}
};

return (
<>
<button
className={`${className} ${isLoading ? 'opacity-70 cursor-not-allowed' : ''}`}
onClick={handleSignIn}
disabled={isLoading}
>
{isLoading ? 'Signing in...' : children}
</button>
{error && <p className="text-red-500 text-sm mt-2">{error}</p>}
</>
);
}

Production Considerations

Before deploying to production:

  1. Update Environment Variables: Ensure all environment variables are set in your production environment
  2. Update Callback URLs: Update authorized redirect URIs in your OAuth provider settings
  3. Set NEXTAUTH_URL: Point to your production domain
  4. Generate Strong Secret: Use a strong, unique secret for NEXTAUTH_SECRET
  5. Configure Database: For production, consider using a database adapter for session persistence
  6. Add CSRF Protection: NextAuth.js has built-in CSRF protection, but ensure it's properly configured

Summary

In this tutorial, we've learned how to:

  • Set up NextAuth.js in a Next.js application
  • Configure OAuth providers (Google, GitHub, Facebook)
  • Create user-friendly sign-in buttons
  • Protect routes and access user session data
  • Handle authentication errors
  • Extend NextAuth with callbacks and custom logic

Social login provides a streamlined authentication experience for your users while reducing the burden of account management. With NextAuth.js, implementing these features in a Next.js application becomes straightforward and secure.

Additional Resources

Exercises

  1. Add Twitter as an additional social login provider
  2. Create a custom sign-in page with a unified design
  3. Implement role-based access control based on the social provider used
  4. Store additional user information in a database when they sign in
  5. Create a user profile page that displays information from their social account


If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)