observablehq / feedback

Customer submitted bugs and feature requests
42 stars 3 forks source link

A pattern for storing API secrets, maybe even obtained via OAuth #350

Open simonw opened 2 years ago

simonw commented 2 years ago

I really like using Observable notebooks to explore web APIs, often that require some kind of API key.

With private notebooks I can just embed my API key in the notebook - but I also like the option to share my notebooks with other people - without having to give them my secret API key.

I've solved this in the past by including an input field that they can paste their API key into - but ideally I'd like to then persist that secret API key so they don't have to paste it in every time they interact with the notebook.

@tophtucker built this example for me which helps a lot: https://observablehq.com/@tophtucker/give-a-user-a-persistent-personal-key-for-a-notebook

The more advanced thing I want to be able to do is build notebooks that can participate in an OAuth flow. I'd like to be able to link from my notebook to an OAuth consent page somewhere, then have that other website configured to redirect the user BACK to the notebook after they authenticate - then I would take the code returned in the query seeing, exchange it for an access token, store that access token in local storage and use it to make API calls.

I tried to implement this a few years ago and ran into a problem - sadly I don't have notes on what caught me out there. So maybe this is possible already?

TLDR of the above: I want it to be as easy as possible to build notebooks that interact with private APIs using API tokens, stored securely on behalf of my users and potentially obtained from OAuth flows.

simonw commented 2 years ago

I just tried building a prototype notebook that uses the GitHub OAuth API - https://observablehq.com/@simonw/github-oauth-prototype - and quickly realized why it's not currently feasible to build such a thing in a notebook: the second step in the GitHub OAuth flow requires I exchange the ?code= parameter that GitHub sent me by POSTing the following:

parameter type description
client_id string Required. The client ID you received from GitHub for your OAuth App.
client_secret string Required. The client secret you received from GitHub for your OAuth App.
code string Required. The code you received as a response to Step 1.
redirect_uri string The URL in your application where users are sent after authorization.

I'm not willing to include my client_secret in a public notebook, so this flow doesn't work for me.

https://docs.github.com/en/developers/apps/building-oauth-apps/authorizing-oauth-apps#2-users-are-redirected-back-to-your-site-by-github

Maybe this is a lost cause, and there's no sensible way to build a notebook that can be authenticated against using OAuth from the GitHub API. That would be a shame though!

mbostock commented 2 years ago

Here’s one approach by Tom Larkworthy:

https://observablehq.com/@tomlarkworthy/oauth https://observablehq.com/@endpointservices/secrets

It would be nice to have first-party support for this sort of thing.

tomlarkworthy commented 2 years ago

I tend to link to the oauth-examples which includes a working Github login https://observablehq.com/@tomlarkworthy/oauth-examples you can prod and poke (but not fork as that invalidates the redirect URL!)

The client_secret ends up in my cloud account though, I am open to figuring out a different solution if you have some ideas, the serverside container runtime enabling it all is not against self hosting, for instance https://github.com/endpointservices/webcode.run