Add CloudBase Authentication to Next.js
In one sentence: Use
@cloudbase/js-sdkin a Next.js 14+ App Router project to integrate SMS Verification Code / WeChat Open Platform QR Login, store login state in anhttpOnlycookie, read identity in Server Components viacookies(), perform lightweight validation in middleware running on Edge Runtime, and run heavy business logic in Route Handlers withruntime: 'nodejs'.Estimated time: 35 minutes | Difficulty: Advanced
Applicable Scenarios
- Applicable: Next.js 14 / 15 App Router full-stack applications where SSR pages need user identity for personalized rendering
- Applicable: React SPAs already using add-auth-web-with-cloudbase-sdk that want to migrate to Next.js for SSR + middleware interception
- Applicable: Using middleware for unauthenticated request interception / canary routing / A-B splits
- Not applicable: Pure Pages Router projects — go directly to the add-auth-web-with-cloudbase-sdk SPA template. Pages Router does not have the concept of Server Components or Server Actions
- Not applicable: Obtaining admin-level login state on the Node.js side (that requires server tokens from
@cloudbase/node-sdk, which is outside the scope of this recipe)
Prerequisites
| Dependency | Version |
|---|---|
| Node.js | ≥ 18.18.0 |
next | 14.2.x or 15.x |
@cloudbase/js-sdk | 3.3.x (latest) or @cloudbase/js-sdk@v2, i.e. 2.27.x |
react / react-dom | ^18.3.0 (Next.js 15 uses ^19.0.0) |
External dependencies:
- An active CloudBase environment ID, region set to Shanghai (SMS Verification Code login is only supported in the Shanghai region)
- In Console → Authentication → Login Methods, enable the methods you want:
- "SMS Verification Code Login"
- "WeChat Open Platform Login" — enter the AppID and AppSecret from a website application registered on WeChat Open Platform
Next.js 15 changed cookies() / headers() / params / searchParams to all be async — they must be await-ed before use. Next.js 14 keeps the synchronous API. This recipe is written for Next.js 15; for Next.js 14 simply replace await cookies() with cookies().
Step 1: Install @cloudbase/js-sdk in Your Next.js Project
npx create-next-app@latest my-cloudbase-app --typescript --app --tailwind=false --eslint --src-dir=false --import-alias="@/*"
cd my-cloudbase-app
npm i @cloudbase/js-sdk
Create lib/cloudbase.ts (client-only; the SDK uses crypto / localStorage):
'use client';
import cloudbase from '@cloudbase/js-sdk';
export const app = cloudbase.init({
env: 'your-env-id',
// Omitting region defaults to Shanghai; SMS login is only supported in Shanghai
});
export const auth = app.auth({ persistence: 'local' });
Step 2: Write the Login Page as a Client Component (SMS + WeChat QR)
app/login/page.tsx (marked 'use client' because it uses the SDK):
'use client';
import { useState } from 'react';
import { useRouter } from 'next/navigation';
import { auth } from '@/lib/cloudbase';
import { setSessionCookie } from './actions';
export default function LoginPage() {
const router = useRouter();
const [phone, setPhone] = useState('');
const [code, setCode] = useState('');
const [verificationInfo, setVerificationInfo] = useState<any>(null);
const [countdown, setCountdown] = useState(0);
const [err, setErr] = useState('');
const sendCode = async () => {
setErr('');
if (!/^\+86\s?\d{11}$/.test(phone)) {
setErr('Phone number format should be +86 13800000000');
return;
}
try {
const info = await auth.getVerification({ phone_number: phone });
setVerificationInfo(info);
setCountdown(60);
const t = setInterval(() => {
setCountdown((c) => {
if (c <= 1) { clearInterval(t); return 0; }
return c - 1;
});
}, 1000);
} catch (e: any) {
setErr(e.message || 'Failed to send');
}
};
const submit = async (e: React.FormEvent) => {
e.preventDefault();
setErr('');
try {
await auth.signInWithSms({
verificationInfo,
verificationCode: code,
phoneNum: phone,
});
// Login successful — write access token to httpOnly cookie
const loginState = await auth.getLoginState();
if (!loginState) throw new Error('Login state is empty');
await setSessionCookie(loginState.accessToken);
router.push('/');
} catch (e: any) {
setErr(e.message || 'Login failed');
}
};
return (
<form onSubmit={submit}>
<input
placeholder="+86 13800000000"
value={phone}
onChange={(e) => setPhone(e.target.value)}
/>
<button type="button" onClick={sendCode} disabled={countdown > 0}>
{countdown > 0 ? `Resend in ${countdown}s` : 'Get verification code'}
</button>
<input
placeholder="6-digit code"
value={code}
onChange={(e) => setCode(e.target.value)}
/>
<button type="submit">Login</button>
{err && <div style={{ color: 'red' }}>{err}</div>}
</form>
);
}
Key points:
auth.signInWithSmsfollows the two-step flowgetVerification→signInWithSms;verificationInfois the object returned bygetVerificationand must be passed back as-is- After a successful client-side login, the
accessTokenis written to anhttpOnlycookie via the Server ActionsetSessionCookie, making it accessible to Server Components and middleware - WeChat QR Login uses an OAuth redirect flow. The process is the same as in add-auth-web-with-cloudbase-sdk Step 5; in Next.js simply swap the callback page for
app/login/wechat-callback/page.tsx— the logic is unchanged
Step 3: Store Login State in an httpOnly Cookie (Server Action)
app/login/actions.ts (marked 'use server'):
'use server';
import { cookies } from 'next/headers';
export async function setSessionCookie(accessToken: string) {
const cookieStore = await cookies();
cookieStore.set('cloudbase_session', accessToken, {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'lax',
path: '/',
maxAge: 60 * 60 * 24 * 30, // 30 days, aligned with SDK persistence: 'local'
});
}
export async function clearSessionCookie() {
const cookieStore = await cookies();
cookieStore.delete('cloudbase_session');
}
Key points:
httpOnly: trueprevents JavaScript from reading the cookie, protecting the token from XSSsameSite: 'lax'is the recommended default; do not use'strict'— cross-site redirects (e.g. WeChat QR callback) will not send the cookiesecure: trueis required in production; useprocess.env.NODE_ENV === 'production'so that local HTTP development still works- Server Components cannot directly
set/deletecookies — they can only read. Write operations must be placed in a Server Action or Route Handler