diff --git a/jupyter_server/serverapp.py b/jupyter_server/serverapp.py index 0f64d830b5..585d8fb9d4 100755 --- a/jupyter_server/serverapp.py +++ b/jupyter_server/serverapp.py @@ -786,6 +786,9 @@ def _write_cookie_secret_file(self, secret): token = Unicode('', help=_i18n("""Token used for authenticating first-time connections to the server. + The token can be read from the file referenced by JUPYTER_TOKEN_FILE or set directly + with the JUPYTER_TOKEN environment variable. + When no password is enabled, the default is to generate a new, random token. @@ -800,6 +803,10 @@ def _token_default(self): if os.getenv('JUPYTER_TOKEN'): self._token_generated = False return os.getenv('JUPYTER_TOKEN') + if os.getenv('JUPYTER_TOKEN_FILE'): + self._token_generated = False + with io.open(os.getenv('JUPYTER_TOKEN_FILE'), "r") as token_file: + return token_file.read() if self.password: # no token if password is enabled self._token_generated = False diff --git a/jupyter_server/tests/extension/test_launch.py b/jupyter_server/tests/extension/test_launch.py index 5056d9a6a6..343ffa5cbe 100644 --- a/jupyter_server/tests/extension/test_launch.py +++ b/jupyter_server/tests/extension/test_launch.py @@ -1,6 +1,7 @@ """Test launching Jupyter Server Applications through as ExtensionApp launch_instance. """ +from pathlib import Path import os import sys import time @@ -45,7 +46,7 @@ def wait_up(url, interval=0.1, check=None): @pytest.fixture def launch_instance(request, port, token): - def _run_in_subprocess(argv=[]): + def _run_in_subprocess(argv=[], add_token=True): def _kill_extension_app(): try: @@ -55,13 +56,15 @@ def _kill_extension_app(): pass process.wait(10) + if add_token: + f'--ServerApp.token="{token}"', + process = subprocess.Popen([ sys.executable, '-m', 'mockextensions.app', f'--port={port}', '--ip=127.0.0.1', '--no-browser', - f'--ServerApp.token="{token}"', *argv, ], cwd=HERE) @@ -93,3 +96,15 @@ def test_base_url(launch_instance, fetch): assert r.status_code == 200 +def test_token_file(launch_instance, fetch, token): + token_file = HERE / Path('token_file.txt') + os.environ['JUPYTER_TOKEN_FILE'] = str(token_file) + token_file.write_text(token, encoding='utf-8') + + launch_instance(add_token=False) + r = fetch("/mock") + del os.environ['JUPYTER_TOKEN_FILE'] + token_file.unlink() + assert r.status_code == 200 + +