Next.js Examples ​
Complete examples for using Flowfull Clients with Next.js applications (App Router & Pages Router).
Architecture
@pubflow/nextjs- For authentication with Flowless (managed auth service)@pubflow/flowfull-client- For HTTP requests to your custom Flowfull backend
Installation ​
bash
# Install both packages
npm install @pubflow/nextjs @pubflow/flowfull-clientApp Router Setup ​
1. Configure PubflowProvider ​
typescript
// app/providers.tsx
'use client';
import { PubflowProvider } from '@pubflow/nextjs';
export function Providers({ children }: { children: React.ReactNode }) {
return (
<PubflowProvider
config={{
baseUrl: process.env.NEXT_PUBLIC_FLOWLESS_URL || 'https://your-flowless.pubflow.com',
bridgeBasePath: '/bridge',
authBasePath: '/auth'
}}
loginRedirectPath="/login"
publicPaths={['/login', '/register']}
>
{children}
</PubflowProvider>
);
}typescript
// app/layout.tsx
import { Providers } from './providers';
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>
<Providers>{children}</Providers>
</body>
</html>
);
}2. Create Flowfull API Client ​
typescript
// lib/flowfull.ts
import { createFlowfull } from '@pubflow/flowfull-client';
// Create client for your custom backend
export const flowfull = createFlowfull(
process.env.NEXT_PUBLIC_BACKEND_URL || 'https://api.myapp.com',
{
headers: {
'X-Client-Version': '1.0.0'
},
retryAttempts: 3,
timeout: 30000
}
);Authentication with Flowless ​
Login Page ​
typescript
// app/login/page.tsx
'use client';
import { useState } from 'react';
import { useRouter } from 'next/navigation';
import { useAuth } from '@pubflow/nextjs';
export default function LoginPage() {
const router = useRouter();
const { login, isLoading } = useAuth();
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState('');
async function handleSubmit(e: React.FormEvent) {
e.preventDefault();
setError('');
try {
const result = await login({ email, password });
if (result.success) {
router.push('/dashboard');
} else {
setError(result.error || 'Login failed');
}
} catch (err) {
setError('An error occurred');
}
}
return (
<div className="login-page">
<h1>Login</h1>
<form onSubmit={handleSubmit}>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value.toLowerCase())}
placeholder="Email"
required
/>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="Password"
required
/>
<button type="submit" disabled={isLoading}>
{isLoading ? 'Logging in...' : 'Login'}
</button>
{error && <div className="error">{error}</div>}
</form>
</div>
);
}Dashboard Page ​
typescript
// app/dashboard/page.tsx
'use client';
import { useAuth } from '@pubflow/nextjs';
import { useRouter } from 'next/navigation';
export default function DashboardPage() {
const { user, isAuthenticated, logout, isLoading } = useAuth();
const router = useRouter();
async function handleLogout() {
await logout();
router.push('/login');
}
if (isLoading) {
return <div>Loading...</div>;
}
if (!isAuthenticated) {
router.push('/login');
return null;
}
return (
<div className="dashboard">
<h1>Dashboard</h1>
<div className="user-info">
<p><strong>Name:</strong> {user?.name}</p>
<p><strong>Email:</strong> {user?.email}</p>
<p><strong>User Type:</strong> {user?.userType}</p>
</div>
<button onClick={handleLogout}>Logout</button>
</div>
);
}Protected Page with useAuthGuard ​
typescript
// app/admin/page.tsx
'use client';
import { useAuthGuard } from '@pubflow/nextjs';
import { useRouter } from 'next/navigation';
export default function AdminPage() {
const router = useRouter();
const { user, isLoading } = useAuthGuard({
allowedTypes: ['admin'],
onRedirect: (path, reason) => {
if (reason === 'unauthorized') {
alert('Admin access required');
}
router.push(path);
}
});
if (isLoading) {
return <div>Loading...</div>;
}
return (
<div>
<h1>Admin Panel</h1>
<p>Welcome, Admin {user?.name}!</p>
</div>
);
}Data Fetching from Custom Backend ​
Use @pubflow/flowfull-client to fetch data from your custom Flowfull backend:
User List Page ​
typescript
// app/users/page.tsx
'use client';
import { useState, useEffect } from 'react';
import { flowfull } from '@/lib/flowfull';
interface User {
id: string;
name: string;
email: string;
role: string;
}
export default function UsersPage() {
const [users, setUsers] = useState<User[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState('');
useEffect(() => {
fetchUsers();
}, []);
async function fetchUsers() {
try {
const data = await flowfull.get<User[]>('/users');
setUsers(data);
} catch (err: any) {
setError(err.message || 'Failed to fetch users');
} finally {
setLoading(false);
}
}
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error}</div>;
return (
<div>
<h1>Users</h1>
<ul>
{users.map(user => (
<li key={user.id}>
<strong>{user.name}</strong> - {user.email} ({user.role})
</li>
))}
</ul>
</div>
);
}Pages Router Setup ​
Configure _app.tsx ​
typescript
// pages/_app.tsx
import type { AppProps } from 'next/app';
import { PubflowProvider } from '@pubflow/nextjs';
export default function App({ Component, pageProps }: AppProps) {
return (
<PubflowProvider
config={{
baseUrl: process.env.NEXT_PUBLIC_FLOWLESS_URL || 'https://your-flowless.pubflow.com',
bridgeBasePath: '/bridge',
authBasePath: '/auth'
}}
loginRedirectPath="/login"
publicPaths={['/login', '/register']}
>
<Component {...pageProps} />
</PubflowProvider>
);
}Login Page (Pages Router) ​
typescript
// pages/login.tsx
import { useState } from 'react';
import { useRouter } from 'next/router';
import { useAuth } from '@pubflow/nextjs';
export default function LoginPage() {
const router = useRouter();
const { login, isLoading } = useAuth();
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState('');
async function handleSubmit(e: React.FormEvent) {
e.preventDefault();
setError('');
try {
const result = await login({ email, password });
if (result.success) {
router.push('/dashboard');
} else {
setError(result.error || 'Login failed');
}
} catch (err) {
setError('An error occurred');
}
}
return (
<div>
<h1>Login</h1>
<form onSubmit={handleSubmit}>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value.toLowerCase())}
placeholder="Email"
required
/>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="Password"
required
/>
<button type="submit" disabled={isLoading}>
{isLoading ? 'Logging in...' : 'Login'}
</button>
{error && <div>{error}</div>}
</form>
</div>
);
}Next Steps ​
- Next.js Package - Full API reference
- Authentication Guide - Learn more about authentication
- Making API Calls - Advanced API patterns