Skip to main content

Username/password authentication for Datasette with database-backed accounts

Project description

datasette-accounts

[!WARNING] This plugin is experimental!

Username/password authentication for Datasette with accounts stored in the internal database (not in plugin config). Provisioning, password resets, disabling, and admin management all happen at runtime through an admin UI, a datasette accounts CLI, and a JSON API, guarded by a real Datasette 1.0 permission.

"Basic" as in database-backed basic login — not HTTP Basic auth.

Users log in at /-/login:

The login page: a Log in heading with username and password fields, and a help note reading "Trouble signing in? Email data-help@example.com."

Admins manage accounts at /-/admin/users — create accounts and disable, lock, reset, promote, or delete existing ones:

The admin accounts table listing users with admin, status, and lock columns and per-user action buttons.

Features

  • Database-backed accounts in Datasette's internal DB (create / disable / delete / reset-password / toggle-admin / unlock at runtime).
  • Server-side sessions — revocable per-device, with "log out everywhere" and an admin session list. Disabling an account or revoking a session takes effect on the next request.
  • A registered admin action (datasette-accounts-admin) that is self-answered for root and enabled admins, and composes with config allow blocks.
  • A datasette accounts CLI for provisioning and managing accounts from the shell — the same audited, guarded code path as the web admin UI.
  • Security hardening built in: timing-safe login (no username enumeration), PBKDF2 run off the event loop, unconditional CSRF gates, strict ?next= validation, brute-force lockout (shared by login and change-password), forced first-password-change, audit logging, and retention/pruning.
  • A Svelte/TS frontend for the login, account, and admin pages.
  • Integrates with datasette-user-profiles (a required dependency) — emits a stable actor id and seeds the profiles directory, so every account can view and edit their profile once granted the profile_access permission.

Installation

datasette install datasette-accounts

Requires Datasette 1.0a23+ and Python 3.10+.

Getting started

1. Persist accounts with --internal

Accounts live in the internal database, which is an ephemeral temp file unless you pass --internal. The plugin prints a loud startup warning when it is ephemeral. For any real use:

datasette mydata.db --internal accounts.db

2. Create the first admin

There is no admin until you make one. The quickest way is the CLI, which writes directly to the internal database — point it at the same accounts.db:

datasette accounts bootstrap-admin alice --generate -i accounts.db
# Created admin alice.
# Password (shown once): …

bootstrap-admin is idempotent — if an enabled admin already exists it prints admin already exists — skipping and exits 0, so it is safe to drop into a container entrypoint or provisioning script. Pass --password-stdin to feed a password without exposing it in argv, or --generate to mint one.

Prefer to bootstrap from the browser? Start Datasette with --root:

datasette mydata.db --internal accounts.db --root

Datasette prints a one-time http://…/-/auth-token?token=… URL that logs you in as root, who is always allowed the admin action. Open /-/admin/users, create your first admin account, then restart without --root.

3. Day-to-day

  • Users log in at /-/login and manage their own password at /-/account.
  • Admins manage accounts at /-/admin/users.
  • The Datasette menu gains Log in / Log out / Your account entries, and an Accounts link for admins.

Managing accounts from the shell

The datasette accounts command group is the CLI counterpart to the admin UI. It does not touch the internal tables directly — every command reconstructs a Datasette instance and calls the same audited, guarded db.* functions the web routes use, so last-admin guards, session revocation, and the audit trail all apply identically. Every mutating command requires -i/--internal PATH (a persistent DB); every data-emitting command supports --json.

datasette accounts create USERNAME       # --admin, --generate, --password-stdin, --must-change
datasette accounts bootstrap-admin NAME   # idempotent first-admin creation
datasette accounts list                   # --admins / --pending / --locked / --disabled
datasette accounts reset-password USERNAME
datasette accounts promote / demote USERNAME
datasette accounts disable / enable USERNAME
datasette accounts unlock USERNAME        # clear lockout counters
datasette accounts logout USERNAME        # revoke all of a user's sessions
datasette accounts delete USERNAME --yes
datasette accounts audit                  # the admin-audit trail
datasette accounts login-attempts         # the login-attempt audit
datasette accounts hash-password [PASSWORD]

Run datasette accounts COMMAND --help for the full options of each. Generated passwords are printed once to stdout and never written to the audit trail or logs.

Messages

Admins can write optional help text at /-/admin/messages — a sign-in prompt shown on the homepage to signed-out visitors, and a help/contact note shown below the login form. Blank hides a message. Bodies are admin-authored HTML rendered verbatim, so you can include links and mailto: contacts (only admins can edit them).

Configuration

All options live under the datasette-accounts plugin block and have safe defaults (a zero-config install works — it just warns about persistence):

option type default meaning
session_ttl_days int 14 absolute session lifetime
password_min_length int 8 minimum new-password length (max is fixed at 1024)
lockout_threshold int 5 consecutive failures before lock; 0 disables lockout
lockout_minutes int 15 auto-unlock window after a lock
secure_cookie "auto" / true / false "auto" Secure flag on the session cookie; set true when serving over HTTPS
audit_retention_days int 90 delete login_audit rows older than this; 0 = keep forever
plugins:
  datasette-accounts:
    session_ttl_days: 30
    password_min_length: 12
    secure_cookie: true
    audit_retention_days: 30

User profiles

Accounts are seeded into datasette-user-profiles automatically, but its profile pages are gated by the profile_access permission, which denies by default. Grant it to every signed-in account so they can view and edit their own profile:

permissions:
  profile_access:
    id: "*"        # any actor with an id — i.e. any signed-in account

or on the command line:

datasette mydata.db --internal accounts.db -s permissions.profile_access.id '*'

Development

See docs/DEVELOPMENT.md for the security model, setup, and the dev loop.

License

Apache-2.0

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

datasette_accounts-0.0.1a1.tar.gz (92.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

datasette_accounts-0.0.1a1-py3-none-any.whl (94.5 kB view details)

Uploaded Python 3

File details

Details for the file datasette_accounts-0.0.1a1.tar.gz.

File metadata

  • Download URL: datasette_accounts-0.0.1a1.tar.gz
  • Upload date:
  • Size: 92.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for datasette_accounts-0.0.1a1.tar.gz
Algorithm Hash digest
SHA256 167835d8d96e1177d9faf197f94a074a65a9a95518bd09f45aef220cdeac289e
MD5 85bedf936766f8b3a1f8efbfdc4612f4
BLAKE2b-256 f6c6831c29af0da1c67fd0d6aeeee49b4a0f3eb0ce38a8e1d497ab5083307e96

See more details on using hashes here.

File details

Details for the file datasette_accounts-0.0.1a1-py3-none-any.whl.

File metadata

  • Download URL: datasette_accounts-0.0.1a1-py3-none-any.whl
  • Upload date:
  • Size: 94.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for datasette_accounts-0.0.1a1-py3-none-any.whl
Algorithm Hash digest
SHA256 4f94250ac0b2d8ffac11dd5a34daa4dc9b3de85edec1e8a22ba14822730c3edd
MD5 a56430351e281ca9253502e3eb1d0cfb
BLAKE2b-256 b7bc1702b601660b212cd570bc276c0ec27438ccbcc4ca4e9d9a27765f5ebcd0

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page