datasette/docs
Simon Willison c96dc5ce26
register_token_handler() plugin hook for custom API token backends (#2650)
Closes #2649

* Add register_token_handler plugin hook for pluggable token backends

Adds a new register_token_handler hook that allows plugins to provide
custom token creation and verification backends. This enables plugins
like datasette-oauth to issue tokens without depending on specific
backend plugins like datasette-auth-tokens.

Key changes:
- New datasette/tokens.py with TokenHandler base class and SignedTokenHandler
  (the default signed-token implementation moved here)
- New register_token_handler hookspec in hookspecs.py
- Datasette.create_token() is now async and delegates to token handlers
- New Datasette.verify_token() method tries all handlers in sequence
- handler= parameter on create_token() to select a specific backend
- TokenHandler exported from datasette package for plugin use
- Fixed actor_from_request loop to await all coroutines (avoids warnings)

* Add documentation and hook test for register_token_handler

Fixes CI failures: the new hook needs a section in docs/plugin_hooks.rst
(checked by test_plugin_hooks_are_documented) and a test_hook_* function
in test_plugins.py (checked by test_plugin_hooks_have_tests).

* Register tokens module as separate default plugin

Instead of re-exporting hookimpls from default_permissions/__init__.py,
register datasette.default_permissions.tokens as its own DEFAULT_PLUGINS
entry. Cleaner and avoids confusing import-for-side-effect patterns.

* Replace restrict_x params with TokenRestrictions dataclass

Consolidates the three separate restrict_all, restrict_database, and
restrict_resource parameters into a single TokenRestrictions dataclass.
Cleaner API surface for both Datasette.create_token() and
TokenHandler.create_token().

Also clarifies docs re: default handler selection via pluggy ordering.

* Add builder methods to TokenRestrictions

Adds allow_all(), allow_database(), and allow_resource() methods that
return self for chaining. Callers no longer need to manipulate nested
dicts directly:

    restrictions = (TokenRestrictions()
        .allow_all("view-instance")
        .allow_database("mydb", "create-table")
        .allow_resource("mydb", "mytable", "insert-row"))

* docs: add 1.0a25 upgrade guide section for create_token() signature change

Ref: https://github.com/simonw/datasette/issues/2649#issuecomment-3962639393

* docs: note that create_token() is now async in upgrade guide

* docs: update internals, plugin_hooks, authentication for new token API

- internals.rst: new async create_token() signature with restrictions
  and handler params, add TokenRestrictions reference docs
- plugin_hooks.rst: show full create_token signature in TokenHandler
  example, note list returns and error cases
- authentication.rst: cross-reference TokenRestrictions from the
  restrictions section

* style: apply black formatting to token handler files

* docs: fix RST heading underline length in internals.rst

* tests: add restrictions round-trip and expiration tests for token handler

Covers allow_database/allow_resource builders, _r payload encoding,
and token_expires in verified actors. Coverage 76% -> 90%.

* tests: add test for signed tokens disabled

* fix: add TokenRestrictions TYPE_CHECKING import to fix ruff F821

* docs: regenerate plugins.rst with cog

* docs: reformat code blocks in plugin_hooks.rst with blacken-docs

* docs: add await .verify_token() to internals.rst

* tests: rewrite register_token_handler test to use real plugin handler

Adds a HardcodedTokenHandler to the test plugins dir that creates
tokens like dstok_hardcoded_token_1. The test now exercises creating
tokens via the default handler (which is the plugin's hardcoded one),
by explicitly naming the hardcoded handler, and by explicitly naming
the signed handler -- then verifies each token round-trips correctly.

* tests: clarify test_token_handler_via_http tests the default signed handler

* fix: use handler="signed" explicitly where signed tokens are expected

The HardcodedTokenHandler in my_plugin.py gets globally registered,
so create_token() without a handler name picks it up as the default.
Fix the create-token view, CLI, and tests to explicitly request the
signed handler where they depend on signed token behavior.

* fix: use handler="signed" in test_create_table_permissions

https://claude.ai/code/session_013cQFiDQjYRrRBH2biFfKuS
2026-02-25 16:32:45 -08:00
..
_static Add favicon to documentation (#1967) 2022-12-31 11:00:31 -08:00
_templates Drop jQuery dependency 2023-03-26 16:38:58 -07:00
.gitignore Added initial docs, including a changelog 2017-11-16 07:11:00 -08:00
authentication.rst register_token_handler() plugin hook for custom API token backends (#2650) 2026-02-25 16:32:45 -08:00
auto-build.sh Added --load-extension argument to datasette serve 2017-11-16 08:48:49 -08:00
binary_data.rst Use shot-scraper images from datasette-screenshots repo, closes #1844 2022-10-14 12:57:00 -07:00
changelog.rst Release 1.0a24 2026-01-29 09:00:22 -08:00
cli-reference.rst datasette serve --default-deny option (#2593) 2025-11-12 16:14:21 -08:00
codespell-ignore-words.txt Move Metadata to --internal database 2024-06-11 09:33:23 -07:00
conf.py Enable MyST Markdown docs, port events.rst, refs #2565 2025-10-31 16:38:04 -07:00
configuration.rst Configuration via the command-line section 2024-02-05 13:43:50 -08:00
contributing.rst dependency-groups and uv (#2611) 2025-12-11 17:32:58 -08:00
csv_export.rst Use shot-scraper images from datasette-screenshots repo, closes #1844 2022-10-14 12:57:00 -07:00
custom_templates.rst New .core CSS class for inputs and buttons 2024-09-03 08:37:26 -07:00
datasette-0.51.png Release 0.51 2020-10-31 15:21:49 -07:00
datasette-logo.svg Added new logo to the documentation 2020-07-12 12:53:29 -07:00
deploying.rst Add test for RST heading underline lengths, closes #2544 2025-10-26 09:49:49 -07:00
ecosystem.rst Shrunk ecosystem docs in favour of datasette.io, closes #1182 2021-01-09 14:17:18 -08:00
events.md Enable MyST Markdown docs, port events.rst, refs #2565 2025-10-31 16:38:04 -07:00
facets.rst Move non-metadata configuration from metadata.yaml to datasette.yaml 2023-10-12 09:16:37 -07:00
full_text_search.rst Move non-metadata configuration from metadata.yaml to datasette.yaml 2023-10-12 09:16:37 -07:00
getting_started.rst Replace Glitch with Codespaces, closes #2488 2025-05-28 19:17:22 -07:00
index.rst Removed broken refs to Glitch, closes #2503 2025-09-28 21:15:58 -07:00
installation.rst Python 3.14, drop Python 3.9 2025-10-08 13:11:32 -07:00
internals.rst register_token_handler() plugin hook for custom API token backends (#2650) 2026-02-25 16:32:45 -08:00
introspection.rst Implement resource-based permission system with SQL-driven access control 2025-10-24 10:32:18 -07:00
javascript_plugins.rst JavaScript plugins documentation, closes #2250 2024-02-05 11:47:17 -08:00
json_api.rst Fixed some rST labels I broke 2025-10-31 09:15:39 -07:00
Makefile Added documentation on the Datasette Ecosystem 2019-01-31 19:36:07 -08:00
metadata.rst Removed units functionality and Pint dependency 2024-08-20 19:03:33 -07:00
metadata_doc.py Rename metadata tables and add schema to docs, refs #2382 2024-08-05 13:53:55 -07:00
pages.rst /-/schema and /db/-/schema and /db/table/-/schema pages (plus .json/.md) 2025-11-07 12:01:23 -08:00
performance.rst Release 0.63a1 2022-10-23 20:07:09 -07:00
plugin_hooks.rst register_token_handler() plugin hook for custom API token backends (#2650) 2026-02-25 16:32:45 -08:00
plugins.rst register_token_handler() plugin hook for custom API token backends (#2650) 2026-02-25 16:32:45 -08:00
publish.rst Remove all remaining "$ " prefixes from docs, closes #2140 2023-08-11 10:44:34 -07:00
settings.rst Fix permissions_execute_sql warnings in documentation 2025-11-01 11:52:23 -07:00
spatialite.rst blacken-docs 2026-02-20 11:28:39 -08:00
sql_queries.rst Fix permissions_execute_sql warnings in documentation 2025-11-01 11:52:23 -07:00
testing_plugins.rst blacken-docs 2026-02-20 11:28:39 -08:00
upgrade-1.0a20.md Fix for link from changelog not working 2025-11-03 14:38:57 -08:00
upgrade_guide.md register_token_handler() plugin hook for custom API token backends (#2650) 2026-02-25 16:32:45 -08:00
writing_plugins.rst New .core CSS class for inputs and buttons 2024-09-03 08:37:26 -07:00