Cereal docs
Build a research agent

Scope access to a workspace

Authenticate in your app and check ownership before session access or source reads.

Continue from chat. Cereal trusts your server's asserted identity; it does not authenticate the person using your application.

Derive identity from authentication

The starter maps HTTP Basic credentials to Ada and Grace, each with a separate workspace. Neither a form field nor a model argument chooses the session owner or workspace.

src/app.ts
  function authenticate(request: Request): Member | undefined {
    const header = request.headers.get("authorization") || ""
    if (!header.startsWith("Basic ")) return undefined
    const credentials = Buffer.from(header.slice(6), "base64").toString()
    return members.find(({ id, password }) => {
      const expected = Buffer.from(`${id}:${password}`)
      const actual = Buffer.from(credentials)
      return expected.length === actual.length && timingSafeEqual(expected, actual)
    })
  }

  async function ownsSession(id: string, member: Member) {
    const session = await client.sessions.get({ id })
    return (
      session.identity?.id === member.id && session.metadata?.workspaceId === member.workspaceId
    )
  }

Every token, message, pending-approval, and decision request checks ownsSession before calling Cereal. A session belonging to another member returns 404. State-changing browser requests also require an Origin matching your application.

The source tools separately check workspaceId in verified session metadata. Search filters before returning titles; reading by ID checks the same boundary. Knowing a document ID does not grant access to its contents.

Test two workspaces

  1. As ada, ask about the Orion launch and copy the session ID from browser storage or the console.
  2. Open a private browser window and sign in as grace.
  3. Ask to read launch-plan. The tool returns found: false. Grace can read private-roadmap, the Atlas document.
  4. In Grace's window, request /api/sessions/ADA_SESSION_ID/token. The app returns 404.
  5. Confirm message and decision routes enforce the same ownership check.

Replace the fixture credential mapping with your application's sign-in and workspace membership lookup. Keep server-derived identity and ownership checks on every route. See identity and metadata.

Continue to recover and debug, or optionally control publication with a hook.

On this page