Browser permissions granted to notebooks are too broad

Some notebooks require special browser permssions. For example, here’s a notebook that asks for access to your microphone.

When I grant access to the microphone to this notebook, it also grants microphone permission to notebooks written by other users. (Tested in Chrome.) This seems unfortunate. I’d like to write another notebook that uses a serial port (via a Chrome-specific API), but I’m wary of encouraging people to grant such permissions to all notebooks.

For security, Observable runs all user JavaScript within an iframe whose URL is a user-specific subdomain, but this unfortunately has no effect on the microphone permission, and I assume other browser permissions work similarly. Would running notebooks in separate subdomains in the top level window fix this?

1 Like

Yes, it looks like if we had a per-user domain for the top-level window (in addition to the per-user domain we have for the iframe), that permissions would be scoped per user. So, then the URL for a notebook might be something like

instead of

Another possibility is that Observable could do a separate in-application user prompt to determine whether to add the microphone permission to the allow list for a particular user’s iframe. So, you’d separate prompts for each user (or even notebook) that requests it, in addition to the (one-time) native prompt for Observable as a whole. But to do this we’d have to know, ideally statically, whether a notebook will want a particular permission and I think that would be tricky to do.

Sorry, it looks like there’s no quick fix to this. It would be nice if we could instruct the browser to only grant the permission to the iframe origin rather than tying it to the top-level domain, but it seems unlikely there will be browser support for that in the near future.

1 Like

As far as I can tell this API is not currently allowlisted in the iframe. However, there’s a workaround which will also allow you to grant microphone/video access only for your own notebooks. I’ve written a helper to comfortably grant permissions via a top-level proxy window:

import {request} from '@mootari/powerful-features'
// query button
viewof serial = request(win => win.navigator.serial.getPorts())
// value

Similarly, for microphone access:

viewof audio = request(win => win.navigator.mediaDevices.getUserMedia({audio: true}))