Integrate Bondify Auth in Next.js with Server Actions
Add Telegram authentication to Next.js 14+ using Bondify’s React SDK and Server Actions. Covers App Router, cookies, and proof verification.
Bondify integrates naturally with the Next.js App Router. The client-side @bondify/react package drives the Telegram auth flow in a 'use client' component, and a Server Action handles proof verification, session cookie creation, and the final redirect — all without a separate API route. This approach keeps your secret key on the server, enables streaming and React Server Components in the rest of your app, and gives you a single file for the entire login flow.
Add both variables to .env.local. Only the project ID should be prefixed with NEXT_PUBLIC_ — that prefix is what Next.js uses to decide whether a variable is safe to bundle into the client.
BONDIFY_SECRET_KEY must never carry the NEXT_PUBLIC_ prefix. Any variable prefixed with NEXT_PUBLIC_ is inlined into the browser bundle at build time and becomes publicly readable. Your secret key must stay server-only.
The Server Action verifies the proof cryptographically, writes an httpOnly session cookie, and redirects to the dashboard. Because this runs on the server, the secret key is never exposed to the browser.
app/login/actions.ts
'use server';import { verifyProof } from '@bondify/server';import { cookies } from 'next/headers';import { redirect } from 'next/navigation';export async function createSession(proof: string) { const user = await verifyProof(proof, process.env.BONDIFY_SECRET_KEY!); // user.telegramId — the user's Telegram ID (string) // user.name — display name from Telegram // user.username — Telegram @handle (may be null) (await cookies()).set('user_id', user.telegramId, { httpOnly: true, secure: process.env.NODE_ENV === 'production', sameSite: 'lax', maxAge: 60 * 60 * 24 * 7, // 7 days }); redirect('/dashboard');}
verifyProof throws if the proof is invalid, tampered with, or expired. Always let that exception propagate (or catch it and return an error to the client) — never fall through and create a session with an unverified proof.
Add an async layout to any route group you want to protect. It reads the session cookie and redirects unauthenticated visitors to /login before rendering any children.
app/dashboard/layout.tsx
import { cookies } from 'next/headers';import { redirect } from 'next/navigation';export default async function DashboardLayout({ children,}: { children: React.ReactNode;}) { const userId = (await cookies()).get('user_id')?.value; if (!userId) redirect('/login'); return <>{children}</>;}
For more advanced session handling — such as storing structured user data or rotating tokens — replace the plain user_id cookie with a signed JWT. The jose or jsonwebtoken package works well server-side in Next.js.
Create a Server Action that clears the session cookie and redirects to /login:
app/dashboard/actions.ts
'use server';import { cookies } from 'next/headers';import { redirect } from 'next/navigation';export async function signOut() { (await cookies()).delete('user_id'); redirect('/login');}
Then call it from a Client Component button:
app/dashboard/SignOutButton.tsx
'use client';import { signOut } from './actions';export default function SignOutButton() { return ( <form action={signOut}> <button type="submit">Sign out</button> </form> );}