diff --git a/docs/environment.yml b/docs/environment.yml index eb6f5793..b23b5601 100644 --- a/docs/environment.yml +++ b/docs/environment.yml @@ -17,7 +17,7 @@ dependencies: - pip: - entrypoints - oauthlib>=2.0 - - recommonmark==0.4.0 + - recommonmark==0.5.0 - async_generator - prometheus_client - attrs>=17.4.0 diff --git a/docs/requirements.txt b/docs/requirements.txt index 046a6a69..5f8b447a 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -2,6 +2,6 @@ # if you change this file -r ../requirements.txt alabaster_jupyterhub -recommonmark==0.4.0 +recommonmark==0.5.0 sphinx-copybutton sphinx>=1.7 diff --git a/docs/source/api/spawner.rst b/docs/source/api/spawner.rst index 9c5f5a9d..77ff34e0 100644 --- a/docs/source/api/spawner.rst +++ b/docs/source/api/spawner.rst @@ -13,7 +13,7 @@ Module: :mod:`jupyterhub.spawner` ---------------- .. autoconfigurable:: Spawner - :members: options_from_form, poll, start, stop, get_args, get_env, get_state, template_namespace, format_string + :members: options_from_form, poll, start, stop, get_args, get_env, get_state, template_namespace, format_string, create_certs, move_certs :class:`LocalProcessSpawner` ---------------------------- diff --git a/docs/source/changelog.md b/docs/source/changelog.md index 50b53679..c02422e9 100644 --- a/docs/source/changelog.md +++ b/docs/source/changelog.md @@ -7,6 +7,145 @@ command line for details. ## [Unreleased] +## 1.0 + +### [1.0.0] 2018-03-XX + +JupyterHub 1.0 is a major milestone for JupyterHub. +Huge thanks to the many people who have contributed to this release, +whether it was through discussion, testing, documentation, or development. + +#### Major new features + +- Support TLS encryption and authentication of all internal communication. + Spawners must implement `.move_certs` method to make certificates available + to the notebook server if it is not local to the Hub. +- There is now full UI support for managing named servers. + With named servers, each jupyterhub user may have access to more than one named server. For example, a professor may access a server named `research` and another named `teaching`. + + ![named servers on the home page](./images/named-servers-home.png) +- Authenticators can now expire and refresh authentication data by implementing + `Authenticator.refresh_user(user)`. + This allows things like OAuth data and access tokens to be refreshed. + When used together with `Authenticator.refresh_pre_spawn = True`, + auth refresh can be forced prior to Spawn, + allowing the Authenticator to *require* that authentication data is fresh + immediately before the user's server is launched. + +```eval_rst +.. seealso:: + + - :meth:`.Authenticator.refresh_user` + - :meth:`.Spawner.create_certs` + - :meth:`.Spawner.move_certs` +``` + +#### New features + +- allow custom spawners, authenticators, and proxies to register themselves via 'entry points', enabling more convenient configuration such as: + + ```python + c.JupyterHub.authenticator_class = 'github' + c.JupyterHub.spawner_class = 'docker' + c.JupyterHub.proxy_class = 'traefik_etcd' + ``` +- Spawners are passed the tornado Handler object that requested their spawn (as `self.handler`), + so they can do things like make decisions based on query arguments in the request. +- SimpleSpawner and DummyAuthenticator, which are useful for testing, have been merged into JupyterHub itself: + + ```python + # For testing purposes only. Should not be used in production. + c.JupyterHub.authenticator_class = 'dummy' + c.JupyterHub.spawner_class = 'simple' + ``` + + These classes are **not** appropriate for production use. Only testing. +- Add health check endpoint at `/hub/health` +- Several prometheus metrics have been added (thanks to [Outreachy](https://www.outreachy.org/) applicants!) +- A new API for registering user activity. + To prepare for the addition of [alternate proxy implementations](https://github.com/jupyterhub/traefik-proxy), + responsibility for tracking activity is taken away from the proxy + and moved to the notebook server (which already has activity tracking features). + Activity is now tracked by pushing it to the Hub from user servers instead of polling the + proxy API. +- Dynamic `options_form` callables may now return an empty string + which will result in no options form being rendered. +- `Spawner.user_options` is persisted to the database to be re-used, + so that a server spawned once via the form can be re-spawned via the API + with the same options. +- Added `c.PAMAuthenticator.pam_normalize_username` option for round-tripping + usernames through PAM to retrieve the normalized form. +- Added `c.JupyterHub.named_server_limit_per_user` configuration to limit + the number of named servers each user can have. + The default is 0, for no limit. +- API requests to HubAuthenticated services (e.g. single-user servers) + may pass a token in the `Authorization` header, + matching authentication with the Hub API itself. +- Added `Authenticator.is_admin(handler, authentication)` method + and `Authenticator.admin_groups` configuration for automatically + determining that a member of a group should be considered an admin. +- New `c.Authenticator.post_auth_hook` configuration + that can be any callable of the form `async def hook(authenticator, handler, authentication=None):`. + This hook may transform the return value of `Authenticator.authenticate()` + and return a new authentication dictionary, + e.g. specifying admin privileges, group membership, + or custom white/blacklisting logic. + This hook is called *after* existing normalization and whitelist checking. +- `Spawner.options_from_form` may now be async +- Added `JupyterHub.shutdown_on_logout` option to trigger shutdown of a user's + servers when they log out. + + +#### Changes + +- Authentication methods such as `check_whitelist` should now take an additional + `authentication` argument + that will be a dictionary (default: None) of authentication data, + as returned by `Authenticator.authenticate()`: + + ```python + def check_whitelist(self, username, authentication=None): + ... + ``` + + `authentication` should have a default value of None + for backward-compatibility with jupyterhub < 1.0. +- Prometheus metrics page is now authenticated. + Any authenticated user may see the prometheus metrics. + To disable prometheus authentication, + set `JupyterHub.authenticate_prometheus = False`. +- Visits to `/user/:name` no longer trigger an implicit launch of the user's server. + Instead, a page is shown indicating that the server is not running + with a link to request the spawn. +- API requests to `/user/:name` for a not-running server will have status 503 instead of 404. +- OAuth includes a confirmation page when attempting to visit another user's server, + so that users can choose to cancel authentication with the single-user server. + Confirmation is still skipped when accessing your own server. + + +#### Fixed + +- Various fixes to improve Windows compatibility + (default Authenticator and Spawner still do not support Windows, but other Spawners may) +- Fixed compatibility with Oracle db +- Fewer redirects following a visit to the default `/` url +- Error when progress is requested before progress is ready +- Error when API requests are made to a not-running server without authentication + +#### Development changes + +There have been several changes to the development process that shouldn't +generally affect users of JupyterHub, but may affect contributors. +In general, see `CONTRIBUTING.md` for contribution info or ask if you have questions. + +- JupyterHub has adopted `black` as a code autoformatter and `pre-commit` + as a tool for automatically running code formatting on commit. + This is meant to make it *easier* to contribute to JupyterHub, + so let us know if it's having the opposite effect. +- JupyterHub has switched its test suite to using `pytest-asyncio` from `pytest-tornado`. +- OAuth is now implemented internally using `oauthlib` instead of `python-oauth2`. This should have no effect on behavior. + + ## 0.9 ### [0.9.4] 2018-09-24 @@ -426,7 +565,8 @@ Fix removal of `/login` page in 0.4.0, breaking some OAuth providers. First preview release -[Unreleased]: https://github.com/jupyterhub/jupyterhub/compare/0.9.4...HEAD +[Unreleased]: https://github.com/jupyterhub/jupyterhub/compare/1.0.0...HEAD +[1.0.0]: https://github.com/jupyterhub/jupyterhub/compare/0.9.4...HEAD [0.9.4]: https://github.com/jupyterhub/jupyterhub/compare/0.9.3...0.9.4 [0.9.3]: https://github.com/jupyterhub/jupyterhub/compare/0.9.2...0.9.3 [0.9.2]: https://github.com/jupyterhub/jupyterhub/compare/0.9.1...0.9.2 diff --git a/docs/source/conf.py b/docs/source/conf.py index 4f82adba..2e2e2087 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -56,6 +56,16 @@ default_role = 'literal' # -- Source ------------------------------------------------------------- +import recommonmark +from recommonmark.transform import AutoStructify + + +def setup(app): + app.add_config_value('recommonmark_config', {'enable_eval_rst': True}, True) + app.add_stylesheet('custom.css') + app.add_transform(AutoStructify) + + source_parsers = {'.md': 'recommonmark.parser.CommonMarkParser'} source_suffix = ['.rst', '.md'] diff --git a/docs/source/getting-started/config-basics.md b/docs/source/getting-started/config-basics.md index f25f69e1..47850ac9 100644 --- a/docs/source/getting-started/config-basics.md +++ b/docs/source/getting-started/config-basics.md @@ -1,7 +1,7 @@ # Configuration Basics The section contains basic information about configuring settings for a JupyterHub -deployment. The [Technical Reference](../reference/index.html) +deployment. The [Technical Reference](../reference/index) documentation provides additional details. This section will help you learn how to: @@ -44,7 +44,7 @@ jupyterhub -f /etc/jupyterhub/jupyterhub_config.py ``` The IPython documentation provides additional information on the -[config system](http://ipython.readthedocs.io/en/stable/development/config.html) +[config system](http://ipython.readthedocs.io/en/stable/development/config) that Jupyter uses. ## Configure using command line options @@ -61,7 +61,7 @@ would enter: ```bash jupyterhub --ip 10.0.1.2 --port 443 --ssl-key my_ssl.key --ssl-cert my_ssl.cert -``` +``` All configurable options may technically be set on the command-line, though some are inconvenient to type. To set a particular configuration @@ -77,10 +77,10 @@ jupyterhub --Spawner.notebook_dir='~/assignments' ## Configure for various deployment environments The default authentication and process spawning mechanisms can be replaced, and -specific [authenticators](./authenticators-users-basics.html) and -[spawners](./spawners-basics.html) can be set in the configuration file. +specific [authenticators](./authenticators-users-basics) and +[spawners](./spawners-basics) can be set in the configuration file. This enables JupyterHub to be used with a variety of authentication methods or -process control and deployment environments. [Some examples](../reference/config-examples.html), +process control and deployment environments. [Some examples](../reference/config-examples), meant as illustration, are: - Using GitHub OAuth instead of PAM with [OAuthenticator](https://github.com/jupyterhub/oauthenticator) @@ -93,8 +93,8 @@ use a custom proxy (e.g. Traefik), this also not needed. Connections to user servers go through the proxy, and *not* the hub itself. If the proxy stays running when the hub restarts (for -maintnance, re-configuration, etc), then use connections are not +maintenance, re-configuration, etc.), then use connections are not interrupted. For simplicity, by default the hub starts the proxy automatically, so if the hub restarts, the proxy restarts, and user connections are interrupted. It is easy to run the proxy separately, -for information see [the separate proxy page](../reference/separate-proxy.html). +for information see [the separate proxy page](../reference/separate-proxy). diff --git a/docs/source/getting-started/services-basics.md b/docs/source/getting-started/services-basics.md index 8273f7d6..7e716a63 100644 --- a/docs/source/getting-started/services-basics.md +++ b/docs/source/getting-started/services-basics.md @@ -14,7 +14,7 @@ document will: - explain some basic information about API tokens - clarify that API tokens can be used to authenticate to - single-user servers as of [version 0.8.0](../changelog.html) + single-user servers as of [version 0.8.0](../changelog) - show how the [cull_idle_servers][] script can be: - used in a Hub-managed service - run as a standalone script @@ -29,14 +29,14 @@ Hub via the REST API. To run such an external service, an API token must be created and provided to the service. -As of [version 0.6.0](../changelog.html), the preferred way of doing +As of [version 0.6.0](../changelog), the preferred way of doing this is to first generate an API token: ```bash openssl rand -hex 32 ``` -In [version 0.8.0](../changelog.html), a TOKEN request page for +In [version 0.8.0](../changelog), a TOKEN request page for generating an API token is available from the JupyterHub user interface: ![Request API TOKEN page](../images/token-request.png) diff --git a/docs/source/images/login-button.png b/docs/source/images/login-button.png new file mode 100644 index 00000000..68502bf7 Binary files /dev/null and b/docs/source/images/login-button.png differ diff --git a/docs/source/images/login-form.png b/docs/source/images/login-form.png new file mode 100644 index 00000000..a2196c93 Binary files /dev/null and b/docs/source/images/login-form.png differ diff --git a/docs/source/images/named-servers-admin.png b/docs/source/images/named-servers-admin.png new file mode 100644 index 00000000..25e23d15 Binary files /dev/null and b/docs/source/images/named-servers-admin.png differ diff --git a/docs/source/images/named-servers-home.png b/docs/source/images/named-servers-home.png new file mode 100644 index 00000000..b55ac6cb Binary files /dev/null and b/docs/source/images/named-servers-home.png differ diff --git a/docs/source/images/not-running.png b/docs/source/images/not-running.png new file mode 100644 index 00000000..0bd21b27 Binary files /dev/null and b/docs/source/images/not-running.png differ diff --git a/docs/source/images/spawn-pending.png b/docs/source/images/spawn-pending.png new file mode 100644 index 00000000..bb2c3323 Binary files /dev/null and b/docs/source/images/spawn-pending.png differ diff --git a/docs/source/images/token-page.png b/docs/source/images/token-page.png new file mode 100644 index 00000000..de4b4721 Binary files /dev/null and b/docs/source/images/token-page.png differ diff --git a/docs/source/installation-basics.md b/docs/source/installation-basics.md index 33d55aee..62c44cd7 100644 --- a/docs/source/installation-basics.md +++ b/docs/source/installation-basics.md @@ -6,7 +6,7 @@ JupyterHub is supported on Linux/Unix based systems. To use JupyterHub, you need a Unix server (typically Linux) running somewhere that is accessible to your team on the network. The JupyterHub server can be on an internal network at your organization, or it can run on the public internet (in which case, take care -with the Hub's [security](./security-basics.html)). +with the Hub's [security](./getting-started/security-basics)). JupyterHub officially **does not** support Windows. You may be able to use JupyterHub on Windows if you use a Spawner and Authenticator that work on @@ -28,7 +28,7 @@ Prior to beginning installation, it's helpful to consider some of the following: - Spawner of singleuser notebook servers (Docker, Batch, etc.) - Services (nbgrader, etc.) - JupyterHub database (default SQLite; traditional RDBMS such as PostgreSQL,) - MySQL, or other databases supported by [SQLAlchemy](http://www.sqlalchemy.org)) + MySQL, or other databases supported by [SQLAlchemy](http://www.sqlalchemy.org)) ## Folders and File Locations diff --git a/docs/source/reference/config-user-env.md b/docs/source/reference/config-user-env.md index f5964042..c085b106 100644 --- a/docs/source/reference/config-user-env.md +++ b/docs/source/reference/config-user-env.md @@ -120,7 +120,7 @@ sure are available, I can install their specs system-wide (in /usr/local) with: ``` -## Multi-user hosts vs. Containers +## Multi-user hosts vs. Containers There are two broad categories of user environments that depend on what Spawner you choose: @@ -145,3 +145,37 @@ In both cases, you want to *avoid putting configuration in user home directories* because users can change those configuration settings. Also, home directories typically persist once they are created, so they are difficult for admins to update later. + +## Named servers + +By default, in a JupyterHub deployment each user has exactly one server. + +JupyterHub can, however, have multiple servers per user. +This is most useful in deployments where users can configure the environment +in which their server will start (e.g. resource requests on an HPC cluster), +so that a given user can have multiple configurations running at the same time, +without having to stop and restart their one server. + +To allow named servers: + +```python +c.JupyterHub.allow_named_servers = True +``` + +Named servers were implemented in the REST API in JupyterHub 0.8, +and JupyterHub 1.0 introduces UI for managing named servers via the user home page: + +![named servers on the home page](../images/named-servers-home.png) + +as well as the admin page: + +![named servers on the admin page](../images/named-servers-admin.png) + +Named servers can be accessed, created, started, stopped, and deleted +from these pages. Activity tracking is now per-server as well. + +The number of named servers per user can be limited by setting + +```python +c.JupyterHub.named_server_limit_per_user = 5 +``` diff --git a/docs/source/reference/index.rst b/docs/source/reference/index.rst index 7e119a66..088d0ae8 100644 --- a/docs/source/reference/index.rst +++ b/docs/source/reference/index.rst @@ -5,6 +5,7 @@ Technical Reference :maxdepth: 2 technical-overview + urls websecurity authenticators spawners diff --git a/docs/source/reference/rest-api.rst b/docs/source/reference/rest-api.rst new file mode 100644 index 00000000..c16d678d --- /dev/null +++ b/docs/source/reference/rest-api.rst @@ -0,0 +1,14 @@ +:orphan: + +=================== +JupyterHub REST API +=================== + +.. this doc exists as a resolvable link target +.. which _static files are not + +.. meta:: + :http-equiv=refresh: 0;url=../_static/rest-api/index.html + +The rest API docs are `here <../_static/rest-api/index.html>`_ +if you are not redirected automatically. diff --git a/docs/source/reference/rest.md b/docs/source/reference/rest.md index 5799312d..95e9ea8b 100644 --- a/docs/source/reference/rest.md +++ b/docs/source/reference/rest.md @@ -27,7 +27,7 @@ Hub. To send requests using JupyterHub API, you must pass an API token with the request. -As of [version 0.6.0](../changelog.html), the preferred way of +As of [version 0.6.0](../changelog.md), the preferred way of generating an API token is: ```bash @@ -48,7 +48,7 @@ jupyterhub token This command generates a random string to use as a token and registers it for the given user with the Hub's database. -In [version 0.8.0](../changelog.html), a TOKEN request page for +In [version 0.8.0](../changelog.md), a TOKEN request page for generating an API token is available from the JupyterHub user interface: ![Request API TOKEN page](../images/token-request.png) @@ -138,8 +138,8 @@ First you must enable named-servers by including the following setting in the `j `c.JupyterHub.allow_named_servers = True` -If using the [zero-to-jupyterhub-k8s](https://github.com/jupyterhub/zero-to-jupyterhub-k8s) set-up to run JupyterHub, -then instead of editing the `jupyterhub_config.py` file directly, you could pass +If using the [zero-to-jupyterhub-k8s](https://github.com/jupyterhub/zero-to-jupyterhub-k8s) set-up to run JupyterHub, +then instead of editing the `jupyterhub_config.py` file directly, you could pass the following as part of the `config.yaml` file, as per the [tutorial](https://zero-to-jupyterhub.readthedocs.io/en/latest/): ```bash @@ -158,11 +158,6 @@ The same servers can be stopped by substituting `DELETE` for `POST` above. ### Some caveats for using named-servers -The named-server capabilities are not fully implemented for JupyterHub as yet. -While it's possible to start/stop a server via the API, the UI on the -JupyterHub control-panel has not been implemented, and so it may not be obvious -to those viewing the panel that a named-server may be running for a given user. - For named-servers via the API to work, the spawner used to spawn these servers will need to be able to handle the case of multiple servers per user and ensure uniqueness of names, particularly if servers are spawned via docker containers @@ -178,5 +173,5 @@ Note: The Swagger specification is being renamed the [OpenAPI Initiative][]. [interactive style on swagger's petstore]: http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyterhub/jupyterhub/master/docs/rest-api.yml#!/default [OpenAPI Initiative]: https://www.openapis.org/ -[JupyterHub REST API]: ../_static/rest-api/index.html +[JupyterHub REST API]: ./rest-api [Jupyter Notebook REST API]: http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml diff --git a/docs/source/reference/technical-overview.md b/docs/source/reference/technical-overview.md index 15fd57db..a1577701 100644 --- a/docs/source/reference/technical-overview.md +++ b/docs/source/reference/technical-overview.md @@ -28,7 +28,7 @@ by the `jupyterhub` command line program: - **Single-User Notebook Server** (Python/Tornado): a dedicated, single-user, Jupyter Notebook server is started for each user on the system when the user logs in. The object that starts the single-user notebook - servers is called a **Spawner**. + servers is called a **Spawner**. ![JupyterHub subsystems](../images/jhub-parts.png) @@ -49,14 +49,14 @@ The proxy is the only process that listens on a public interface. The Hub sits behind the proxy at `/hub`. Single-user servers sit behind the proxy at `/user/[username]`. -Different **[authenticators](./authenticators.html)** control access +Different **[authenticators](./authenticators.md)** control access to JupyterHub. The default one (PAM) uses the user accounts on the server where JupyterHub is running. If you use this, you will need to create a user account on the system for each user on your team. Using other authenticators, you can allow users to sign in with e.g. a GitHub account, or with any single-sign-on system your organization has. -Next, **[spawners](./spawners.html)** control how JupyterHub starts +Next, **[spawners](./spawners.md)** control how JupyterHub starts the individual notebook server for each user. The default spawner will start a notebook server on the same machine running under their system username. The other main option is to start each server in a separate container, often @@ -66,10 +66,10 @@ using Docker. When a user accesses JupyterHub, the following events take place: -- Login data is handed to the [Authenticator](./authenticators.html) instance for +- Login data is handed to the [Authenticator](./authenticators.md) instance for validation - The Authenticator returns the username if the login information is valid -- A single-user notebook server instance is [spawned](./spawners.html) for the +- A single-user notebook server instance is [spawned](./spawners.md) for the logged-in user - When the single-user notebook server starts, the proxy is notified to forward requests to `/user/[username]/*` to the single-user notebook server. @@ -111,7 +111,7 @@ working directory: This file needs to persist so that a **Hub** server restart will avoid invalidating cookies. Conversely, deleting this file and restarting the server effectively invalidates all login cookies. The cookie secret file is discussed - in the [Cookie Secret section of the Security Settings document](../getting-started/security-basics.html). + in the [Cookie Secret section of the Security Settings document](../getting-started/security-basics.md). The location of these files can be specified via configuration settings. It is recommended that these files be stored in standard UNIX filesystem locations, @@ -122,9 +122,9 @@ all security and runtime files. There are two basic extension points for JupyterHub: -- How users are authenticated by [Authenticators](./authenticators.html) +- How users are authenticated by [Authenticators](./authenticators.md) - How user's single-user notebook server processes are started by - [Spawners](./spawners.html) + [Spawners](./spawners.md) Each is governed by a customizable class, and JupyterHub ships with basic defaults for each. diff --git a/docs/source/reference/urls.md b/docs/source/reference/urls.md new file mode 100644 index 00000000..6497fcb1 --- /dev/null +++ b/docs/source/reference/urls.md @@ -0,0 +1,255 @@ +# JupyterHub URL scheme + +This document describes how JupyterHub routes requests. + +This does not include the [REST API](./rest.md) urls. + +In general, all URLs can be prefixed with `c.JupyterHub.base_url` to +run the whole JupyterHub application on a prefix. + +All authenticated handlers redirect to `/hub/login` to login users +prior to being redirected back to the originating page. +The returned request should preserve all query parameters. + + + +## `/` + +The top-level request is always a simple redirect to `/hub/`, +to be handled by the default JupyterHub handler. + +In general, all requests to `/anything` that do not start with `/hub/` +but are routed to the Hub, will be redirected to `/hub/anything` before being handled by the Hub. + +## `/hub/` + +This is an authenticated URL. + +This handler redirects users to the default URL of the application, +which defaults to the user's default server. +That is, it redirects to `/hub/spawn` if the user's server is not running, +or the server itself (`/user/:name`) if the server is running. + +This default url behavior can be customized in two ways: + +To redirect users to the JupyterHub home page (`/hub/home`) +instead of spawning their server, +set `redirect_to_server` to False: + +```python +c.JupyterHub.redirect_to_server = False +``` + +This might be useful if you have a Hub where you expect +users to be managing multiple server configurations +and automatic spawning is not desirable. + +Second, you can customise the landing page to any page you like, +such as a custom service you have deployed e.g. with course information: + +```python +c.JupyterHub.default_url = '/services/my-landing-service' +``` + +## `/hub/home` + +![The Hub home page with named servers enabled](../images/named-servers-home.png) + +By default, the Hub home page has just one or two buttons +for starting and stopping the user's server. + +If named servers are enabled, there will be some additional +tools for management of named servers. + +*Version added: 1.0* named server UI is new in 1.0. + +## `/hub/login` + +This is the JupyterHub login page. +If you have a form-based username+password login, +such as the default PAMAuthenticator, +this page will render the login form. + +![A login form](../images/login-form.png) + +If login is handled by an external service, +e.g. with OAuth, this page will have a button, +declaring "Login with ..." which users can click +to login with the chosen service. + +![A login redirect button](../images/login-button.png) + +If you want to skip the user-interaction to initiate logging in +via the button, you can set + +```python +c.Authenticator.auto_login = True +``` + +This can be useful when the user is "already logged in" via some mechanism, +but a handshake via redirects is necessary to complete the authentication with JupyterHub. + +## `/hub/logout` + +Visiting `/hub/logout` clears cookies from the current browser. +Note that **logging out does not stop a user's server(s)** by default. + +If you would like to shutdown user servers on logout, +you can enable this behavior with: + +```python +c.JupyterHub.shutdown_on_logout = True +``` + +Be careful with this setting because logging out one browser +does not mean the user is no longer actively using their server from another machine. + +## `/user/:username[/:servername]` + +If a user's server is running, this URL is handled by the user's given server, +not the Hub. +The username is the first part and, if using named servers, +the server name is the second part. + +If the user's server is *not* running, this will be redirected to `/hub/user/:username/...` + +## `/hub/user/:username[/:servername]` + +This URL indicates a request for a user server that is not running +(because `/user/...` would have been handled by the notebook server +if the specified server were running). + +Handling this URL is the most complicated condition in JupyterHub, +because there can be many states: + +1. server is not active + a. user matches + b. user doesn't match +2. server is ready +3. server is pending, but not ready + +If the server is pending spawn, +the browser will be redirected to `/hub/spawn-pending/:username/:servername` +to see a progress page while waiting for the server to be ready. + +If the server is not active at all, +a page will be served with a link to `/hub/spawn/:username/:servername`. +Following that link will launch the requested server. +The HTTP status will be 503 in this case because a request has been made for a server that is not running. + +If the server is ready, it is assumed that the proxy has not yet registered the route. +Some checks are performed and a delay is added before redirecting back to `/user/:username/:servername/...`. +If something is really wrong, this can result in a redirect loop. + +Visiting this page will never result in triggering the spawn of servers +without additional user action (i.e. clicking the link on the page) + +![Visiting a URL for a server that's not running](../images/not-running.png) + +*Version changed: 1.0* + +Prior to 1.0, this URL itself was responsible for spawning servers, +and served the progress page if it was pending, +redirected to running servers, and +This was useful because it made sure that requested servers were restarted after they stopped, +but could also be harmful because unused servers would continuously be restarted if e.g. +an idle JupyterLab frontend were open pointed at it, +which constantly makes polling requests. + +### Special handling of API requests + +Requests to `/user/:username[/:servername]/api/...` are assumed to be +from applications connected to stopped servers. +These are failed with 503 and an informative JSON error message +indicating how to spawn the server. +This is meant to help applications such as JupyterLab +that are connected to a server that has stopped. + +*Version changed: 1.0* + +JupyterHub 0.9 failed these API requests with status 404, +but 1.0 uses 503. + +## `/user-redirect/...` + +This URL is for sharing a URL that will redirect a user +to a path on their own default server. +This is useful when users have the same file at the same URL on their servers, +and you want a single link to give to any user that will open that file on their server. + +e.g. a link to `/user-redirect/notebooks/Index.ipynb` +will send user `hortense` to `/user/hortense/notebooks/Index.ipynb` + +**DO NOT** share links to your own server with other users. +This will not work in general, +unless you grant those users access to your server. + +**Contributions welcome:** The JupyterLab "shareable link" should share this link +when run with JupyterHub, but it does not. +See [jupyterlab-hub](https://github.com/jupyterhub/jupyterlab-hub) +where this should probably be done and +[this issue in JupyterLab](https://github.com/jupyterlab/jupyterlab/issues/5388) +that is intended to make it possible. + +## Spawning + +### `/hub/spawn[/:username[/:servername]]` + +Requesting `/hub/spawn` will spawn the default server for the current user. +If `username` and optionally `servername` are specified, +then the specified server for the specified user will be spawned. +Once spawn has been requested, +the browser is redirected to `/hub/spawn-pending/...`. + +If `Spawner.options_form` is used, +this will render a form, +and a POST request will trigger the actual spawn and redirect. + +![The spawn form](../images/spawn-form.png) + +*Version added: 1.0* + +1.0 adds the ability to specify username and servername. +Prior to 1.0, only `/hub/spawn` was recognized for the default server. + +*Version changed: 1.0* + +Prior to 1.0, this page redirected back to `/hub/user/:username`, +which was responsible for triggering spawn and rendering progress, etc. + +### `/hub/spawn-pending[/:username[/:servername]]` + +![The spawn pending page](../images/spawn-pending.png) + +*Version added: 1.0* this URL is new in JupyterHub 1.0. + +This page renders the progress view for the given spawn request. +Once the server is ready, +the browser is redirected to the running server at `/user/:username/:servername/...`. + +If this page is requested at any time after the specified server is ready, +the browser will be redirected to the running server. + +Requesting this page will never trigger any side effects. +If the server is not running (e.g. because the spawn has failed), +the spawn failure message (if applicable) will be displayed, +and the page will show a link back to `/hub/spawn/...`. + +## `/hub/token` + +![The token management page](../images/token-page.png) + +On this page, users can manage their JupyterHub API tokens. +They can revoke access and request new tokens for writing scripts +against the [JupyterHub REST API](./rest.md). + +## `/hub/admin` + +![The admin panel](../images/named-servers-admin.png) + +Administrators can take various administrative actions from this page: + +1. add/remove users +2. grant admin privileges +3. start/stop user servers +4. shutdown JupyterHub itself