> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/trailbaseio/trailbase/llms.txt
> Use this file to discover all available pages before exploring further.

# User Management

> CLI commands for managing users and admins

## Overview

TrailBase provides comprehensive CLI commands for managing users and administrators. Unlike the admin UI, CLI commands allow you to modify admin users and perform operations that require elevated permissions.

## User Commands

All user commands operate on the `_user` table in the main database. Users can be identified by either email address or UUID.

### User Identifiers

Most commands accept a user identifier that can be:

<ParamField path="Email Address" type="string">
  User's email address (e.g., `user@example.com`)

  Must contain an `@` symbol
</ParamField>

<ParamField path="UUID" type="string">
  User's unique identifier (e.g., `550e8400-e29b-41d4-a716-446655440000`)

  Standard UUID format
</ParamField>

<CodeGroup>
  ```bash Using Email theme={null}
  trail user verify user@example.com true
  ```

  ```bash Using UUID theme={null}
  trail user verify 550e8400-e29b-41d4-a716-446655440000 true
  ```
</CodeGroup>

## Adding Users

### user add

Create a new verified user with email and password.

```bash theme={null}
trail user add <EMAIL> <PASSWORD>
```

<ParamField path="email" type="string" required>
  Email address for the new user. Must be a valid email format and unique.
</ParamField>

<ParamField path="password" type="string" required>
  Password for the new user. Not checked against password policies, so choose a strong password.
</ParamField>

<CodeGroup>
  ```bash Create Regular User theme={null}
  trail user add user@example.com SecureP@ssw0rd123

  # Output: Added user 'user@example.com'
  ```

  ```bash Create Admin User (Two Steps) theme={null}
  # Step 1: Add user
  trail user add admin@example.com AdminP@ssw0rd123

  # Step 2: Promote to admin
  trail admin promote admin@example.com
  ```
</CodeGroup>

<Info>
  Users created with `trail user add` are automatically marked as verified and can log in immediately.
</Info>

<Warning>
  The CLI does not enforce password policies. Ensure you use strong passwords when creating users via CLI.
</Warning>

## Modifying Users

### user change-password

Change a user's password.

```bash theme={null}
trail user change-password <USER> <PASSWORD>
```

<ParamField path="user" type="string" required>
  User identifier (email or UUID).
</ParamField>

<ParamField path="password" type="string" required>
  New password to set for the user.
</ParamField>

<CodeGroup>
  ```bash By Email theme={null}
  trail user change-password user@example.com NewP@ssw0rd456

  # Output: Updated password for 'user@example.com'
  ```

  ```bash By UUID theme={null}
  trail user change-password 550e8400-e29b-41d4-a716-446655440000 NewP@ssw0rd456

  # Output: Updated password for '550e8400-e29b-41d4-a716-446655440000'
  ```
</CodeGroup>

<Note>
  Password changes take effect immediately. Active sessions remain valid until their tokens expire.
</Note>

### user change-email

Change a user's email address.

```bash theme={null}
trail user change-email <USER> <NEW_EMAIL>
```

<ParamField path="user" type="string" required>
  User identifier (email or UUID).
</ParamField>

<ParamField path="new_email" type="string" required>
  New email address to set for the user. Must be unique.
</ParamField>

<CodeGroup>
  ```bash Change Email theme={null}
  trail user change-email old@example.com new@example.com

  # Output: Updated email for 'old@example.com'
  ```

  ```bash By UUID theme={null}
  trail user change-email 550e8400-e29b-41d4-a716-446655440000 updated@example.com

  # Output: Updated email for '550e8400-e29b-41d4-a716-446655440000'
  ```
</CodeGroup>

<Warning>
  Email changes do not trigger verification emails. The user can immediately log in with the new email address.
</Warning>

### user verify

Change a user's email verification status.

```bash theme={null}
trail user verify <USER> [VERIFIED]
```

<ParamField path="user" type="string" required>
  User identifier (email or UUID).
</ParamField>

<ParamField path="verified" type="boolean" default="true">
  Verification status to set. `true` to verify, `false` to unverify.
</ParamField>

<CodeGroup>
  ```bash Verify User theme={null}
  trail user verify user@example.com true

  # Output: Set verified=true for 'user@example.com'
  ```

  ```bash Unverify User theme={null}
  trail user verify user@example.com false

  # Output: Set verified=false for 'user@example.com'
  ```

  ```bash Default (Verify) theme={null}
  trail user verify user@example.com

  # Output: Set verified=true for 'user@example.com'
  ```
</CodeGroup>

<Info>
  Unverified users cannot log in until they verify their email or are manually verified via CLI.
</Info>

## Session Management

### user invalidate-session

Invalidate all active sessions for a user, forcing re-authentication.

```bash theme={null}
trail user invalidate-session <USER>
```

<ParamField path="user" type="string" required>
  User identifier (email or UUID).
</ParamField>

```bash Example theme={null}
trail user invalidate-session user@example.com

# Output: Sessions invalidated for 'user@example.com'
```

<Note>
  Active auth tokens remain valid until expiration. Users will need to re-authenticate when their current token expires.
</Note>

**Use cases:**

* User reports compromised account
* Force logout after password change
* Security incident response
* User permission changes require re-authentication

### user mint-token

Generate an authentication token for a user.

```bash theme={null}
trail user mint-token <USER>
```

<ParamField path="user" type="string" required>
  User identifier (email or UUID).
</ParamField>

**Example:**

```bash theme={null}
trail user mint-token admin@example.com

# Output:
# Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI1NTBlODQwMC1lMjliLTQxZDQtYTcxNi00NDY2NTU0NDAwMDAiLCJleHAiOjE3MDk4MjU0MTJ9.signature
```

<Info>
  The output is in Bearer token format and can be used directly in Authorization headers for API requests.
</Info>

**Use token with curl:**

```bash theme={null}
# Mint token
TOKEN=$(trail user mint-token admin@example.com)

# Use in API request
curl -H "Authorization: ${TOKEN}" https://localhost:4000/api/records/v1/posts
```

**Use cases:**

* Testing API endpoints
* Automated scripts requiring authentication
* Debugging authentication issues
* Service-to-service authentication

<Warning>
  Tokens are sensitive credentials. Handle them securely and never commit them to version control.
</Warning>

## Deleting Users

### user delete

Permanently delete a user and all associated data.

```bash theme={null}
trail user delete <USER>
```

<ParamField path="user" type="string" required>
  User identifier (email or UUID).
</ParamField>

<CodeGroup>
  ```bash By Email theme={null}
  trail user delete user@example.com

  # Output: Deleted user 'user@example.com'
  ```

  ```bash By UUID theme={null}
  trail user delete 550e8400-e29b-41d4-a716-446655440000

  # Output: Deleted user '550e8400-e29b-41d4-a716-446655440000'
  ```
</CodeGroup>

<Warning>
  This operation is **irreversible**. All user data will be permanently deleted. Consider backing up the database before deleting users.
</Warning>

**What gets deleted:**

* User record from `_user` table
* User sessions from `_session` table
* User avatar from `_user_avatar` table
* Related records (depending on foreign key constraints)

**Backup before deletion:**

```bash theme={null}
# Backup database
cp traildepot/data/main.db traildepot/data/main.db.backup

# Then delete user
trail user delete user@example.com
```

## Admin Management

### admin list

List all users with admin privileges.

```bash theme={null}
trail admin list
```

**Example output:**

```
                                   id	email	created	updated
550e8400-e29b-41d4-a716-446655440000	admin@example.com	2024-01-15T10:30:00Z	2024-03-07T14:22:00Z
6ba7b810-9dad-11d1-80b4-00c04fd430c8	super@example.com	2024-02-01T08:15:00Z	2024-03-05T16:45:00Z
```

**Output columns:**

* `id` - User UUID
* `email` - User email address
* `created` - Account creation timestamp
* `updated` - Last update timestamp

### admin promote

Promote a regular user to admin.

```bash theme={null}
trail admin promote <USER>
```

<ParamField path="user" type="string" required>
  User identifier (email or UUID).
</ParamField>

<CodeGroup>
  ```bash By Email theme={null}
  trail admin promote user@example.com

  # Output: Promoted user to admin for 'user@example.com'
  ```

  ```bash By UUID theme={null}
  trail admin promote 550e8400-e29b-41d4-a716-446655440000

  # Output: Promoted user to admin for '550e8400-e29b-41d4-a716-446655440000'
  ```
</CodeGroup>

<Info>
  Admin users gain access to the admin UI and all admin API endpoints. Permissions take effect immediately for new sessions.
</Info>

**Admin privileges include:**

* Access to Admin UI (`/_admin`)
* Configuration management
* User management via UI
* Schema management
* Log viewing
* API management

### admin demote

Demote an admin user to regular user.

```bash theme={null}
trail admin demote <USER>
```

<ParamField path="user" type="string" required>
  User identifier (email or UUID).
</ParamField>

<CodeGroup>
  ```bash By Email theme={null}
  trail admin demote admin@example.com

  # Output: Demoted admin to user for 'admin@example.com'
  ```

  ```bash By UUID theme={null}
  trail admin demote 550e8400-e29b-41d4-a716-446655440000

  # Output: Demoted admin to user for '550e8400-e29b-41d4-a716-446655440000'
  ```
</CodeGroup>

<Warning>
  Demoted users lose admin access immediately for new sessions. Existing sessions may retain admin access until tokens expire.
</Warning>

<Note>
  Unlike the admin UI, the CLI allows you to demote yourself. Ensure you have at least one admin user before demoting all admins.
</Note>

## User Import

### user import

Bulk import users from external authentication providers.

```bash theme={null}
trail user import [OPTIONS]
```

<ParamField path="--auth0-json" type="string">
  Path to Auth0 exported users as newline-delimited JSON (NDJSON) file.
</ParamField>

<ParamField path="-n, --dry-run" type="boolean" default="false">
  Validate users without importing. Useful for testing before actual import.
</ParamField>

<CodeGroup>
  ```bash Dry Run (Validate Only) theme={null}
  trail user import --auth0-json users.ndjson --dry-run

  # Output:
  # Importing 150 users.
  # (No actual import, validation only)
  ```

  ```bash Import Users theme={null}
  trail user import --auth0-json users.ndjson

  # Output:
  # Importing 150 users.
  # Successfully imported 150 users.
  ```
</CodeGroup>

**Auth0 export format:**

Auth0 exports users in NDJSON format (one JSON object per line):

```json theme={null}
{"user_id":"auth0|123","email":"user1@example.com","email_verified":true,...}
{"user_id":"auth0|456","email":"user2@example.com","email_verified":false,...}
```

**Import process:**

1. Validates each user record
2. Creates users with verified status
3. Hashes passwords securely
4. Handles duplicate emails (skips or errors)
5. Reports import statistics

<Info>
  Always run with `--dry-run` first to validate the import file before performing the actual import.
</Info>

<Warning>
  Large imports may take time. Monitor the import process and ensure the database isn't locked by other processes.
</Warning>

## Common Workflows

### Creating Your First Admin

<Accordion title="Step-by-step: Create first admin user">
  ```bash theme={null}
  # 1. Add user
  trail user add admin@example.com SecureAdminP@ssw0rd

  # 2. Promote to admin
  trail admin promote admin@example.com

  # 3. Verify admin status
  trail admin list

  # 4. Log in to admin UI
  # Navigate to http://localhost:4000/_admin
  # Use: admin@example.com / SecureAdminP@ssw0rd
  ```
</Accordion>

### Handling Forgotten Passwords

<Accordion title="Step-by-step: Reset user password">
  ```bash theme={null}
  # 1. User contacts you about forgotten password

  # 2. Reset password via CLI
  trail user change-password user@example.com TemporaryP@ss123

  # 3. Send new temporary password to user via secure channel

  # 4. Instruct user to change password after login
  ```
</Accordion>

### Emergency Admin Access

<Accordion title="Step-by-step: Regain admin access">
  ```bash theme={null}
  # Scenario: Locked out of admin account

  # 1. Check if admin exists
  trail admin list

  # 2. If no admins exist, create emergency admin
  trail user add emergency@example.com EmergencyP@ss123
  trail admin promote emergency@example.com

  # 3. Log in and create proper admin account via UI

  # 4. Delete emergency account
  trail user delete emergency@example.com
  ```
</Accordion>

### Bulk User Operations

<Accordion title="Step-by-step: Create multiple users from CSV">
  ```bash theme={null}
  # users.csv format: email,password
  # user1@example.com,Password123
  # user2@example.com,Password456

  # Create users from CSV
  while IFS=, read -r email password; do
    trail user add "$email" "$password"
  done < users.csv
  ```
</Accordion>

<Accordion title="Step-by-step: Verify all unverified users">
  ```bash theme={null}
  # Get unverified user emails from database
  sqlite3 traildepot/data/main.db \
    "SELECT email FROM _user WHERE verified = 0" | \
    while read -r email; do
      trail user verify "$email" true
      echo "Verified: $email"
    done
  ```
</Accordion>

### Security Operations

<Accordion title="Step-by-step: Handle compromised account">
  ```bash theme={null}
  # 1. Invalidate all sessions
  trail user invalidate-session compromised@example.com

  # 2. Change password
  trail user change-password compromised@example.com NewSecureP@ss789

  # 3. If admin, consider temporary demotion
  trail admin demote compromised@example.com

  # 4. Notify user
  trail email \
    --to compromised@example.com \
    --subject "Security Alert" \
    --body "Your password has been reset. Contact support for details."

  # 5. After user verifies identity, restore admin if needed
  trail admin promote compromised@example.com
  ```
</Accordion>

## Troubleshooting

### User Not Found

**Error:** `Could not find user: user@example.com`

**Solutions:**

```bash theme={null}
# Check if user exists
sqlite3 traildepot/data/main.db "SELECT email FROM _user WHERE email = 'user@example.com'"

# List all users
sqlite3 traildepot/data/main.db "SELECT email FROM _user"

# Check by UUID instead
trail user verify 550e8400-e29b-41d4-a716-446655440000 true
```

### Duplicate Email

**Error:** `User with email already exists`

**Solutions:**

```bash theme={null}
# Find existing user
sqlite3 traildepot/data/main.db \
  "SELECT id, email, verified FROM _user WHERE email = 'user@example.com'"

# Delete existing user if appropriate
trail user delete user@example.com

# Or modify existing user instead of creating new one
trail user change-password user@example.com NewP@ssw0rd
```

### Can't Demote Last Admin

**Issue:** Demoting the last admin leaves no way to access admin UI

**Solution:**

```bash theme={null}
# Create new admin before demoting
trail user add newadmin@example.com AdminP@ss123
trail admin promote newadmin@example.com

# Verify multiple admins exist
trail admin list

# Now safe to demote
trail admin demote oldadmin@example.com
```

### Import Fails Partway

**Issue:** Large import fails after importing some users

**Solutions:**

```bash theme={null}
# 1. Check how many users were imported
sqlite3 traildepot/data/main.db "SELECT COUNT(*) FROM _user"

# 2. Identify which users need importing
# Extract emails from NDJSON
grep -o '"email":"[^"]*"' users.ndjson | cut -d'"' -f4 > all_emails.txt

# Get imported emails
sqlite3 traildepot/data/main.db "SELECT email FROM _user" > imported_emails.txt

# Find remaining emails
comm -23 <(sort all_emails.txt) <(sort imported_emails.txt) > remaining_emails.txt

# 3. Filter NDJSON to only remaining users and retry
```

## Database Schema

### \_user Table

The user table structure:

```sql theme={null}
CREATE TABLE _user (
  id BLOB PRIMARY KEY,              -- UUID (16 bytes)
  email TEXT NOT NULL UNIQUE,       -- Email address
  password_hash BLOB,               -- Argon2id hash
  verified INTEGER NOT NULL,        -- 0 = unverified, 1 = verified
  admin INTEGER NOT NULL,           -- 0 = user, >0 = admin
  created INTEGER NOT NULL,         -- Unix timestamp
  updated INTEGER NOT NULL          -- Unix timestamp
);

CREATE INDEX idx_user_email ON _user(email);
CREATE INDEX idx_user_admin ON _user(admin);
```

**Query examples:**

```sql theme={null}
-- List all users
SELECT id, email, verified, admin, created FROM _user;

-- Find unverified users
SELECT email FROM _user WHERE verified = 0;

-- Count admins
SELECT COUNT(*) FROM _user WHERE admin > 0;

-- Recent users
SELECT email, created FROM _user ORDER BY created DESC LIMIT 10;
```
