CoDuck Docs

#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.

ts
import {
  getSession,
  signInWithPassword,
  signUpWithPassword,
  signOut,
} from '@coduck/sdk/server';
import {
  getSession,
  signInWithPassword,
  signUpWithPassword,
  signOut,
} from '@coduck/sdk/server';
FunctionReturnsNotes
getSession(){ user } | nullReads + verifies the session cookie
signUpWithPassword(email, password, name?)AuthSessionCreates the user and sets the cookie
signInWithPassword(email, password)AuthSessionLogs in and sets the cookie
signOut()voidClears the cookie + invalidates the refresh token

#Sign in (server action)

ts
'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

tsx
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:

ts
// 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).

tsx
'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:

ts
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);
MethodReturns
signup({ email, password, name? })AuthSession
login({ email, password })AuthSession
refresh(refreshToken)AuthSession
verify(accessToken)AuthUser
me(accessToken)AuthUser
logout(accessToken)void

#Types

ts
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
}