Default url customising

Is it possible to customize c.JupyterHub.default_url depending on username or user group. So, main idea is to navigate different users (depending on their roles) to different pages.

According to Application configuration — JupyterHub 1.5.0 documentation you can use a callable function.

If that’s not suitable then c.Spawner.default_url is a property of the spawner, which means it can be configured independently for each user

@manics question re: c.JupyterHub.default_url. I’m using a callable to determine whether the user is an admin or not and accessing the user by user = handler.current_user.

Most of the time the user is None, even when I’m logged in via OAuth. When I do some clicking in jupyterhub around it gets my username properly.

Is there a way to reliably get the user?

I would use the Spawner as that always gets the user, but it’s not available in the handler that’s passed to c.JupyterHub.default_url.

What version of JupyterHub are you using? Can you share your configuration? Can you turn on debug logging and show us the logs?

@manics I’m using 4.0.2.

Any chance I can send logs privately? Happy to post resolution here of course.

In spawner you can get current user from self.user.name attribute if I am not wrong. You dont need to access it from handler

@mahendrapaipuri understood, but I don’t believe the spawner is passed to c.JupyterHub.default_url

@Benjamin_Leff Yes, you are right! I overlooked it and I thought it is about default_url in Spawner object. Sorry about it!

It is strange that you get None object for the user. We use the callable as well for default_url to determine if user is admin or not and it works well. The difference is that we use our custom LDAP authenticator and not OAuth.

JupyterHub determines the current user in prepare step of each request and here is the snippet on how it determines the user. In most of the cases it identifies the user from cookie. So you can check if JupyterHub is setting cookie properly upon authentication before you click anything.

default_url will get the user if the request is authenticated. If you aren’t seeing that, my guess is that it’s because default_url is being called before the user is authenticated, and is being persisted through login, redirects via the ?next url parameter, so the value doesn’t get recomputed after authentication has completed.

Try sending unauthenticated users directly to /hub/login, which will result in computing default_url again after successful login, for example:

def default_url(handler):
    user = handler.current_user
    if not user:
        # not logged in, send to login, no ?next
        # that way, default_url will be called again after successful login
        return handler.get_login_url()
    if "admin-ui" in handler.expanded_scopes:
        # has permission to view the admin page, send there
        return handler.base_url + "hub/admin"
    else:
        # regular user, send to spawn page
        # (which redirects to running user if it's running)
        # this is the default default URL
        return handler.base_url + "hub/spawn"

c.JupyterHub.default_url = default_url

complete example jupyterhub_config.py

2 Likes

I would like to do a slightly different task. I get is_instructor and selected_course from user_options in the pre_spawning_hook and would like to redirect the user to the service which corresponds to that selected_course if the is_instructor is true for that user.
I already tried the below pre_spawner_hook but it didn’t work

  # some code here to get selected_course and is_instructor based on user_options
  if is_instructor:
                  c.JupyterHub.default_url = f'/services/{selected_course}/lab'

here is how the services are initialized:

base_port = 9000
for idx, course in enumerate(courses):
  c.JupyterHub.services.append(
            {
              "name": course,
              "url": f"http://course-svc:{base_port + idx}",
              "command": ["jupyterhub-singleuser", f"--group=formgrade-{course}", f"--port={base_port + idx}", "--debug", "--ServerApp.ip=0.0.0.0"],
              "cwd": f"/mnt/exchange/{course}",
              "oauth_no_confirm": True,
              "environment" : {
                # Here nbgrader.auth.JupyterHubAuthPlugin needs a user, that always exists
                "JUPYTERHUB_USER": "admin",
                'JUPYTERHUB_DEFAULT_URL': '/lab'
              }
            }
          )

Exactly what I needed. Thank you, thank you @minrk !

This very same snippet didn’t work for me in z2jh hub.extraConfig part. I even placed some print statement but i didn’t get any print:

hub:
  extraConfig:
    init: |
      def default_url(handler):
          user = handler.current_user
          printd(f'user: {user} handler.based_url: {handler.base_url} {"admin-ui" in handler.expanded_scopes}')
          if not user:
            return handler.get_login_url()
          if "admin-ui" in handler.expanded_scopes:
            return handler.base_url + "hub/admin"
          else:
            return handler.base_url + "hub/spawn"
      c.JupyterHub.default_url = default_url

while it’s pulling image it’s on /hub/spawn-pending/username and then it still lands on /user/username/lab

I have no other default_url in the configuration.