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-626991001,https://api.github.com/repos/simonw/datasette/issues/699,626991001,MDEyOklzc3VlQ29tbWVudDYyNjk5MTAwMQ==,8431341,2020-05-11T22:06:34Z,2020-05-11T22:06:34Z,NONE,Very nice! Thank you for sharing that :+1: :) Will try it out!,"{""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-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, https://github.com/simonw/datasette/issues/699#issuecomment-626807487,https://api.github.com/repos/simonw/datasette/issues/699,626807487,MDEyOklzc3VlQ29tbWVudDYyNjgwNzQ4Nw==,8431341,2020-05-11T16:23:57Z,2020-05-11T16:24:59Z,NONE,`Authorization: bearer xxx` auth for API keys is a plus plus for me. Looked into just adding this into your `Flask` logic but learned this project doesn't use flask. Interesting 🤔,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",582526961,