Read the session

The zone middleware leaves two pieces of state on the request:

  • x-zone-claims — the verified JWT payload as a JSON string.
  • x-zone-token — the raw bearer token (forward this when you call the platform).

The getSession helper reads both.

In a server component

tsx
import { getSession } from '@cxpa/sdk/zone'

export default async function Page() {
  const { claims, token } = await getSession()

  return (
    <main>
      <h1>Welcome, {claims.userName ?? claims.userEmail}</h1>
      <p>Email: {claims.userEmail}</p>
      <p>Organization: {claims.orgSlug}</p>
      <p>Role: {claims.role}</p>
    </main>
  )
}

In a server action

ts
'use server'
import { getSession } from '@cxpa/sdk/zone'

export async function triggerSomething(input: { url: string }) {
  const { claims, token } = await getSession()
  // token can now be forwarded to createZoneClient(...)
}

Claims

ts
interface ZoneClaims {
  userId: string
  userName: string | null
  userEmail: string
  orgId: string
  orgSlug: string
  agentId: number
  role: 'owner' | 'member' | 'admin'
  aud?: string
  iat?: number
  exp?: number
}

The admin role is a virtual value computed for platform admins; it is not a stored membership role.

userName is nullable — Supabase Auth metadata may not include a full name. Fall back to userEmail (or its local-part / initials) when rendering.

Continue

Call the platform API using the bearer token from getSession().