diff --git a/package.json b/package.json
index 0d7e9b0..c749490 100644
--- a/package.json
+++ b/package.json
@@ -63,6 +63,9 @@
"./features/auth/client": {
"import": "./dist/features/auth/AuthPage.client.js"
},
+ "./features/auth/pages": {
+ "import": "./dist/features/auth/pages/index.js"
+ },
"./features/admin": {
"import": "./dist/features/admin/index.js"
},
diff --git a/src/features/auth/GUIDE-custom-login.md b/src/features/auth/GUIDE-custom-login.md
new file mode 100644
index 0000000..3f54d10
--- /dev/null
+++ b/src/features/auth/GUIDE-custom-login.md
@@ -0,0 +1,102 @@
+# Pages d'authentification personnalisées
+
+Pour utiliser sa propre mise en page, on crée des routes Next.js qui enveloppent les composants Zen dans un layout.
+
+Chaque page suit le même patron : un **composant serveur** qui charge la session et passe les actions, et un **wrapper client** qui gère la navigation.
+
+- Composants : `@zen/core/features/auth/pages`
+- Actions : `@zen/core/features/auth/actions`
+
+---
+
+## Composants disponibles
+
+| Page | Composant | Props principales |
+|-----------------------|------------------------|-------------------|
+| Connexion | `LoginPage` | `onSubmit`, `onSetSessionCookie`, `onNavigate`, `redirectAfterLogin`, `currentUser` |
+| Inscription | `RegisterPage` | `onSubmit`, `onNavigate`, `currentUser` |
+| Mot de passe oublié | `ForgotPasswordPage` | `onSubmit`, `onNavigate`, `currentUser` |
+| Réinitialisation | `ResetPasswordPage` | `onSubmit`, `onNavigate`, `email`, `token` |
+| Confirmation courriel | `ConfirmEmailPage` | `onSubmit`, `onNavigate`, `email`, `token` |
+| Déconnexion | `LogoutPage` | `onLogout`, `onSetSessionCookie` |
+
+`onNavigate` reçoit une valeur parmi : `'login' | 'register' | 'forgot' | 'reset'`.
+
+---
+
+## Exemple : page de connexion
+
+**Serveur** — `app/auth/login/page.js`
+
+```js
+import { getSession, loginAction, setSessionCookie } from '@zen/core/features/auth/actions';
+import { LoginPageWrapper } from './LoginPageWrapper';
+
+export default async function LoginRoute() {
+ const session = await getSession();
+ return (
+
+
+
+ );
+}
+```
+
+**Client** — `app/auth/login/LoginPageWrapper.js`
+
+```js
+'use client';
+
+import { useRouter } from 'next/navigation';
+import { LoginPage } from '@zen/core/features/auth/pages';
+
+export function LoginPageWrapper({ loginAction, setSessionCookie, currentUser }) {
+ const router = useRouter();
+ return (
+ router.push(`/auth/${page}`)}
+ redirectAfterLogin="/"
+ currentUser={currentUser}
+ />
+ );
+}
+```
+
+Le même patron s'applique à toutes les autres pages. Les différences :
+
+- **RegisterPage** : passer `registerAction` comme `onSubmit`
+- **ForgotPasswordPage** : passer `forgotPasswordAction` comme `onSubmit`
+- **ResetPasswordPage** / **ConfirmEmailPage** : lire `email` et `token` dans `searchParams` et les passer en props
+- **LogoutPage** : utiliser `onLogout` au lieu de `onSubmit`, pas de `onNavigate` requis
+
+---
+
+## Protection de route
+
+```js
+import { getSession } from '@zen/core/features/auth/actions';
+import { redirect } from 'next/navigation';
+
+export default async function PageProtégée() {
+ const session = await getSession();
+ if (!session?.user) redirect('/auth/login');
+ // ...
+}
+```
+
+---
+
+## Page par défaut (sans personnalisation)
+
+Si une mise en page personnalisée n'est pas nécessaire, on garde simplement :
+
+```js
+// app/auth/[...auth]/page.js
+export { default } from '@zen/core/features/auth/server';
+```
diff --git a/src/features/auth/README-custom-login.md b/src/features/auth/README-custom-login.md
deleted file mode 100644
index 7c9ecb3..0000000
--- a/src/features/auth/README-custom-login.md
+++ /dev/null
@@ -1,347 +0,0 @@
-# Custom auth pages
-
-This guide explains how to build your own auth pages (login, register, forgot password, reset password, confirm email, logout) so they match your site’s layout and style. For a basic site you can keep using the [default auth page](#default-auth-page).
-
-## Overview
-
-You can use a **custom page for every auth flow**:
-
-| Page | Component | Server action(s) |
-|-----------------|-----------------------|-------------------------------------|
-| Login | `LoginPage` | `loginAction`, `setSessionCookie` |
-| Register | `RegisterPage` | `registerAction` |
-| Forgot password | `ForgotPasswordPage` | `forgotPasswordAction` |
-| Reset password | `ResetPasswordPage` | `resetPasswordAction` |
-| Confirm email | `ConfirmEmailPage` | `verifyEmailAction` |
-| Logout | `LogoutPage` | `logoutAction`, `setSessionCookie` |
-
-- **Components**: from `@zen/core/auth/components`
-- **Actions**: from `@zen/core/auth/actions`
-
-Create your own routes (e.g. `/login`, `/register`, `/auth/forgot`) and wrap Zen’s components in your layout. Each page follows the same pattern: a **server component** that loads data and passes actions, and a **client wrapper** that handles navigation and renders the Zen component.
-
----
-
-## Route structure
-
-Choose a URL scheme and use it consistently. Two common options:
-
-**Option A – All under `/auth/*` (like the default)**
-`/auth/login`, `/auth/register`, `/auth/forgot`, `/auth/reset`, `/auth/confirm`, `/auth/logout`
-
-**Option B – Top-level routes**
-`/login`, `/register`, `/forgot`, `/reset`, `/confirm`, `/logout`
-
-The `onNavigate` callback receives one of: `'login' | 'register' | 'forgot' | 'reset'`. Map each to your chosen path, e.g. `router.push(\`/auth/${page}\`)` or `router.push(\`/${page}\`)`.
-
-Reset and confirm pages need `email` and `token` from the URL (e.g. `/auth/reset?email=...&token=...`). Your server page can read `searchParams` and pass them to the component.
-
----
-
-## Component reference (props)
-
-Use this when wiring each custom page.
-
-| Component | Props |
-|-----------------------|--------|
-| **LoginPage** | `onSubmit` (loginAction), `onSetSessionCookie`, `onNavigate`, `redirectAfterLogin`, `currentUser` |
-| **RegisterPage** | `onSubmit` (registerAction), `onNavigate`, `currentUser` |
-| **ForgotPasswordPage**| `onSubmit` (forgotPasswordAction), `onNavigate`, `currentUser` |
-| **ResetPasswordPage** | `onSubmit` (resetPasswordAction), `onNavigate`, `email`, `token` (from URL) |
-| **ConfirmEmailPage** | `onSubmit` (verifyEmailAction), `onNavigate`, `email`, `token` (from URL) |
-| **LogoutPage** | `onLogout` (logoutAction), `onSetSessionCookie` (optional) |
-
----
-
-## 1. Login
-
-**Server:** `app/login/page.js` (or `app/auth/login/page.js`)
-
-```js
-import { getSession, loginAction, setSessionCookie } from '@zen/core/auth/actions';
-import { LoginPageWrapper } from './LoginPageWrapper';
-
-export default async function LoginRoute() {
- const session = await getSession();
- return (
-
-
-
- );
-}
-```
-
-**Client:** `app/login/LoginPageWrapper.js`
-
-```js
-'use client';
-
-import { useRouter } from 'next/navigation';
-import { LoginPage } from '@zen/core/auth/components';
-
-export function LoginPageWrapper({ loginAction, setSessionCookie, currentUser }) {
- const router = useRouter();
- return (
- router.push(`/auth/${page}`)}
- redirectAfterLogin="/"
- currentUser={currentUser}
- />
- );
-}
-```
-
----
-
-## 2. Register
-
-**Server:** `app/register/page.js`
-
-```js
-import { getSession, registerAction } from '@zen/core/auth/actions';
-import { RegisterPageWrapper } from './RegisterPageWrapper';
-
-export default async function RegisterRoute() {
- const session = await getSession();
- return (
-
-
-
- );
-}
-```
-
-**Client:** `app/register/RegisterPageWrapper.js`
-
-```js
-'use client';
-
-import { useRouter } from 'next/navigation';
-import { RegisterPage } from '@zen/core/auth/components';
-
-export function RegisterPageWrapper({ registerAction, currentUser }) {
- const router = useRouter();
- return (
- router.push(`/auth/${page}`)}
- currentUser={currentUser}
- />
- );
-}
-```
-
----
-
-## 3. Forgot password
-
-**Server:** `app/forgot/page.js`
-
-```js
-import { getSession, forgotPasswordAction } from '@zen/core/auth/actions';
-import { ForgotPasswordPageWrapper } from './ForgotPasswordPageWrapper';
-
-export default async function ForgotRoute() {
- const session = await getSession();
- return (
-
-
-
- );
-}
-```
-
-**Client:** `app/forgot/ForgotPasswordPageWrapper.js`
-
-```js
-'use client';
-
-import { useRouter } from 'next/navigation';
-import { ForgotPasswordPage } from '@zen/core/auth/components';
-
-export function ForgotPasswordPageWrapper({ forgotPasswordAction, currentUser }) {
- const router = useRouter();
- return (
- router.push(`/auth/${page}`)}
- currentUser={currentUser}
- />
- );
-}
-```
-
----
-
-## 4. Reset password
-
-Requires `email` and `token` from the reset link (e.g. `/auth/reset?email=...&token=...`). Read `searchParams` in the server component and pass them to the client.
-
-**Server:** `app/auth/reset/page.js` (or `app/reset/page.js` with dynamic segment if needed)
-
-```js
-import { resetPasswordAction } from '@zen/core/auth/actions';
-import { ResetPasswordPageWrapper } from './ResetPasswordPageWrapper';
-
-export default async function ResetRoute({ searchParams }) {
- const params = typeof searchParams?.then === 'function' ? await searchParams : searchParams ?? {};
- const email = params.email ?? '';
- const token = params.token ?? '';
- return (
-
-
-
- );
-}
-```
-
-**Client:** `app/auth/reset/ResetPasswordPageWrapper.js`
-
-```js
-'use client';
-
-import { useRouter } from 'next/navigation';
-import { ResetPasswordPage } from '@zen/core/auth/components';
-
-export function ResetPasswordPageWrapper({ resetPasswordAction, email, token }) {
- const router = useRouter();
- return (
- router.push(`/auth/${page}`)}
- email={email}
- token={token}
- />
- );
-}
-```
-
----
-
-## 5. Confirm email
-
-Requires `email` and `token` from the verification link (e.g. `/auth/confirm?email=...&token=...`).
-
-**Server:** `app/auth/confirm/page.js`
-
-```js
-import { verifyEmailAction } from '@zen/core/auth/actions';
-import { ConfirmEmailPageWrapper } from './ConfirmEmailPageWrapper';
-
-export default async function ConfirmRoute({ searchParams }) {
- const params = typeof searchParams?.then === 'function' ? await searchParams : searchParams ?? {};
- const email = params.email ?? '';
- const token = params.token ?? '';
- return (
-
-
-
- );
-}
-```
-
-**Client:** `app/auth/confirm/ConfirmEmailPageWrapper.js`
-
-```js
-'use client';
-
-import { useRouter } from 'next/navigation';
-import { ConfirmEmailPage } from '@zen/core/auth/components';
-
-export function ConfirmEmailPageWrapper({ verifyEmailAction, email, token }) {
- const router = useRouter();
- return (
- router.push(`/auth/${page}`)}
- email={email}
- token={token}
- />
- );
-}
-```
-
----
-
-## 6. Logout
-
-**Server:** `app/auth/logout/page.js`
-
-```js
-import { logoutAction, setSessionCookie } from '@zen/core/auth/actions';
-import { LogoutPageWrapper } from './LogoutPageWrapper';
-
-export default function LogoutRoute() {
- return (
-
-
-
- );
-}
-```
-
-**Client:** `app/auth/logout/LogoutPageWrapper.js`
-
-```js
-'use client';
-
-import { LogoutPage } from '@zen/core/auth/components';
-
-export function LogoutPageWrapper({ logoutAction, setSessionCookie }) {
- return (
-
- );
-}
-```
-
----
-
-## Protecting routes
-
-Use `protect()` from `@zen/core/auth` and set `redirectTo` to your custom login path:
-
-```js
-import { protect } from '@zen/core/auth';
-
-export const middleware = protect({ redirectTo: '/login' });
-```
-
-So unauthenticated users are sent to your custom login page.
-
----
-
-## Default auth page
-
-If you don’t need a custom layout, keep using the built-in auth UI. In `app/auth/[...auth]/page.js`:
-
-```js
-export { default } from '@zen/core/auth/page';
-```
-
-This serves login, register, forgot, reset, confirm, and logout under `/auth/*` with the default styling.
diff --git a/src/features/auth/pages/index.js b/src/features/auth/pages/index.js
new file mode 100644
index 0000000..cc9dde1
--- /dev/null
+++ b/src/features/auth/pages/index.js
@@ -0,0 +1,6 @@
+export { default as LoginPage } from './LoginPage.client.js';
+export { default as RegisterPage } from './RegisterPage.client.js';
+export { default as ForgotPasswordPage } from './ForgotPasswordPage.client.js';
+export { default as ResetPasswordPage } from './ResetPasswordPage.client.js';
+export { default as ConfirmEmailPage } from './ConfirmEmailPage.client.js';
+export { default as LogoutPage } from './LogoutPage.client.js';