Skip to content
此页面尚未提供您所选语言的版本,当前显示英文版本。

Password Management

Configure PBKDF2-SHA256 password hashing, admin CLI/API resets, self-service token-based reset flows, and SQLite or PostgreSQL credential storage in Potato.

Password Management

New in v2.4.0

Potato's authentication system uses PBKDF2-SHA256 with 100,000 iterations and per-user salts — the same approach recommended by NIST for secure password storage. This page covers how passwords are stored, how to reset them, and how to persist credentials across server restarts.

Security Implementation

Passwords are stored in salt$hash format:

  • 32-character hex salt, unique per user
  • 64-character SHA-256 hash of salt + password
  • Constant-time comparison via hmac.compare_digest to prevent timing attacks

Existing plaintext passwords in user_config.jsonl files are automatically re-hashed with unique salts when Potato loads them — no manual migration needed.

Default Configuration

By default, Potato uses in-memory authentication. Annotators must be listed in the config:

yaml
authentication:
  method: in_memory
  require_password: true
 
user_config:
  users:
    - username: "annotator1"
      password: "initial-password"   # will be hashed on first load
    - username: "annotator2"
      password: "initial-password"

Persistent Credentials

In-memory credentials are lost on restart. For persistent storage, use a file or database backend.

File-Based Persistence

yaml
authentication:
  method: in_memory
  user_config_path: /shared/path/to/user_config.jsonl

Potato writes hashed credentials to this file. On restart it reads them back — passwords set or changed during a session persist across restarts.

Database Backend

SQLite (no additional dependencies):

yaml
authentication:
  method: database
  database_url: "sqlite:///auth/users.db"

PostgreSQL (requires psycopg2-binary):

yaml
authentication:
  method: database
  database_url: "postgresql://user:password@localhost:5432/potato_auth"

Database tables are created automatically on first startup.

Note: method: database and user_config_path are mutually exclusive — choose one persistence strategy.

Resetting Passwords

Admin CLI

Reset a password from the command line:

bash
# Reset a specific user's password
potato reset-password config.yaml --username annotator1
 
# Prompted for new password interactively

Admin API

Reset programmatically with an API key:

bash
curl -X POST http://localhost:8000/admin/reset_password \
  -H "X-API-Key: $ADMIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"username": "annotator1", "new_password": "new-secure-password"}'

Self-Service Token Reset

Potato supports a user-initiated reset flow. Users go to /forgot-password, enter their username, and receive a single-use reset token. They visit /reset/<token> to set a new password.

Tokens are valid for 24 hours and can only be used once. Potato does not send emails — the admin distributes the reset link manually.

Enable in config:

yaml
authentication:
  method: database
  database_url: "sqlite:///auth/users.db"
  allow_password_reset: true
  reset_token_ttl_hours: 24

Admin workflow:

bash
# Generate a reset token for a user
curl -X POST http://localhost:8000/admin/generate_reset_token \
  -H "X-API-Key: $ADMIN_API_KEY" \
  -d '{"username": "annotator1"}'
 
# Returns: {"reset_url": "https://your-server.com/reset/abc123..."}
# Share this URL with the annotator

Passwordless Mode

For classroom demos, quick studies, or tasks using external authentication (MTurk, Prolific), you can disable passwords entirely:

yaml
authentication:
  method: in_memory
  require_password: false

Annotators enter any username to log in — no password prompt appears. Not recommended for sensitive data or tasks requiring verified identity.

See Passwordless Login for details.

Complete Reference

yaml
authentication:
  method: in_memory       # in_memory | database | oauth | clerk
 
  # In-memory options
  require_password: true
  user_config_path: path/to/users.jsonl   # optional persistence
 
  # Database options (mutually exclusive with user_config_path)
  database_url: "sqlite:///auth/users.db"
 
  # Self-service reset
  allow_password_reset: true
  reset_token_ttl_hours: 24
 
user_config:
  users:
    - username: "researcher"
      password: "secure-passphrase"
      role: admin
    - username: "annotator1"
      password: "initial-pass"
      role: annotator

Further Reading

For implementation details, see the source documentation.