Skip to content
Helix Docs

ctx.identity

Reference for ctx.identity with the user's id, email, and name, when it is null, and how to set an identity in tests.

For developers Updated Oct 23, 2026
View as Markdown

ctx.identity carries the authenticated user for HTTP-triggered functions. On paths excluded from authentication it is null instead of throwing, so handlers can serve both authenticated and anonymous requests. Schedules run without a user, and their context has no identity field.

When a request is made by a signed-in user, or with a project API token, ctx.identity describes that user (for a token, the API user the token belongs to). ctx.identity is null when there is no user: runs started with ctx.callFunctionAsync, and anonymous requests on paths excluded from authentication.

IdentityContext

interface IdentityContext {
  user: {
    id: string;            // Helix user ID
    email: string | null;  // null when the platform has no email for the caller
    name: string | null;   // null when the platform has no name for the caller
  };
}

ctx.identity is typed IdentityContext | null.

FieldTypeDescription
user.idstringHelix user ID. Also mirrored on the top-level userId execution metadata field.
user.emailstring | nullThe user’s email address. null when the platform has no email for the caller.
user.namestring | nullDisplay name. null when the platform has no name for the caller.

Example

// functions/api/v1/dashboard.get.ts
import { defineFunction } from '@trayai/helix-sdk';

export default defineFunction(async (ctx) => {
  if (!ctx.identity) {
    // Reachable only on paths excluded from authentication
    throw ctx.error(401, 'Sign-in required');
  }

  const { user } = ctx.identity;
  // email and name can be null, so fall back to the id
  const label = user.name ?? user.email ?? user.id;
  ctx.log.info('Dashboard accessed', { user: label });

  return getDashboard(ctx, { greeting: `Welcome back, ${label}` });
});

Identity in local development

helix dev has no sign-in flow, and the dev server does not supply an identity, so ctx.identity is null locally. The one exception is helix agent chat --user <id>: tools run by that agent see { user: { id, email: null, name: null } } (see helix agent). Handle null the way you handle an excluded path: branch on it instead of assuming a user.

To test code that reads the identity, pass one to runWithContext from the testing module:

import { runWithContext } from '@trayai/helix-sdk/testing';

const identity = { user: { id: 'u_1', email: 'ada@example.com', name: 'Ada' } };
const result = await runWithContext({ identity }, () => greetUser());
expect(result).toBe('Hello, Ada');

Who can open a published app is set on the project’s Access Control tab, not in code. See identity and roles.

Loading search…

Jump to a section

tab to move · esc to close