Complete Example
Install Dependencies
Install logto-authkit and required dependencies:
npm install @ouim/logto-authkit @logto/react
Create Root Layout
Set up the auth provider in your root layout:
app/layout.tsx
import { AuthProvider } from '@ouim/logto-authkit'
import './globals.css'
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>
<AuthProvider
config={{
endpoint: process.env.NEXT_PUBLIC_LOGTO_ENDPOINT!,
appId: process.env.NEXT_PUBLIC_LOGTO_APP_ID!,
resources: [process.env.NEXT_PUBLIC_API_RESOURCE!],
scopes: ['openid', 'profile', 'email'],
}}
callbackUrl={`${process.env.NEXT_PUBLIC_APP_URL}/callback`}
enablePopupSignIn={true}
>
{children}
</AuthProvider>
</body>
</html>
)
}
Create Home Page
Build your landing page with authentication:
app/page.tsx
'use client'
import { useAuth, UserCenter } from '@ouim/logto-authkit'
import Link from 'next/link'
export default function Home() {
const { user, isLoadingUser, signIn } = useAuth()
return (
<div className="min-h-screen bg-gradient-to-b from-gray-50 to-gray-100">
<nav className="bg-white shadow-sm">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex justify-between h-16">
<div className="flex items-center">
<Link href="/" className="text-xl font-bold text-gray-900">
logto-authkit App
</Link>
</div>
<div className="flex items-center gap-4">
{user && (
<Link
href="/dashboard"
className="text-gray-700 hover:text-gray-900"
>
Dashboard
</Link>
)}
<UserCenter />
</div>
</div>
</div>
</nav>
<main className="max-w-7xl mx-auto py-16 px-4 sm:px-6 lg:px-8">
<div className="text-center">
<h1 className="text-5xl font-bold text-gray-900 mb-6">
Welcome to logto-authkit
</h1>
<p className="text-xl text-gray-600 mb-8 max-w-2xl mx-auto">
A simplified authentication solution for Next.js applications.
Get started with secure, production-ready auth in minutes.
</p>
{isLoadingUser ? (
<div className="flex justify-center">
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600"></div>
</div>
) : user ? (
<div className="space-y-4">
<div className="bg-white rounded-lg shadow-md p-6 max-w-md mx-auto">
<p className="text-lg font-semibold text-gray-900 mb-2">
Welcome back, {user.name || user.email}!
</p>
<p className="text-gray-600">
You are successfully authenticated.
</p>
</div>
<Link
href="/dashboard"
className="inline-block bg-blue-600 text-white px-8 py-3 rounded-lg hover:bg-blue-700 font-semibold"
>
Go to Dashboard
</Link>
</div>
) : (
<div className="space-y-4">
<button
onClick={() => signIn()}
className="bg-blue-600 text-white px-8 py-3 rounded-lg hover:bg-blue-700 font-semibold"
>
Sign In
</button>
<p className="text-sm text-gray-500">
Sign in to access your personalized dashboard
</p>
</div>
)}
</div>
</main>
</div>
)
}
Create Protected Dashboard
Build a dashboard with automatic authentication protection:
app/dashboard/page.tsx
'use client'
import { useAuth, UserCenter } from '@ouim/logto-authkit'
import Link from 'next/link'
export default function Dashboard() {
const { user, isLoadingUser } = useAuth({
middleware: 'auth',
redirectTo: '/signin',
})
if (isLoadingUser) {
return (
<div className="flex items-center justify-center min-h-screen">
<div className="animate-spin rounded-full h-16 w-16 border-b-2 border-blue-600"></div>
</div>
)
}
return (
<div className="min-h-screen bg-gray-50">
<nav className="bg-white shadow-sm">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex justify-between h-16">
<div className="flex items-center">
<Link href="/" className="text-xl font-bold text-gray-900">
logto-authkit App
</Link>
</div>
<div className="flex items-center">
<UserCenter />
</div>
</div>
</div>
</nav>
<main className="max-w-7xl mx-auto py-8 px-4 sm:px-6 lg:px-8">
<div className="mb-8">
<h1 className="text-3xl font-bold text-gray-900">Dashboard</h1>
<p className="text-gray-600 mt-2">Welcome to your protected dashboard</p>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div className="bg-white rounded-lg shadow p-6">
<h2 className="text-xl font-semibold mb-4 text-gray-900">
User Profile
</h2>
<dl className="space-y-3">
<div>
<dt className="text-sm font-medium text-gray-500">User ID</dt>
<dd className="mt-1 text-sm text-gray-900 font-mono">{user?.id}</dd>
</div>
<div>
<dt className="text-sm font-medium text-gray-500">Name</dt>
<dd className="mt-1 text-sm text-gray-900">
{user?.name || 'Not provided'}
</dd>
</div>
<div>
<dt className="text-sm font-medium text-gray-500">Email</dt>
<dd className="mt-1 text-sm text-gray-900">
{user?.email || 'Not provided'}
</dd>
</div>
</dl>
</div>
<div className="bg-white rounded-lg shadow p-6">
<h2 className="text-xl font-semibold mb-4 text-gray-900">
Authentication Status
</h2>
<div className="space-y-3">
<div className="flex items-center">
<div className="w-3 h-3 bg-green-500 rounded-full mr-3"></div>
<span className="text-sm text-gray-900">Authenticated</span>
</div>
<p className="text-sm text-gray-600">
You have successfully authenticated and can access protected
resources.
</p>
<Link
href="/api/user"
target="_blank"
className="inline-block text-sm text-blue-600 hover:text-blue-800"
>
View API Response →
</Link>
</div>
</div>
</div>
</main>
</div>
)
}
Create API Route with Server-Side Auth
Add a protected API route using server-side authentication:
app/api/user/route.ts
import { NextRequest, NextResponse } from 'next/server'
import { verifyNextAuth } from '@ouim/logto-authkit/server'
export async function GET(request: NextRequest) {
const result = await verifyNextAuth(request, {
logtoUrl: process.env.LOGTO_ENDPOINT!,
audience: process.env.LOGTO_API_RESOURCE!,
})
if (!result.success) {
return NextResponse.json(
{ error: result.error },
{ status: 401 }
)
}
// Access authenticated user info
const { auth } = result
return NextResponse.json({
userId: auth.userId,
isAuthenticated: auth.isAuthenticated,
payload: auth.payload,
})
}
Add Authentication Pages
Create the required callback and sign-in pages:
'use client'
import { CallbackPage } from '@ouim/logto-authkit'
export default function Callback() {
return (
<CallbackPage
onSuccess={() => {
console.log('Authentication successful')
}}
onError={(error) => {
console.error('Authentication failed:', error)
}}
/>
)
}
Configure Environment Variables
Create a
.env.local file with your Logto configuration:.env.local
NEXT_PUBLIC_LOGTO_ENDPOINT=https://your-tenant.logto.app
NEXT_PUBLIC_LOGTO_APP_ID=your-app-id
NEXT_PUBLIC_API_RESOURCE=https://api.yourapp.com
NEXT_PUBLIC_APP_URL=http://localhost:3000
# Server-side variables
LOGTO_ENDPOINT=https://your-tenant.logto.app
LOGTO_API_RESOURCE=https://api.yourapp.com
Server-Side Authentication
logto-authkit supports server-side authentication for API routes and middleware:- API Routes
- Middleware
app/api/protected/route.ts
import { NextRequest, NextResponse } from 'next/server'
import { verifyNextAuth } from '@ouim/logto-authkit/server'
export async function GET(request: NextRequest) {
const result = await verifyNextAuth(request, {
logtoUrl: process.env.LOGTO_ENDPOINT!,
audience: process.env.LOGTO_API_RESOURCE!,
})
if (!result.success) {
return NextResponse.json(
{ error: 'Unauthorized' },
{ status: 401 }
)
}
return NextResponse.json({
message: 'Protected data',
userId: result.auth.userId,
})
}
middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
import { verifyNextAuth } from '@ouim/logto-authkit/server'
export async function middleware(request: NextRequest) {
// Only protect API routes
if (request.nextUrl.pathname.startsWith('/api/protected')) {
const result = await verifyNextAuth(request, {
logtoUrl: process.env.LOGTO_ENDPOINT!,
audience: process.env.LOGTO_API_RESOURCE!,
})
if (!result.success) {
return NextResponse.json(
{ error: 'Unauthorized' },
{ status: 401 }
)
}
}
return NextResponse.next()
}
export const config = {
matcher: '/api/protected/:path*',
}
Features Demonstrated
- Next.js App Router: Full integration with App Router
- Client-Side Auth: Protected pages with automatic redirects
- Server-Side Auth: Secure API routes with JWT verification
- Environment Variables: Proper configuration management
- Popup Sign-In: Optional popup-based authentication
- User Center: Pre-built UI component for user management
Running the Example
npm run dev
http://localhost:3000 to see your Next.js app with authentication.
Next Steps
Protected Routes
Advanced route protection patterns
Server Integration
Learn more about server-side auth