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/699#issuecomment-626945281,https://api.github.com/repos/simonw/datasette/issues/699,626945281,MDEyOklzc3VlQ29tbWVudDYyNjk0NTI4MQ==,9599,2020-05-11T20:32:33Z,2020-05-11T20:32:33Z,OWNER,"I did have a bit of trouble with this one-off plugin getting it to load in the correct order - since I need authentication to work if EITHER the one-off plugin spots a token or my `datasette-auth-github` plugin authenticates the user.
That's why I want authentication as a core Datasette concept - so plugins like these can easily play together in a predictable manner.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",582526961,
https://github.com/simonw/datasette/issues/699#issuecomment-626943809,https://api.github.com/repos/simonw/datasette/issues/699,626943809,MDEyOklzc3VlQ29tbWVudDYyNjk0MzgwOQ==,9599,2020-05-11T20:30:07Z,2020-05-11T20:31:18Z,OWNER,"I implemented bearer tokens in a private project of mine as a one-off plugin. I'm going to extract that out into a installable plugin soon. For the moment, my `plugins/token_auth.py` file looks like this:
```python
from datasette import hookimpl
import secrets
class TokenAuth:
def __init__(
self, app, secret, auth,
):
self.app = app
self.secret = secret
self.auth = auth
async def __call__(self, scope, receive, send):
if scope.get(""type"") != ""http"":
return await self.app(scope, receive, send)
authorization = dict(scope.get(""headers"") or {}).get(b""authorization"") or b""""
expected = ""Bearer {}"".format(self.secret).encode(""utf8"")
if secrets.compare_digest(authorization, expected):
scope = dict(scope, auth=self.auth)
return await self.app(scope, receive, send)
@hookimpl(trylast=True)
def asgi_wrapper(datasette):
config = datasette.plugin_config(""token-auth"") or {}
secret = config.get(""secret"")
auth = config.get(""auth"")
def wrap_with_asgi_auth(app):
return TokenAuth(app, secret=secret, auth=auth,)
return wrap_with_asgi_auth
```
Then I have the following in `metadata.json`:
```json
{
""plugins"": {
""token-auth"": {
""auth"": {
""name"": ""token-bot""
},
""secret"": {
""$env"": ""TOKEN_SECRET""
}
}
}
}
```
And a `TOKEN_SECRET` environment variable.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",582526961,