Authentication
View as markdown.mdProfile fields
Store custom fields — a role, a bio, preferences — on every user.
Beyond identity, a project can define custom fields stored on every user: a bio, a role,
a set of interests. You define them in the dashboard or via the MCP. Your app reads and writes their values
through the SDK.
Defining a field
Go to Authentication → Profile fields and add a field. Each one has:
| Setting | Description |
|---|---|
| Name | The key you'll use in code, e.g. role |
| Description | A note for whoever manages users in the dashboard |
| Type | Text, Single choice, or Multiple choice |
| Options | For the choice types — one per line |
| Visible to the user | Whether the user can see the field at all |
| Editable by the user | Whether the user can change it themselves |
Types
The following TypeScript types will be returned depending on the type of the profile field:
| Type | Value in code |
|---|---|
| Text | string | null |
| Single choice | string | null |
| Multiple choice | string[] | null |
Visibility and editability
The visibility and editability properties of a field define the following:
Visible:
true- This field will be returned in thegetUser({ profile: true })response.false- This field will not be returned when getting the profile.
Editable:
true- This field can be edited by the user themselves via theupdateProfile()method.false- This field can only be edited from the dashboard. Useful for fields like arole.
Editable implies visible, so a field that isn't visible can't be user-editable.
Reading the profile
Ask for the profile alongside the user — one round trip:
const me = await client.auth.getUser({ profile: true });
me?.profile.bio; // "…"
me?.profile.role; // "member"Writing the profile
await client.auth.updateProfile({ bio: 'Hello' });
await client.auth.updateProfile({ bio: null }); // null clears a fieldA user can only update their own profile, and only fields marked editable. Writing a profile field that was marked as not editable is rejected.
Typing the profile
You can pass your field shape as a type argument:
type Profile = {
bio: string;
role: 'admin' | 'member';
interests: string[];
};
const me = await client.auth.getUser<Profile>({ profile: true });
me?.profile.role; // 'admin' | 'member' | null | undefined
me?.profile.xyz; // compile error — not a declared fieldNote
Every field comes back optional and nullable — absent if not visible to you, null if
visible but unset. Declare the plain shape and the SDK adds | null | undefined for you.
Field values must extend string | string[] | null.
Managing fields
Add, change or remove fields in the dashboard, or through the MCP server — handy when an assistant is writing the code that uses them. The SDK reads and writes values, never definitions.