#Auth
Email/password authentication for your deployed app. Sessions are stored in an httpOnly cookie and managed by server helpers; the client gets a small useUser() hook.
Deploy required. Auth needs
CODUCK_AUTH_KEY, which CoDuck only injects when the project is deployed. Sign-in will not work in the in-editor preview — deploy first.
#Server helpers
@coduck/sdk/server wraps the cookie + session handling for Next.js (App Router). Use it in route handlers and server actions.
import {
getSession,
signInWithPassword,
signUpWithPassword,
signOut,
} from '@coduck/sdk/server';import {
getSession,
signInWithPassword,
signUpWithPassword,
signOut,
} from '@coduck/sdk/server';| Function | Returns | Notes |
|---|---|---|
getSession() | { user } | null | Reads + verifies the session cookie |
signUpWithPassword(email, password, name?) | AuthSession | Creates the user and sets the cookie |
signInWithPassword(email, password) | AuthSession | Logs in and sets the cookie |
signOut() | void | Clears the cookie + invalidates the refresh token |
#Sign in (server action)
'use server';
import { signInWithPassword } from '@coduck/sdk/server';
import { redirect } from 'next/navigation';
export async function login(formData: FormData) {
await signInWithPassword(
String(formData.get('email')),
String(formData.get('password')),
);
redirect('/dashboard');
}'use server';
import { signInWithPassword } from '@coduck/sdk/server';
import { redirect } from 'next/navigation';
export async function login(formData: FormData) {
await signInWithPassword(
String(formData.get('email')),
String(formData.get('password')),
);
redirect('/dashboard');
}#Protect a server component
import { getSession } from '@coduck/sdk/server';
import { redirect } from 'next/navigation';
export default async function Dashboard() {
const session = await getSession();
if (!session) redirect('/login');
return <p>Welcome, {session.user.email}</p>;
}import { getSession } from '@coduck/sdk/server';
import { redirect } from 'next/navigation';
export default async function Dashboard() {
const session = await getSession();
if (!session) redirect('/login');
return <p>Welcome, {session.user.email}</p>;
}#The /api/me route
The client hook reads the session from your own app via GET /api/me. Expose it with the server helper so the browser never touches the cookie directly:
// app/api/me/route.ts
import { getSession } from '@coduck/sdk/server';
export async function GET() {
const session = await getSession();
return Response.json(session ?? { user: null });
}// app/api/me/route.ts
import { getSession } from '@coduck/sdk/server';
export async function GET() {
const session = await getSession();
return Response.json(session ?? { user: null });
}#Client hook
@coduck/sdk/client gives you the current user in a client component. It fetches /api/me (above).
'use client';
import { useUser } from '@coduck/sdk/client';
export function UserBadge() {
const { user, loading, refresh } = useUser(); // useUser('/api/me') by default
if (loading) return null;
if (!user) return <a href="/login">Sign in</a>;
return <span>{user.email}</span>;
}'use client';
import { useUser } from '@coduck/sdk/client';
export function UserBadge() {
const { user, loading, refresh } = useUser(); // useUser('/api/me') by default
if (loading) return null;
if (!user) return <a href="/login">Sign in</a>;
return <span>{user.email}</span>;
}useUser() returns { user: AuthUser | null, loading: boolean, refresh: () => Promise<void> }.
#Low-level client
For full control over tokens (custom flows, non-cookie clients), @coduck/sdk/auth exposes the raw client:
import { auth } from '@coduck/sdk/auth';
const session = await auth.login({ email, password });
// → { user, accessToken, refreshToken, expiresIn }
const user = await auth.me(session.accessToken);
const renewed = await auth.refresh(session.refreshToken);
await auth.logout(session.accessToken);import { auth } from '@coduck/sdk/auth';
const session = await auth.login({ email, password });
// → { user, accessToken, refreshToken, expiresIn }
const user = await auth.me(session.accessToken);
const renewed = await auth.refresh(session.refreshToken);
await auth.logout(session.accessToken);| Method | Returns |
|---|---|
signup({ email, password, name? }) | AuthSession |
login({ email, password }) | AuthSession |
refresh(refreshToken) | AuthSession |
verify(accessToken) | AuthUser |
me(accessToken) | AuthUser |
logout(accessToken) | void |
#Types
interface AuthUser {
id: string;
email: string;
name?: string | null;
createdAt: string;
}
interface AuthSession {
user: AuthUser;
accessToken: string;
refreshToken: string;
expiresIn: number; // seconds until the access token expires
}interface AuthUser {
id: string;
email: string;
name?: string | null;
createdAt: string;
}
interface AuthSession {
user: AuthUser;
accessToken: string;
refreshToken: string;
expiresIn: number; // seconds until the access token expires
}