The support inbox lists customer tickets for the signed-in agent. The home page stays reachable without a session.

Clone [starters/remix](https://github.com/authdog/samples/tree/main/starters/remix). SDK reference: [Remix](/docs/frameworks/remix).

The ticket list answers who the agent is. It does not grant a permission. Apply [authorization](/docs/concepts/authorization) after the identity check.

## What you need

| Requirement | Detail |
| --- | --- |
| Public key | `pk_...` from the [console](https://console.authdog.com) |
| Environment | Copy `.env.example` to `.env` and set `PK_AUTHDOG` |
| Secret key | Never put `sk_...` in client code |
| Return URL | Account portal back to this app. Local: `http://localhost:5173`. The root loader must receive `?token=` |

## Run

```bash
npm install
npm run dev
```

Open http://localhost:5173. Sign in, then open `/inbox`. You should see `tkt_88` (Northwind, invoice PDF) and `tkt_89` (Contoso, locked test user). Without a session, `/inbox` redirects to `signinUri`.

## Root loader

`identityLoader()` validates `?token=` through userinfo and sets HttpOnly cookies. Keep that exchange on the root loader. Calling `.json()` on the callback response and rebuilding it drops `Set-Cookie`.

```tsx
// app/root.tsx
import { Outlet, Scripts } from "@remix-run/react"
import { AuthdogProvider, ReloadPage } from "@authdog/remix-node/client"
import { identityLoader } from "@authdog/remix-node"

export const loader = identityLoader()

export default function App() {
  return (
    <AuthdogProvider>
      <Outlet />
      <Scripts />
      <ReloadPage />
    </AuthdogProvider>
  )
}
```

`AuthdogProvider` strips `?token=` in the browser. The HttpOnly cookie is set by the server loader. The loader itself returns an unauthenticated result instead of denying the request. The inbox enforces it.

## Inbox

```tsx
// app/routes/inbox.tsx
import { identityLoader } from "@authdog/remix-node"
import { redirect, type LoaderFunctionArgs } from "@remix-run/node"

const TICKETS = [
  { id: "tkt_88", from: "Northwind", subject: "Invoice PDF missing", state: "open" },
  { id: "tkt_89", from: "Contoso", subject: "SSO test user locked", state: "waiting" },
]

const loadIdentity = identityLoader()

export const loader = async (args: LoaderFunctionArgs) => {
  const response = await loadIdentity(args)
  if (!(response instanceof Response)) {
    throw new Response("Identity loader failed", { status: 500 })
  }
  const identity = (await response.json()) as {
    isAuthenticated: boolean
    signinUri: string
  }
  if (!identity.isAuthenticated) throw redirect(identity.signinUri)
  return { ...identity, tickets: TICKETS }
}
```
