Documentation Index Fetch the complete documentation index at: https://mintlify.com/directus/directus/llms.txt
Use this file to discover all available pages before exploring further.
What are Users?
Users are individual accounts that can authenticate and access Directus. Each user has a unique email address, password (or authentication method), and is assigned to one or more roles that determine their permissions and access levels.
Users are stored in the directus_users system collection and can be managed through the API or admin interface.
User Structure
Users have both required system fields and optional profile information:
Required Fields
id - Unique identifier (UUID)
email - Unique email address (case-insensitive)
password - Hashed password
role - Assigned role ID
status - Account status (active, suspended, draft, invited)
provider - Authentication provider (default, ldap, oauth, etc.)
Optional Fields
first_name - User’s first name
last_name - User’s last name
avatar - Profile image (file ID)
language - Preferred interface language
theme - App theme preference (auto, light, dark)
tfa_secret - Two-factor authentication secret
email_notifications - Enable email notifications
title - Job title
description - User bio/description
tags - Organizational tags
location - Geographic location
Creating Users
Via API
POST /users
Content-Type : application/json
{
"email" : "editor@example.com" ,
"password" : "SecurePassword123!" ,
"role" : "editor-role-id" ,
"first_name" : "Jane" ,
"last_name" : "Smith" ,
"status" : "active"
}
From the source code (~/workspace/source/api/src/services/users.ts:190-200), creating a user:
Validates email uniqueness (case-insensitive)
Checks password against password policy
Hashes the password securely
Creates the user record
Triggers user creation hooks
Email Validation
From the source code (~/workspace/source/api/src/services/users.ts:50-80):
private async checkUniqueEmails ( emails : string [], excludeKey ?: PrimaryKey ): Promise < void > {
emails = emails . map (( email ) => email . toLowerCase ());
const duplicates = emails . filter (( value , index , array ) =>
array . indexOf ( value ) !== index
);
if (duplicates.length) {
throw new RecordNotUniqueError ({
collection: 'directus_users' ,
field: 'email' ,
});
}
const query = this . knex
.select( 'email' )
.from( 'directus_users' )
.whereRaw( `LOWER(??) IN ( ${ emails . map (() => '?' ) } )` , [ 'email' , ... emails]);
if (excludeKey) {
query.whereNot('id', excludeKey);
}
const results = await query;
if (results.length) {
throw new RecordNotUniqueError({
collection: 'directus_users' ,
field: 'email' ,
});
}
}
Password Policies
From the source code (~/workspace/source/api/src/services/users.ts:87-118), passwords are validated against configurable policies:
private async checkPasswordPolicy ( passwords : string []): Promise < void > {
const settingsService = new SettingsService ({
schema: this . schema ,
knex: this . knex ,
});
const { auth_password_policy : policyRegExString } = await settingsService.readSingleton({
fields : [ 'auth_password_policy' ],
});
if (! policyRegExString ) {
return ;
}
const wrapped = policyRegExString . startsWith ( '/' ) && policyRegExString . endsWith ( '/' );
const regex = new RegExp ( wrapped ? policyRegExString . slice ( 1 , - 1 ) : policyRegExString );
for ( const password of passwords ) {
if ( ! regex . test ( password )) {
throw new FailedValidationError ({
message: `Provided password doesn't match password policy` ,
path: [ 'password' ],
type: 'custom.pattern.base' ,
});
}
}
}
User Status
Users can have different statuses:
Active
Fully functional account that can authenticate and access the system.
Invited
User has been invited but hasn’t completed registration.
Draft
User account exists but is not yet active.
Suspended
{ "status" : "suspended" }
Account is temporarily disabled and cannot authenticate.
Suspended users cannot log in and their sessions are invalidated.
Inviting Users
Send invitation emails to new users:
POST /users/invite
Content-Type : application/json
{
"email" : "newuser@example.com" ,
"role" : "editor-role-id" ,
"invite_url" : "https://yourdomain.com/admin/accept-invite"
}
From the source code (~/workspace/source/api/src/services/users.ts:153-164), the invitation process:
Creates a user with status: invited
Generates a JWT token with email and scope: invite
Sends invitation email with acceptance link
Token expires based on USER_INVITE_TOKEN_TTL setting
What are Roles?
Roles are groups that define shared permissions and access levels. Users are assigned to roles, which in turn are associated with policies containing permissions.
User → Role → Policies → Permissions
Role Structure
// Stored in directus_roles collection
{
id : string ; // Unique identifier
name : string ; // Role display name
icon : string ; // Icon identifier
description : string ; // Role description
ip_access : string []; // Allowed IP addresses
enforce_tfa : boolean ; // Require two-factor authentication
admin_access : boolean ; // Grant full admin access
app_access : boolean ; // Allow access to admin app
parent : string | null ; // Parent role for inheritance
}
Admin Roles
Roles with admin_access: true bypass all permission checks:
{
"id" : "admin-role" ,
"name" : "Administrator" ,
"admin_access" : true ,
"app_access" : true
}
Admin users have unrestricted access to all collections, fields, and items. Use this carefully.
App Access
Roles with app_access: true can access the Directus admin application:
{
"id" : "editor-role" ,
"name" : "Editor" ,
"app_access" : true ,
"admin_access" : false
}
Roles without app access can only use the API.
Creating Roles
POST /roles
Content-Type : application/json
{
"name" : "Content Editor" ,
"icon" : "edit" ,
"description" : "Can create and edit content" ,
"admin_access" : false ,
"app_access" : true
}
From the source code (~/workspace/source/api/src/services/roles.ts:13-19), role creation is straightforward but changes to roles trigger cache clearing and user integrity checks.
Role Inheritance
Roles can inherit from parent roles:
{
"id" : "senior-editor" ,
"name" : "Senior Editor" ,
"parent" : "editor-role"
}
From the source code (~/workspace/source/api/src/services/roles.ts:108-119), role nesting is validated to prevent circular references:
private async validateRoleNesting ( ids : string [], parent : string ) {
if ( ids . includes ( parent )) {
throw new InvalidPayloadError ({
reason: 'A role cannot be a parent of itself'
});
}
const roles = await fetchRolesTree ( parent , { knex: this . knex });
if ( ids . some (( id ) => roles . includes ( id ))) {
throw new InvalidPayloadError ({
reason: 'A role cannot have a parent that is already a descendant of itself'
});
}
}
Policies and Access
Roles are linked to policies through the directus_access collection:
{
"id" : 1 ,
"role" : "editor-role" ,
"policy" : "editor-policy" ,
"sort" : 1
}
Multiple policies can be assigned to a single role, with permissions merged from all policies.
Deleting Roles
From the source code (~/workspace/source/api/src/services/roles.ts:46-106), deleting a role:
Deletes all permissions associated with the role’s policies
Deletes all presets for the role
Suspends all users assigned to the role
Sets users’ role to NULL
Updates child roles to remove parent reference
override async deleteMany ( keys : PrimaryKey [], opts : MutationOptions = {}): Promise < PrimaryKey [] > {
opts. userIntegrityCheckFlags = UserIntegrityCheckFlag . All ;
await transaction (this.knex, async ( trx ) => {
// Delete permissions for this role
await accessService . deleteByQuery (
{ filter : { role : { _in : keys } } },
{ ... opts , bypassLimits : true },
);
// Delete presets for this role
await presetsService . deleteByQuery (
{ filter : { role : { _in : keys } } },
{ ... opts , bypassLimits : true },
);
// Suspend users in role
await usersService . updateByQuery (
{ filter : { role : { _in : keys } } },
{ status : 'suspended' , role : null },
{ ... opts , bypassLimits : true },
);
// Clear parent references
await rolesService . updateByQuery (
{ filter : { parent : { _in : keys } } },
{ parent : null },
);
await rolesItemsService . deleteMany ( keys , opts );
});
return keys;
}
Deleting a role suspends all users assigned to it. Reassign users to different roles before deletion to maintain their access.
Authentication Providers
Users can authenticate through multiple providers:
Default Provider
{
"email" : "user@example.com" ,
"password" : "password" ,
"provider" : "default"
}
Standard email/password authentication.
LDAP Provider
{
"email" : "user@company.com" ,
"provider" : "ldap"
}
OAuth Providers
{
"email" : "user@gmail.com" ,
"provider" : "google"
}
Supported OAuth providers: Google, GitHub, Facebook, etc.
Two-Factor Authentication
Enabling TFA
POST /users/me/tfa/enable
Content-Type : application/json
{
"password" : "current-password"
}
Returns a QR code and secret for authenticator apps.
Enforcing TFA
Roles can require TFA for all users:
{
"id" : "admin-role" ,
"name" : "Administrator" ,
"enforce_tfa" : true
}
IP Access Restrictions
Limit role access to specific IP addresses:
{
"id" : "admin-role" ,
"ip_access" : [
"192.168.1.0/24" ,
"10.0.0.1"
]
}
User Sessions
From the source code (~/workspace/source/api/src/services/users.ts:123-133), user sessions can be cleared:
private async clearUserSessions ( userKeys : PrimaryKey [], excludeSession ?: string ): Promise < void > {
if ( excludeSession ) {
await this . knex
. from ( 'directus_sessions' )
. whereIn ( 'user' , userKeys )
. andWhereNot ( 'token' , '=' , excludeSession )
. delete ();
} else {
await this . knex
. from ( 'directus_sessions' )
. whereIn ( 'user' , userKeys )
. delete ();
}
}
This is useful for:
Forcing users to re-authenticate
Security incidents
Role/permission changes
Common Use Cases
Content Team Create Editor, Reviewer, and Publisher roles with progressive permissions for content workflows.
API Clients Set up API-only roles without app access for external system integrations.
Department Access Create department-specific roles with conditional permissions based on user attributes.
Customer Portal Build customer-facing roles with limited access to their own data and public content.
Best Practices
Unique Email Addresses : Ensure email addresses are unique across all users, even with different casing.
Strong Password Policies : Configure password policies in settings to enforce complexity requirements.
Role-Based Design : Design roles based on job functions rather than individual users for easier management.
Minimal Admin Accounts : Limit the number of users with admin access to reduce security risks.
Enable TFA : Require two-factor authentication for sensitive roles like administrators.
Regular Audits : Periodically review user accounts and roles to remove inactive users and update permissions.
Permissions - Access control rules assigned to roles
Collections - Data that users and roles can access
Items - Records that users create and manage