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_digestto 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:
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
authentication:
method: in_memory
user_config_path: /shared/path/to/user_config.jsonlPotato 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):
authentication:
method: database
database_url: "sqlite:///auth/users.db"PostgreSQL (requires psycopg2-binary):
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:
# Reset a specific user's password
potato reset-password config.yaml --username annotator1
# Prompted for new password interactivelyAdmin API
Reset programmatically with an API key:
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:
authentication:
method: database
database_url: "sqlite:///auth/users.db"
allow_password_reset: true
reset_token_ttl_hours: 24Admin workflow:
# 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 annotatorPasswordless Mode
For classroom demos, quick studies, or tasks using external authentication (MTurk, Prolific), you can disable passwords entirely:
authentication:
method: in_memory
require_password: falseAnnotators 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
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: annotatorFurther Reading
- SSO & OAuth Authentication — sign in with Google, GitHub, or institutional SSO
- Passwordless Login — username-only access for open tasks
- Production Setup — HTTPS and reverse proxy configuration
- Admin Dashboard — managing annotator accounts
For implementation details, see the source documentation.