Allow jupyter-server-proxy from another origin

Hi Everyone,

I’m looking for some help or pointers on what I think is a configuration that I should be doing to jupyter-server-proxy.

TL;DR can jupyter-server-proxy be made to serve to a different origin?
TL;DR2 is some other jhub auth behaviour causing this and not the proxy as I am assuming?

Some Context

  • I have a notebook that uses the pyvista library for 3D visualisation using the trame server backend.
  • The pyvista “widget” creates an iframe, pointing back to the notebook server, relying on juptyer-server-proxy to serve the target html page
  • I am including this notebook in a MyST markdown site, that is backed by a BinderHub, so I have BinderHub providing a single user server for this myst markdown website – but the myst website runs on a different origin to the hub/single-user server

The Problem

  • When I run the code in a myst website, in the iframe appears the well known Jupyter enter token or set password screen
  • if in a separate tab I go the the single user server and open lab, I can execute the notebook as expected and the iframe contents appear
  • if in a separate tab I then paste the src url from the iframe, the page opens as expected (as I have a cookie set by the previous visit)

To get to this point I have added the following configuration to my local test instance:

jupyterhub_config.py

c.LocalContainerSpawner.cmd = "jupyter-server"
c.LocalContainerSpawner.args = ['--NotebookApp.tornado_settings={"headers":{"Content-Security-Policy": "frame-ancestors *;"}, "Access-Control-Allow-Origin": "*"}']
c.LocalContainerSpawner.cors_allow_origin = "*"
c.LocalContainerSpawner.environment = {
    "CN_JUPYTER_SERVER_BASE_URL": "http://192.168.0.119:8000/",
}
c.Spawner.cors_allow_origin = "*"
c.JupyterHub.tornado_settings = {'headers': {'Content-Security-Policy': "frame-ancestors *;", 'Access-Control-Allow-Origin': '*'}}

jupyter_notebook_config.py


c.NotebookApp.allow_origin = "*"
c.NotebookApp.allow_credentials = True
c.NotebookApp.disable_check_xsrf = True
c.NotebookApp.tornado_settings = {
    "headers": {"Content-Security-Policy": "frame-ancestors 'self' *"},
}

def allow_all_hosts(host):
    print(f"Allowing host: {host}")
    return True

c.ServerProxy.host_allowlist = [allow_all_hosts]

I am also ensuring that the iframe src url includes a &token=xxxxx parameter by using GitHub - curvenote/jupyter-server-user-token: Jupyter Server extension that adds a user server token to the environment to get it into the user’s environment.

Note that I have also tested with a plain iframe in the notebook, pointing back to the page served by the proxy with the same problem.

I’d appreciate any thoughts or pointers on how to get this working, or if there is a different approach I could take.

Thanks
Steve

It might be the proxied app inside the frame (pyvista?) that needs to set some headers to allow it to be embedded. jupyter-server-proxy doesn’t override the proxied app’s headers. Does your browser console report any security issues with the iframe or origin?

An easy way to rule out jupyter-server-proxy should be to proxy a plain http server, e.g. python -mhttp.server <PORT> and see if that works. I’ve tried it with a standalone JupyterLab and it works, but it fails if I run an application that prevents embedding.

1 Like

@jourdain, any ideas here?

1 Like

Thanks @manics for the idea!

I’ve just tried that in my local setup here and indeed I can serve a plain html back using http.server and get the iframe displayed in page ok.

And if I remove the token query arg, I get redirected to the login screen as expected!

So all the hub/proxy setup is ok (albeit OTT as I probably have redundant options set) and this points to the response from the trame server causing the redirect to the login page.

@jourdain is there some type of same origin constraint in trame and is there a way around it?

Note that this is using the jupyter-server-proxy as I’ve not yet been able to get trame-jupyter-extension to work either in notebooks (just get spinners) or on page with myst (no output).

(my test notebooks fwiw GitHub - stevejpurves/pyvista-test)

If you know what the problematic or missing headers are jupyter-server-proxy has a rewrite_response option. It’s currently missing from the docs, but you can use the test config as an example:

This will only work for services managed by jupyter-server-proxy, you can’t use it with /proxy/<PORT>/

1 Like

We may have been too eager to enable that for our VTK/WASM integration. If wasm is not in use, we can skip it. In fact if you pull the latest wslink that should remove that constraint.

HTH