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/nextjsQuick 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 emailCreate 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 Router
// 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 emailManual 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>
);
}Cookie Storage
The SDK uses secure cookie storage for tokens:
// Automatic cookie configuration
// - httpOnly: true
// - secure: true (in production)
// - sameSite: 'lax'
// - path: '/'
// - encrypted with AUTH_SECRETAPI 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>): NextAuthConfigClient 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>
): NextMiddlewareTypes
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