JupyterHub provides four (4) roles that are available by default:

Default roles

  • user role provides a default user scope self that grants access to the user’s own resources.

  • admin role contains all available scopes and grants full rights to all actions. This role cannot be edited.

  • token role provides a default token scope inherit that resolves to the same permissions as the owner of the token has.

  • server role allows for posting activity of “itself” only.

These roles cannot be deleted.

We call these ‘default’ roles because they are available by default and have a default collection of scopes. However, you can define the scopes associated with each role (excluding the admin role) to suit your needs, as seen below.

The user, admin, and token roles, by default, all preserve the permissions prior to Role-based Access Control (RBAC). Only the server role is changed from pre-2.0, to reduce its permissions to activity-only instead of the default of a full access token.

Additional custom roles can also be defined (see Defining Roles). Roles can be assigned to the following entities:

  • Users

  • Services

  • Groups

An entity can have zero, one, or multiple roles, and there are no restrictions on which roles can be assigned to which entity. Roles can be added to or removed from entities at any time.

When a new user gets created, they are assigned their default role, user. Additionally, if the user is created with admin privileges (via c.Authenticator.admin_users in or admin: true via API), they will be also granted admin role. If existing user’s admin status changes via API or, their default role will be updated accordingly (after next startup for the latter).

Services do not have a default role. Services without roles have no access to the guarded API end-points. So, most services will require assignment of a role in order to function.

A group does not require any role, and has no roles by default. If a user is a member of a group, they automatically inherit any of the group’s permissions (see Resolving roles and scopes for more details). This is useful for assigning a set of common permissions to several users.

A token’s permissions are evaluated based on their owning entity. Since a token is always issued for a user or service, it can never have more permissions than its owner. If no specific scopes are requested for a new token, the token is assigned the scopes of the token role.

Defining Roles#

Roles can be defined or modified in the configuration file as a list of dictionaries. An example:

# in

c.JupyterHub.load_roles = [{
   'name': 'server-rights',
   'description': 'Allows parties to start and stop user servers',
   'scopes': ['servers'],
   'users': ['alice', 'bob'],
   'services': ['idle-culler'],
   'groups': ['admin-group'],}

The role server-rights now allows the starting and stopping of servers by any of the following:

  • users alice and bob

  • the service idle-culler

  • any member of the admin-group.


Tokens cannot be assigned roles through role definition but may be assigned specific roles when requested via API (see Requesting API token with specific scopes).

Another example:

# in

c.JupyterHub.load_roles = [
   'description': 'Read-only user models',
   'name': 'reader',
   'scopes': ['read:users'],
   'services': ['external'],
   'users': ['maria', 'joe']

The role reader allows users maria and joe and service external to read (but not modify) any user’s model.


In a role definition, the name field is required, while all other fields are optional.
Role names must:

  • be 3 - 255 characters

  • use ascii lowercase, numbers, ‘unreserved’ URL punctuation -_.~

  • start with a letter

  • end with letter or number.

users, services, and groups only accept objects that already exist in the database or are defined previously in the file. It is not possible to implicitly add a new user to the database by defining a new role.

If no scopes are defined for new role, JupyterHub will raise a warning. Providing non-existing scopes will result in an error.

In case the role with a certain name already exists in the database, its definition and scopes will be overwritten. This holds true for all roles except the admin role, which cannot be overwritten; an error will be raised if trying to do so. All the role bearers permissions present in the definition will change accordingly.

Overriding Default Roles#

Role definitions can include those of the “default” roles listed above (admin excluded), if the default scopes associated with those roles do not suit your deployment. For example, to specify what permissions the $JUPYTERHUB_API_TOKEN issued to all single-user servers has, define the server role.

To restore the JupyterHub 1.x behavior of servers being able to do anything their owners can do, use the scope inherit (for ‘inheriting’ the owner’s permissions):

c.JupyterHub.load_roles = [
   'name': 'server',
   'scopes': ['inherit'],

or, better yet, identify the specific scopes you want server environments to have access to.

If you don’t want to get too detailed, one option is the self scope, which will have no effect on non-admin users, but will restrict the token issued to admin user servers to only have access to their own resources, instead of being able to take actions on behalf of all other users.

c.JupyterHub.load_roles = [
   'name': 'server',
   'scopes': ['self'],

Removing Roles#

Only the entities present in the role definition in the remain the role bearers. If a user, service or group is removed from the role definition, they will lose the role on the next startup.

Once a role is loaded, it remains in the database until removing it from the and restarting the Hub. All previously defined role bearers will lose the role and associated permissions. Default roles, even if previously redefined through the config file and removed, will not be deleted from the database.