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().