Skip to Content
SDKsNext.js

Next.js SDK

Next.js integration with OAuth 2.0 authentication, middleware, and route handlers.

This SDK provides OAuth 2.0 authentication only. For other authentication flows, use the core binoauth SDK directly.

Installation

npm install @binoauth/nextjs

Quick Start

Configure Environment

# .env.local BINOAUTH_ISSUER=https://auth.binoauth.com BINOAUTH_CLIENT_ID=your-client-id BINOAUTH_CLIENT_SECRET=your-client-secret BINOAUTH_REDIRECT_URI=http://localhost:3000/api/auth/callback AUTH_SECRET=your-auth-secret BINOAUTH_SCOPE=openid profile email

Create Auth Instance

// lib/auth.ts import { createAuth } from "@binoauth/nextjs"; export const { handler, withAuth, login, logout, handleCallback, auth, getAccessToken } = createAuth({ // Configuration reads from environment variables // or provide config manually });

Add API Route Handler

// app/api/auth/[...oauth]/route.ts import { handler } from "@/lib/auth"; export const GET = handler; export const POST = handler;

Add Client Components

// app/layout.tsx import { AuthProvider } from '@binoauth/nextjs'; export default function RootLayout({ children, }: { children: React.ReactNode; }) { return ( <html> <body> <AuthProvider> {children} </AuthProvider> </body> </html> ); }

Authentication

Login and Logout

// app/login/page.tsx import { login } from '@/lib/auth'; export default function LoginPage() { return ( <form action={login}> <button type="submit">Login with BinoAuth</button> </form> ); }
// components/LogoutButton.tsx import { logout } from '@/lib/auth'; export function LogoutButton() { return ( <form action={logout}> <button type="submit">Logout</button> </form> ); }

Get Current User

// app/profile/page.tsx import { auth } from '@/lib/auth'; export default async function ProfilePage() { const user = await auth(); if (!user) { return <div>Not authenticated</div>; } return ( <div> <h1>Welcome, {user.name}</h1> <p>Email: {user.email}</p> </div> ); }

Client-Side Authentication

// components/UserProfile.tsx 'use client'; import { useAuth } from '@binoauth/nextjs'; export function UserProfile() { const { user, isLoading, isAuthenticated } = useAuth(); if (isLoading) return <div>Loading...</div>; if (!isAuthenticated) return <div>Not authenticated</div>; return ( <div> <h1>Welcome, {user?.name}</h1> <p>Email: {user?.email}</p> </div> ); }

Route Protection

Server-Side Guards

// app/dashboard/page.tsx import { ServerAuthGuard } from '@binoauth/nextjs'; const DashboardContent = () => ( <div> <h1>Dashboard</h1> <p>Protected content</p> </div> ); export default ServerAuthGuard(DashboardContent);

Client-Side Guards

// components/ProtectedComponent.tsx 'use client'; import { ClientAuthGuard } from '@binoauth/nextjs'; const ProtectedContent = ({ user }) => ( <div> <h1>Protected Content</h1> <p>Welcome, {user.name}</p> </div> ); export default ClientAuthGuard(ProtectedContent);

Middleware

Basic Protection

// middleware.ts import { createWithAuth } from '@binoauth/nextjs'; export default createWithAuth({ // Configuration reads from environment variables }); export const config = { matcher: ['/dashboard/:path*', '/profile/:path*'] };

Custom Middleware

// middleware.ts import { createWithAuth } from '@binoauth/nextjs'; import { NextResponse } from 'next/server'; export default createWithAuth((request) => { // Custom logic here const response = NextResponse.next(); // Add custom headers response.headers.set('X-Custom-Header', 'value'); return response; });

OAuth Callback

Automatic Handling

The SDK automatically handles OAuth callbacks at /api/auth/callback. No additional setup needed.

Custom Callback Handling

// app/api/auth/callback/route.ts import { handleCallback } from '@/lib/auth'; import { NextRequest } from 'next/server'; export async function GET(request: NextRequest) { const { searchParams } = new URL(request.url); const code = searchParams.get('code'); const state = searchParams.get('state'); if (!code || !state) { return Response.json({ error: 'Missing parameters' }, { status: 400 }); } try { await handleCallback({ code, state }); return Response.redirect('/dashboard'); } catch (error) { return Response.redirect('/login?error=callback_failed'); } }

Configuration

Environment Variables

# Required BINOAUTH_ISSUER=https://auth.binoauth.com BINOAUTH_CLIENT_ID=your-client-id BINOAUTH_CLIENT_SECRET=your-client-secret BINOAUTH_REDIRECT_URI=http://localhost:3000/api/auth/callback AUTH_SECRET=your-auth-secret # Optional BINOAUTH_SCOPE=openid profile email

Manual Configuration

import { createAuth } from '@binoauth/nextjs'; export const auth = createAuth({ issuer: 'https://auth.binoauth.com', clientId: 'your-client-id', clientSecret: 'your-client-secret', redirectUri: 'http://localhost:3000/api/auth/callback', authSecret: 'your-auth-secret', scope: 'openid profile email' });

Security Configuration

export const auth = createAuth({ // ... other config security: { allowedDomains: ['yourapp.com'], trustProxyHeaders: true, maxRedirectDepth: 3 } });

Server Actions

Form Actions

// app/login/page.tsx import { login } from '@/lib/auth'; export default function LoginPage() { return ( <form action={login}> <button type="submit">Login</button> </form> ); }

API Actions

// app/api/user/route.ts import { getAccessToken } from '@/lib/auth'; export async function GET() { const token = await getAccessToken(); if (!token) { return Response.json({ error: 'Unauthorized' }, { status: 401 }); } // Use token for API calls return Response.json({ token }); }

TypeScript Support

The SDK is fully typed with TypeScript:

import type { NextAuthConfig, ClientSafeConfig, CreateAuth } from '@binoauth/nextjs'; import type { BinoAuthConfig, User, TokenResponse } from 'binoauth';

Error Handling

// app/error.tsx 'use client'; export default function Error({ error, reset, }: { error: Error & { digest?: string }; reset: () => void; }) { return ( <div> <h2>Authentication Error</h2> <p>{error.message}</p> <button onClick={reset}>Try again</button> </div> ); }

The SDK uses secure cookie storage for tokens:

// Automatic cookie configuration // - httpOnly: true // - secure: true (in production) // - sameSite: 'lax' // - path: '/' // - encrypted with AUTH_SECRET

API Reference

Server Functions

// Authentication login(): Promise<void> logout(returnTo?: string): Promise<void> handleCallback(params: { code: string; state: string }): Promise<void> auth(): Promise<User | null> getAccessToken(): Promise<string | null> // Configuration createAuth(config?: Partial<NextAuthConfig>): CreateAuth readAuthConfigFromEnv(config?: Partial<NextAuthConfig>): NextAuthConfig

Client Components

// Components <AuthProvider> <ClientAuthGuard> <ServerAuthGuard> // Hooks useAuth(): { user: User | null; isLoading: boolean; isAuthenticated: boolean; }

Middleware

// Middleware createWithAuth(config?: Partial<NextAuthConfig>): NextMiddleware createWithAuth( middleware: NextMiddleware, config?: Partial<NextAuthConfig> ): NextMiddleware

Types

interface NextAuthConfig extends BinoAuthConfig { clientSecret: string; authSecret: string; security?: { allowedDomains?: string[]; trustProxyHeaders?: boolean; maxRedirectDepth?: number; }; } interface CreateAuth { handler: RouteHandler; withAuth: MiddlewareFactory; login: ServerAction; logout: ServerAction; handleCallback: ServerAction; auth: ServerAction; getAccessToken: ServerAction; }

Examples

Full App Router Example

// lib/auth.ts import { createAuth } from '@binoauth/nextjs'; export const { handler, withAuth, login, logout, auth, getAccessToken } = createAuth();
// app/api/auth/[...oauth]/route.ts import { handler } from '@/lib/auth'; export const GET = handler; export const POST = handler;
// middleware.ts import { createWithAuth } from '@binoauth/nextjs'; export default createWithAuth(); export const config = { matcher: ['/dashboard/:path*'] };
// app/layout.tsx import { AuthProvider } from '@binoauth/nextjs'; export default function RootLayout({ children, }: { children: React.ReactNode; }) { return ( <html> <body> <AuthProvider> {children} </AuthProvider> </body> </html> ); }
// app/dashboard/page.tsx import { auth } from '@/lib/auth'; import { redirect } from 'next/navigation'; export default async function DashboardPage() { const user = await auth(); if (!user) { redirect('/login'); } return ( <div> <h1>Dashboard</h1> <p>Welcome, {user.name}</p> </div> ); }
Last updated on