html_url,issue_url,id,node_id,user,created_at,updated_at,author_association,body,reactions,issue,performed_via_github_app
https://github.com/simonw/datasette/issues/1855#issuecomment-1347761892,https://api.github.com/repos/simonw/datasette/issues/1855,1347761892,IC_kwDOBm6k_c5QVTbk,9599,2022-12-13T05:14:25Z,2022-12-13T05:14:25Z,OWNER,New documentation: https://docs.datasette.io/en/latest/authentication.html#restricting-the-actions-that-a-token-can-perform,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1423336089,
https://github.com/simonw/datasette/issues/1855#issuecomment-1347759522,https://api.github.com/repos/simonw/datasette/issues/1855,1347759522,IC_kwDOBm6k_c5QVS2i,9599,2022-12-13T05:11:43Z,2022-12-13T05:11:43Z,OWNER,"Decided to do the `/-/create-token` UI in a separate ticket:
- #1947","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1423336089,
https://github.com/simonw/datasette/issues/1855#issuecomment-1347731288,https://api.github.com/repos/simonw/datasette/issues/1855,1347731288,IC_kwDOBm6k_c5QVL9Y,9599,2022-12-13T04:24:50Z,2022-12-13T04:24:50Z,OWNER,For the tests for `datasette create-token` it would be useful if `datasette --get` had a mechanism for sending an `Authorization: Bearer X` header.,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1423336089,
https://github.com/simonw/datasette/issues/1855#issuecomment-1347726302,https://api.github.com/repos/simonw/datasette/issues/1855,1347726302,IC_kwDOBm6k_c5QVKve,9599,2022-12-13T04:16:26Z,2022-12-13T04:16:26Z,OWNER,I'm going to move this code into `datasette/cli.py` - it's a bit unexpected having it live in `default_permissions.py` like this (I couldn't find the code when I went looking for it earlier).,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1423336089,
https://github.com/simonw/datasette/issues/1855#issuecomment-1347707683,https://api.github.com/repos/simonw/datasette/issues/1855,1347707683,IC_kwDOBm6k_c5QVGMj,9599,2022-12-13T03:55:35Z,2022-12-13T04:15:27Z,OWNER,"Help looks like this:
```
Usage: datasette create-token [OPTIONS] ID
Create a signed API token for the specified actor ID
Example:
datasette create-token root --secret mysecret
To only allow create-table:
datasette create-token root --secret mysecret \
--all create-table
Or to only allow insert-row against a specific table:
datasette create-token root --secret myscret \
--resource mydb mytable insert-row
Restricted actions can be specified multiple times using multiple --all,
--database, and --resource options.
Add --debug to see a decoded version of the token.
Options:
--secret TEXT Secret used for signing the API tokens
[required]
-e, --expires-after INTEGER Token should expire after this many seconds
-a, --all ACTION Restrict token to this action
-d, --database DB ACTION Restrict token to this action on this
database
-r, --resource DB RESOURCE ACTION
Restrict token to this action on this
database resource (a table, SQL view or
named query)
--debug Show decoded token
--plugins-dir DIRECTORY Path to directory containing custom plugins
--help Show this message and exit.
```","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1423336089,
https://github.com/simonw/datasette/issues/1855#issuecomment-1347695728,https://api.github.com/repos/simonw/datasette/issues/1855,1347695728,IC_kwDOBm6k_c5QVDRw,9599,2022-12-13T03:30:09Z,2022-12-13T03:30:09Z,OWNER,"I just noticed this in the existing code:
https://github.com/simonw/datasette/blob/c5d30b58a1cd1c66bbddcf3561db005543ecaf25/datasette/default_permissions.py#L195-L203
Hard-coding those action names should not be necessary any more, especially now we have `datasette.permissions` for looking up metadata about the permissions.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1423336089,
https://github.com/simonw/datasette/issues/1855#issuecomment-1347694871,https://api.github.com/repos/simonw/datasette/issues/1855,1347694871,IC_kwDOBm6k_c5QVDEX,9599,2022-12-13T03:28:15Z,2022-12-13T03:28:15Z,OWNER,"Initial prototype of the `create-token` command changes:
```diff
diff --git a/datasette/default_permissions.py b/datasette/default_permissions.py
index 406dae40..bbe1247e 100644
--- a/datasette/default_permissions.py
+++ b/datasette/default_permissions.py
@@ -278,17 +278,55 @@ def register_commands(cli):
help=""Token should expire after this many seconds"",
type=int,
)
+ @click.option(
+ ""alls"",
+ ""-a"",
+ ""--all"",
+ type=str,
+ multiple=True,
+ help=""Restrict token to this permission"",
+ )
+ @click.option(
+ ""databases"",
+ ""-d"",
+ ""--database"",
+ type=(str, str),
+ multiple=True,
+ help=""Restrict token to this permission on this database"",
+ )
+ @click.option(
+ ""resources"",
+ ""-r"",
+ ""--resource"",
+ type=(str, str, str),
+ multiple=True,
+ help=""Restrict token to this permission on this database resource (a table, SQL view or named query)"",
+ )
@click.option(
""--debug"",
help=""Show decoded token"",
is_flag=True,
)
- def create_token(id, secret, expires_after, debug):
+ def create_token(id, secret, expires_after, alls, databases, resources, debug):
""Create a signed API token for the specified actor ID""
ds = Datasette(secret=secret)
bits = {""a"": id, ""token"": ""dstok"", ""t"": int(time.time())}
if expires_after:
bits[""d""] = expires_after
+ if alls or databases or resources:
+ bits[""_r""] = {}
+ if alls:
+ bits[""_r""][""a""] = list(alls)
+ if databases:
+ bits[""_r""][""d""] = {}
+ for database, action in databases:
+ bits[""_r""][""d""].setdefault(database, []).append(action)
+ if resources:
+ bits[""_r""][""r""] = {}
+ for database, table, action in resources:
+ bits[""_r""][""r""].setdefault(database, {}).setdefault(
+ table, []
+ ).append(action)
token = ds.sign(bits, namespace=""token"")
click.echo(""dstok_{}"".format(token))
if debug:
```
Still needs tests, plus I'd like it to use abbreviations if available to keep the token length shorter.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1423336089,
https://github.com/simonw/datasette/issues/1855#issuecomment-1347693620,https://api.github.com/repos/simonw/datasette/issues/1855,1347693620,IC_kwDOBm6k_c5QVCw0,9599,2022-12-13T03:25:41Z,2022-12-13T03:25:41Z,OWNER,"I'm going to rename ""t"" in the magic format to ""r"" for resource.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1423336089,
https://github.com/simonw/datasette/issues/1855#issuecomment-1347675456,https://api.github.com/repos/simonw/datasette/issues/1855,1347675456,IC_kwDOBm6k_c5QU-VA,9599,2022-12-13T02:57:46Z,2022-12-13T02:57:46Z,OWNER,"I was going to have the CLI command throw an error if you attempt to use a permission that isn't registered with Datasette, but then I remembered that one of the uses for the CLI tool is to create signed tokens that will work against other Datasette instances (via the `--secret` option) that might have different plugins installed that register different permission names.
So I might have it output warnings instead.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1423336089,
https://github.com/simonw/datasette/issues/1855#issuecomment-1313148519,https://api.github.com/repos/simonw/datasette/issues/1855,1313148519,IC_kwDOBm6k_c5ORQ5n,9599,2022-11-14T06:13:43Z,2022-12-13T02:46:51Z,OWNER,"The `datasette create-token` command will need to be able to do this too.
Right now that command looks like this:
```
% datasette create-token --help
Usage: datasette create-token [OPTIONS] ID
Create a signed API token for the specified actor ID
Options:
--secret TEXT Secret used for signing the API tokens
[required]
-e, --expires-after INTEGER Token should expire after this many seconds
--debug Show decoded token
--help Show this message and exit.
```
```
% datasette create-token root --secret sec --debug -e 445
dstok_eyJhIjoicm9vdCIsInRva2VuIjoiZHN0b2siLCJ0IjoxNjY4NDA2MjEzLCJkIjo0NDV9.Hd6qRli6xRKkOIRQgZkPO5iN1wM
Decoded:
{
""a"": ""root"",
""token"": ""dstok"",
""t"": 1668406213,
""d"": 445
}
```
(The `--debug` bit adds the decoded token.)
Syntax for adding ""insert row"" for everything, ""update row"" for all in the ""data"" database and ""delete row"" just for the docs / titles table:
```
datasette create-token root --secret sec \
--all insert-row \
--database data update-row \
--table docs titles delete-row
```
The `ir` / `ur` / `dr` options would work too. To add multiple permissions use these options multiple times:
```
datasette create-token root --secret sec \
--all insert-row \
--all delete-row
```
Short versions: `-a` and `-d` and `-t`.
UPDATE: I have decided to use the term `resource` in the user-facing elements of this feature instead of `table`, since that can refer to a SQL view and a canned query as well.
So `--resource` and `-r`, not `-t`.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1423336089,
https://github.com/simonw/datasette/issues/1855#issuecomment-1347669087,https://api.github.com/repos/simonw/datasette/issues/1855,1347669087,IC_kwDOBm6k_c5QU8xf,9599,2022-12-13T02:45:15Z,2022-12-13T02:45:15Z,OWNER,The hardest piece here is the UI. I'm going to implement the CLI command first.,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1423336089,