Local Authentication

Local authentication provides email and password-based user management without external OAuth dependencies. This is production-ready authentication with full control over user accounts and passwords.

For organizations using Google Workspace or other identity providers, consider Google OAuth or OIDC.

How It Works

┌──────────────┐     ┌─────────────────┐     ┌────────────┐
│   Browser    │────▶│   Stategraph    │────▶│ PostgreSQL │
│              │     │     Server      │     │            │
└──────────────┘     └─────────────────┘     └────────────┘
       │                     │
       │  1. Enter email     │
       │     & password      │
       │                     │
       │  2. POST /login     │
       │                     │
       │◀─── Session Cookie ─│
       │                     │
       │  3. Authenticated   │
       ▼     requests        │
  1. User enters email and password
  2. Stategraph validates credentials and creates a session
  3. Session token is stored as an HTTP-only cookie
  4. Subsequent requests are authenticated via the session cookie

Initial Setup

When you first deploy Stategraph with local authentication (the default), you'll see a setup wizard that guides you through creating the first admin account.

First-Time Setup Wizard

  1. Navigate to your Stategraph URL (e.g., http://localhost:8080)
  2. You'll see the setup form prompting you to create an admin account
  3. Fill in the required fields:
  4. Email: Your email address (used for login)
  5. Password: Minimum 8 characters, maximum 128 characters
  6. Name: Your display name
  7. Organization: Your organization name

  8. Click Create Admin Account

  9. You'll be automatically logged in and redirected to the Stategraph UI

The first user created is automatically granted admin privileges.

Example Setup

# Deploy Stategraph (Docker Compose example)
docker compose up -d

# Open browser to http://localhost:8080
# Fill in the setup form:
Email:        admin@example.com
Password:     your-secure-password
Name:         Admin User
Organization: My Organization

User Management

Creating Users (Admin Only)

Admins can create additional users through the Settings page:

  1. Log in as an admin user
  2. Navigate to Settings > Users
  3. Click Create User
  4. Fill in user details:
  5. Name: Display name
  6. Email: Email address (used for login)
  7. Password: Minimum 8 characters
  8. Is Admin: Toggle to grant admin privileges

  9. Click Create to create the user

User Roles

Role Capabilities
Admin Full access: create/edit/delete users, manage all states and tenants, view all settings
Regular User Access assigned tenants, create API keys, manage own states

Changing Passwords

Users changing their own password:

  1. Navigate to Settings > Account
  2. Click Change Password
  3. Enter current password for verification
  4. Enter new password (8-128 characters)
  5. Confirm new password

Admins changing any user's password:

  1. Navigate to Settings > Users
  2. Click on the user you want to modify
  3. Click Change Password
  4. Enter new password (no verification required)
  5. Confirm new password

Managing Admin Access

Admins can grant or remove admin privileges from other users:

  1. Navigate to Settings > Users
  2. Click on the user you want to modify
  3. Toggle the Is Admin switch
  4. Confirm the change

Important: You cannot remove admin privileges from yourself if you're the last admin. This prevents accidental lockout.

Deleting Users

Admins can delete users:

  1. Navigate to Settings > Users
  2. Click on the user you want to delete
  3. Click Delete User
  4. Type the user's email to confirm deletion
  5. Click Delete to confirm

Note: Deleted users are soft-deleted (marked as deleted in the database but not removed). Their API keys are immediately invalidated.

Service Accounts (API Users)

Service accounts provide programmatic access for CI/CD pipelines and automation without interactive login.

Creating Service Accounts

Service accounts are created similarly to regular users but with type api:

  1. Navigate to Settings > Service Accounts
  2. Enter a name for the service account (e.g., "github-actions", "ci-production")
  3. Click Create
  4. Copy the generated API token (shown only once)

Service accounts:

  • Cannot log in interactively (no password)
  • Receive an API token on creation
  • Are tied to a specific tenant
  • Provide clear audit trails in transaction logs

Via API:

curl -X POST http://localhost:8080/api/v1/api-users \
  -H "Content-Type: application/json" \
  -H "Cookie: session=<your-session-cookie>" \
  -d '{
    "name": "ci-production",
    "tenant_id": "<tenant-uuid>"
  }'

Response:

{
  "user_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
  "token": "eyJhbGciOiJIUzI1NiIs..."
}

Authentication Flow

Login Flow

  1. User navigates to Stategraph
  2. If not authenticated, redirected to login page
  3. User enters email and password
  4. POST request to /api/v1/login/password
  5. Server validates credentials
  6. Session token created and stored as HTTP-only cookie
  7. User redirected to Stategraph UI

Login Endpoint

POST /api/v1/login/password
Content-Type: application/json

{
  "email": "user@example.com",
  "password": "your-password"
}

Response:

{
  "session_token": "eyJhbGciOiJIUzI1NiIs...",
  "success": true
}

The session_token can be used for Bearer authentication.

Logout

GET /api/v1/logout

Clears the session cookie and logs the user out.

API Endpoints

Authentication Endpoints

Get Login Options

GET /api/v1/login/options

Returns available authentication methods (local, OAuth, etc.).

Response:

{
  "options": []
}

When OAuth is configured, the options array contains available providers.

Login with Password

POST /api/v1/login/password
Content-Type: application/json

{
  "email": "user@example.com",
  "password": "your-password"
}

Check Setup Status

GET /api/v1/setup/status

Returns whether initial setup is needed.

Response:

{
  "needs_setup": false
}

Create First Admin

POST /api/v1/setup/admin
Content-Type: application/json

{
  "email": "admin@example.com",
  "password": "secure-password",
  "name": "Admin User",
  "organization": "My Org"
}

Only works when no users exist in the system.

Logout

GET /api/v1/logout

User Management Endpoints (Admin Only)

List Users

GET /api/v1/users?type=user&limit=25&offset=0

Query parameters: - type: Filter by user type (user or api) - limit: Maximum results (default: 25) - offset: Pagination offset - search: Search by name or email

Response:

{
  "users": [
    {
      "id": "f30ed1f9-be44-46a3-9050-03e9561e94f0",
      "name": "John Doe",
      "email": "john@example.com",
      "is_admin": false,
      "type": "user",
      "created_at": "2024-01-15T10:30:00Z"
    }
  ],
  "total_count": 10,
  "limit": 25,
  "has_more": false
}

Get User Details

GET /api/v1/users/detail?user_id=<user-id>

Response:

{
  "id": "f30ed1f9-be44-46a3-9050-03e9561e94f0",
  "name": "John Doe",
  "email": "john@example.com",
  "is_admin": false,
  "type": "user",
  "created_at": "2024-01-15T10:30:00Z"
}

Note: The last_login field is included when the user has logged in at least once.

Create User

POST /api/v1/users
Content-Type: application/json

{
  "name": "Jane Doe",
  "email": "jane@example.com",
  "password": "secure-password",
  "is_admin": false
}

Response:

{
  "id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
  "name": "Jane Doe",
  "email": "jane@example.com",
  "is_admin": false
}

Update User

PUT /api/v1/users/update?user_id=<user-id>
Content-Type: application/json

{
  "name": "Jane Smith",
  "email": "jane.smith@example.com"
}

Delete User

DELETE /api/v1/users/delete?user_id=<user-id>

Response: 204 No Content

Change User Password

POST /api/v1/users/change-password?user_id=<user-id>
Content-Type: application/json

{
  "new_password": "new-secure-password",
  "current_password": "old-password"  # Only required when changing own password
}

Toggle Admin Status

POST /api/v1/users/toggle-admin?user_id=<user-id>
Content-Type: application/json

{
  "is_admin": true
}

Service Account Endpoints

Create Service Account

POST /api/v1/api-users
Content-Type: application/json

{
  "name": "ci-production",
  "tenant_id": "<tenant-uuid>"
}

Response:

{
  "user_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
  "token": "eyJhbGciOiJIUzI1NiIs..."
}

Important: Save the token immediately - it's only shown once.

Creating API Keys

Once authenticated, you can create API keys for CLI and Terraform access:

  1. Log in to Stategraph
  2. Navigate to Settings > API Keys
  3. Click Create API Key
  4. Optionally provide a name/description
  5. Copy the generated token

Use the API key with the CLI:

export STATEGRAPH_API_KEY="<your-api-key>"
stategraph states list --tenant <tenant-id>

Or with Terraform:

terraform {
  backend "http" {
    address  = "http://localhost:8080/api/v1/states/backend/<state-id>"
    username = "session"
    password = "<your-api-key>"
  }
}

Security Considerations

Password Requirements

  • Minimum length: 8 characters
  • Maximum length: 128 characters
  • No complexity requirements enforced (consider using strong passwords)

Session Security

  • Sessions are stored as HTTP-only cookies (not accessible via JavaScript)
  • Session tokens are JWT tokens signed with a secret key
  • Use HTTPS in production to protect credentials and session tokens in transit

Best Practices

  1. Use HTTPS: Always deploy with HTTPS in production
  2. Strong passwords: Enforce strong password policies at the organizational level
  3. Regular audits: Review user list and admin access regularly
  4. Service accounts: Use service accounts for CI/CD instead of personal credentials
  5. Principle of least privilege: Only grant admin access when necessary
  6. Monitor access: Review transaction logs for unusual activity

Admin Responsibilities

Admins can:

  • Create and delete any user
  • Change any user's password without verification
  • Grant and revoke admin privileges
  • View all states and tenants
  • Cannot accidentally remove the last admin

Transitioning to OAuth

When you're ready to switch to OAuth:

  1. Configure OAuth environment variables (Google OAuth or OIDC)
  2. Restart Stategraph with OAuth configuration
  3. Existing local users remain in the database
  4. New OAuth users are created on first login
  5. Existing API keys continue to work

Note: Once OAuth is enabled, the local authentication login page is replaced with OAuth login. Existing local users cannot log in via password unless OAuth is disabled.

Next Steps