Quickstart
Add an AI assistant inside your authenticated Next.js App Router application. This guide uses your runtime with mordn-hosted infrastructure: your server verifies the session and runs the model; mordn hosts conversations, attachments, knowledge, memory, and published configuration.
You will add a server route and a client component, configure server credentials, and render the assistant inside your signed-in product.
Note
Prerequisites: Next.js 14/15/16 with App Router and a server deployment, React 18 or 19, and an existing authentication setup — Clerk, Auth.js, Supabase Auth, or your own verified sessions. The example below assumes Clerk is already installed and configured. Tailwind is not required; the widget stylesheet is precompiled.
You also need a published mordn agent, its server-only MORDN_CHAT_KEY, and
AI Gateway credentials for model calls. Configure AI_GATEWAY_API_KEY for
local development or deployments without managed Vercel AI Gateway credentials.
Selecting a model in the dashboard does not supply those credentials.
Want conversations in your own Postgres? Follow Bring your own database instead. Same widget, same handler, same security model — you supply the store.
Choose where the handler runs
| Your runtime (this guide) | Direct hosted mode | |
|---|---|---|
| Handler and model execution | Your server deployment | mordn |
| Browser connection | Your /api/chat route | mordn hosted endpoint |
| Agent credential | Server-only mck_live_… | Browser-safe pk_live_… |
| Signed-in identity | getUserId reads a verified server session | getUserToken supplies a signed JWT, verified by mordn |
| Model credentials in your app | Your AI Gateway credentials (or a provider key with a code-defined model) | Not required |
Both use hosted infrastructure. Direct hosted mode is a separate setup, not
what createMordnHandler enables in this guide. It requires hosted mode enabled
on the agent, allowed application origins, and identity-provider JWT/JWKS
settings for signed-in users. A publishable key selects the agent; it does not
authenticate a user. See Hosted mode for that setup.
Optional: scaffold the hosted integration
With widget 0.24.0 or later, run this from an existing Next.js App Router project:
npx @mordn/chat-widget@^0.24.0 init --hostedThis is the your-runtime mode described here, not direct hosted execution.
It generates the catch-all route, a server auth stub, a client component and a
separate .env.mordn.example. It does not install dependencies, change your layout,
overwrite files or secrets, provision a database, or run migrations.
The auth stub deliberately returns null: implement your verified server session,
configure the published agent key and gateway/model credentials, and mount the
component before expecting chat to work. Existing chat routes are refused so the
wizard cannot mix a new backend with an old identity boundary. If you already have
an integration, use the manual steps below instead of deleting it to rerun setup.
Create an agent and copy its key
Create an account, add an agent, and publish it. Publishing is what gives the agent a model, a system prompt, a theme, and its enabled features.
Copy the agent's server key. It looks like mck_live_… and is read only on your
server — never ship it to the browser.
MORDN_CHAT_KEY="mck_live_..."
# Local development or deployments without managed AI Gateway credentials:
AI_GATEWAY_API_KEY="your_ai_gateway_key"Set the required secrets in your deployment environment too. Neither key
belongs in a NEXT_PUBLIC_ variable or client component.
Install
npm install @mordn/chat-widget ai @ai-sdk/reactThese are the chat dependencies to add to your existing authenticated app. This path needs no database driver, storage SDK, or model-provider package. The published agent config supplies a model identifier, not model credentials.
Add the route
import { createMordnHandler } from '@mordn/chat-widget/server';
import { auth } from '@clerk/nextjs/server';
export const { GET, POST, DELETE, OPTIONS } = createMordnHandler({
apiKey: process.env.MORDN_CHAT_KEY!,
getUserId: async () => (await auth()).userId,
});apiKey and getUserId are the only required options. That one key wires
persistence, private attachments, published configuration, knowledge retrieval,
memory, hosted MCP tools, and feedback. Feature behavior depends on your
published configuration; the key does not replace your model credentials.
Swap the Clerk import for whatever you already use. The contract is the same:
return a stable user id from a verified server session, or null.
import { auth } from '@/auth';
getUserId: async () => (await auth())?.user?.id ?? null,Warning
Never derive this id from a header, query parameter, or request body. Those are
controlled by the browser. getUserId is the entire authorization boundary —
the store and storage are bound to whatever it returns. Return null when
unauthenticated and the handler responds 401 before touching user data.
Mount the widget
'use client';
import { ChatWidget } from '@mordn/chat-widget';
import '@mordn/chat-widget/styles.css';
export function Assistant() {
return <ChatWidget />;
}That is the whole component. apiBase defaults to /api/chat; pass it
explicitly if you mounted the route somewhere else.
On mount the widget calls GET ${apiBase}/bootstrap and the server returns only
what the browser is allowed to see — greeting, theme, layout, features, starter
prompts. The widget never sends a userId, so it cannot assert who it is or
whose history it may read.
Send a message
Render <Assistant /> inside a signed-in page or layout, sign in, and type. The first message
creates the conversation; reload the page and it is still there.
Infrastructure you do not need to run
Both columns below use your runtime; this compares hosted infrastructure with bringing your own database, not direct hosted mode.
| mordn-hosted infrastructure | Bring your own database | |
|---|---|---|
| Provision Postgres | Not needed | Required |
| Run migrations | Not needed | Your reviewed migration process |
| Create a private bucket | Not needed | Required for uploads |
| Model credentials | Your AI Gateway credentials | Credentials for your chosen model/provider |
Note
How the model runs. When you do not pass model in code, the handler uses
the model from your published agent config and hands that string to the AI SDK,
which routes it through the AI Gateway. Use managed Vercel AI Gateway
credentials where available; otherwise, set AI_GATEWAY_API_KEY.
In this setup, inference runs from your deployment using your gateway credentials; mordn provides persistence and configuration. This is different from direct hosted mode, where mordn runs the handler and model calls.
To pin a model in code instead, install the provider package and pass model —
see Models & tools. Code always wins over
published configuration.
Verify before shipping
- Two signed-in users cannot load, continue, delete, or attach files to each other's conversations.
- Signed-out requests get
401, not an empty conversation. - History survives a refresh.
MORDN_CHAT_KEYand anyAI_GATEWAY_API_KEYappear only in server-side configuration, never in aNEXT_PUBLIC_variable or browser bundle.- A model response streams successfully in both local and deployed environments; publishing an agent alone does not verify your model credentials.
- If the widget and handler are on different origins, configure
corsandrequestCredentialsdeliberately.