Skip to content

Pre-GA Design Partner and Early Access only. Request access

Helix Docs

ctx.identity

Reference for ctx.identity with the user and org shape, roles as the authorization source, null on excluded paths, and dev identity injection.

For developers Updated Sep 18, 2026
View as Markdown

ctx.identity carries the authenticated user and organization for HTTP-triggered functions when Helix Identity is enabled. On paths excluded from authentication it is null instead of throwing, so handlers can serve both authenticated and anonymous requests. Schedules, app triggers, and queue consumers run without a user; accessing ctx.identity there throws a clear error.

IdentityContext

interface IdentityContext {
  user: {
    id: string;            // Helix user ID
    email: string;
    name: string;
    groups: string[];      // IdP-synced group names, informational only
    roles: string[];       // role IDs from helix.config.ts, use for authorization
  };
  org: {
    id: string;            // Helix org ID
    name: string;
  };
}

ctx.identity is typed IdentityContext | null.

FieldTypeDescription
user.idstringHelix user ID. Also mirrored on the top-level userId execution metadata field.
user.emailstringThe user’s email address
user.namestringDisplay name
user.groupsstring[]IdP-synced group names. For logging and display only; never branch authorization on groups.
user.rolesstring[]Role IDs declared in helix.config.ts, resolved from direct assignments plus group-to-role mappings. The authorization source.
org.idstringHelix organization ID
org.namestringOrganization name

Roles are the app’s authorization vocabulary; groups are an IdP concern. The platform maps IdP groups to roles, and your code should only reason in roles: declarative restrictions via the access named export, or user.roles.includes(...) for branching inside a handler.

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, org } = ctx.identity;
  ctx.log.info('Dashboard accessed', { userId: user.id, org: org.name });

  const isAdmin = user.roles.includes('admin');
  return isAdmin ? getFullDashboard(ctx) : getLimitedDashboard(ctx);
});

Identity in local development

helix dev has no SSO flow in front of it. The dev server injects a static dev identity into every request, so ctx.identity is always populated locally. The default dev user is dev-user / dev@localhost. To test as a specific persona, pass an identity JSON file with helix dev --identity <path>. A file containing just null simulates an unauthenticated request.

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