Overview
Social authentication (OAuth) integration for Next.js with Convex Auth. Supports:
- GitHub OAuth login
- Google OAuth login
- Protected routes
- User session management
Installation
npx shadcn@latest add https://convex-ui.vercel.app/r/social-auth-nextjs
This installs:
- Social login form component
- Logout button
- Protected route example
- Complete Convex backend with auth
- Convex client and provider
Post-Install Setup
Start Convex Development Server
This creates your deployment and provides the deployment URL. Configure Environment Variables
Add to .env.local:NEXT_PUBLIC_CONVEX_URL=https://your-deployment.convex.cloud
CONVEX_DEPLOYMENT=your-deployment-name
Set Up OAuth Providers
For GitHub:
- Go to GitHub Settings > Developer settings > OAuth Apps
- Create a new OAuth App
- Set Authorization callback URL to:
https://<your-convex-url>/api/auth/callback/github
- Get Client ID and Client Secret
For Google:
- Go to Google Cloud Console
- Create a new project or select existing
- Enable Google+ API
- Create OAuth 2.0 credentials
- Add authorized redirect URI:
https://<your-convex-url>/api/auth/callback/google
- Get Client ID and Client Secret
Add credentials to Convex dashboard (Settings > Environment Variables):AUTH_GITHUB_ID=your-github-client-id
AUTH_GITHUB_SECRET=your-github-client-secret
AUTH_GOOGLE_ID=your-google-client-id
AUTH_GOOGLE_SECRET=your-google-client-secret
At least one OAuth provider must be configured for authentication to work.
Wrap App with Provider
import { ConvexClientProvider } from "@/lib/convex/provider";
export default function RootLayout({ children }) {
return (
<html>
<body>
<ConvexClientProvider>{children}</ConvexClientProvider>
</body>
</html>
);
}
Components
Displays OAuth provider buttons:
import { SocialLoginForm } from "@/components/login-form";
export default function LoginPage() {
return (
<div className="flex min-h-screen items-center justify-center">
<SocialLoginForm />
</div>
);
}
Props:
providers
Provider[]
default:"['github', 'google']"
Array of OAuth providers to display. Supported values: 'github', 'google'
Example with single provider:
<SocialLoginForm providers={["github"]} />
Component Source
The component includes provider-specific icons and handles OAuth flow:
components/login-form.tsx
"use client";
import { useAuthActions } from "@convex-dev/auth/react";
import { Button } from "@/components/ui/button";
import { useState } from "react";
type Provider = "github" | "google";
interface SocialLoginFormProps {
providers?: Provider[];
}
export function SocialLoginForm({
providers = ["github", "google"],
}: SocialLoginFormProps) {
const { signIn } = useAuthActions();
const [error, setError] = useState<string | null>(null);
const [loadingProvider, setLoadingProvider] = useState<Provider | null>(null);
const handleSocialLogin = async (provider: Provider) => {
setError(null);
setLoadingProvider(provider);
try {
await signIn(provider);
} catch (err) {
setError(
err instanceof Error
? err.message
: `Failed to sign in with ${provider}`,
);
setLoadingProvider(null);
}
};
// Render provider buttons...
}
Simple logout functionality:
import { LogoutButton } from "@/components/logout-button";
export function Header() {
return (
<header>
<nav>
<LogoutButton />
</nav>
</header>
);
}
Authentication Flow
User Clicks OAuth Button
User selects GitHub or Google login.
Redirect to Provider
User is redirected to the OAuth provider’s login page.
User Authorizes
User grants permissions to your application.
Callback Processing
Provider redirects back to your Convex callback URL with authorization code.
Session Created
Convex Auth exchanges the code for user information and creates a session.
User Redirected
User is redirected back to your application, now authenticated.
Backend Configuration
Auth is configured in convex/auth.ts:
import { convexAuth } from "@convex-dev/auth/server";
import GitHub from "@auth/core/providers/github";
import Google from "@auth/core/providers/google";
// Build providers list dynamically
const providers: any[] = [];
if (process.env.AUTH_GITHUB_ID && process.env.AUTH_GITHUB_SECRET) {
providers.push(GitHub);
}
if (process.env.AUTH_GOOGLE_ID && process.env.AUTH_GOOGLE_SECRET) {
providers.push(Google);
}
export const { auth, signIn, signOut } = convexAuth({
providers,
});
The system automatically includes only the configured providers.
User Data
After authentication, user data is available via the users.current query:
"use client";
import { useQuery } from "convex/react";
import { api } from "@/convex/_generated/api";
export function UserProfile() {
const user = useQuery(api.users.current);
if (!user) return <div>Not logged in</div>;
return (
<div>
<p>Name: {user.name}</p>
<p>Email: {user.email}</p>
<img src={user.image} alt={user.name} />
</div>
);
}
User object structure:
interface User {
_id: Id<"users">;
name?: string;
email?: string;
image?: string;
emailVerified?: boolean;
}
Protected Routes
Protect routes with authentication checks:
import { redirect } from "next/navigation";
import { fetchQuery } from "@/lib/convex/server";
import { api } from "@/convex/_generated/api";
export default async function ProtectedPage() {
const user = await fetchQuery(api.users.current);
if (!user) {
redirect("/auth/login");
}
return (
<div>
<h1>Welcome, {user.name}!</h1>
<p>This is protected content.</p>
</div>
);
}
Environment Variables
Client (.env.local)
Your Convex deployment URL
Your Convex deployment name
Server (Convex Dashboard)
GitHub OAuth client ID. Required if using GitHub authentication.
GitHub OAuth client secret. Required if using GitHub authentication.
Google OAuth client ID. Required if using Google authentication.
Google OAuth client secret. Required if using Google authentication.
OAuth Callback URLs
Configure these in your OAuth provider dashboards:
GitHub:
https://<your-convex-url>/api/auth/callback/github
Google:
https://<your-convex-url>/api/auth/callback/google
Replace <your-convex-url> with your actual Convex deployment URL (from NEXT_PUBLIC_CONVEX_URL).
Customization
Custom Provider Icons
The component includes built-in SVG icons for GitHub and Google. To customize:
function CustomGitHubIcon({ className }: { className?: string }) {
return (
<svg className={className} viewBox="0 0 24 24">
{/* Your custom icon */}
</svg>
);
}
Styling
The component uses shadcn/ui components. Customize via your theme:
<SocialLoginForm className="max-w-sm" />