Repository: jupyterhub/jupyterhub

Issue:
jupyter_server's disable_check_xsrf ignored
<!-- Thank you for contributing. These HTML comments will not render in the issue, but you can delete them once you've read them if you prefer! -->

### Bug description

As noted down in #4744, there are still issues with "HTTP 403: Forbidden ('_xsrf' argument missing from GET)" errors. More specifically, I'm having issues with [nbgallery](https://github.com/nbgallery/lab-extensions/blob/main/jupyterlab_nbgallery/handlers.py#L15-L34) and [jupyterlab_templates](https://github.com/finos/jupyterlab_templates/blob/main/jupyterlab_templates/extension.py#L99-L107).

Some sanitized logs which show the issue:
```
/opt/conda/lib/python3.10/site-packages/jupyter_server/serverapp.py:2235: JupyterServerAuthWarning: Core endpoints without @allow_unauthenticated, @ws_authenticated, nor @web.authenticated:
- GET of JupyterHubLogoutHandler registered for /user/$JUPYTERHUB_USER/logout
- GET of JupyterHubOAuthCallbackHandler registered for /user/$JUPYTERHUB_USER/oauth_callback
  self.web_app = ServerWebApplication(

[...]

[I 2024-03-25 18:27:05.673 ServerApp] Logged-in user {'kind': 'user', 'admin': True, 'name': '$JUPYTERHUB_USER', 'groups': [], 'session_id': 'some-session-id', 'scopes': ['access:servers!server=$JUPYTERHUB_USER/', 'read:users:groups!user=$JUPYTERHUB_USER', 'read:users:name!user=$JUPYTERHUB_USER']}
[E 2024-03-25 18:27:05.674 ServerApp] Not accepting cookie auth on GET /user/$JUPYTERHUB_USER/oauth_callback: HTTP 403: Forbidden ('_xsrf' argument missing from GET)
[I 2024-03-25 18:27:05.674 ServerApp] 302 GET /user/$JUPYTERHUB_USER/oauth_callback?code=[secret]&state=[secret] -> /user/$JUPYTERHUB_USER/templates/names (@127.0.0.1) 57.94ms

[...]

[W 2024-03-25 18:27:08.925 ServerApp] 403 GET /user/$JUPYTERHUB_USER/jupyterlab_nbgallery/environment?_=1711391214409 (@127.0.0.1) 2.76ms
[E 2024-03-25 18:27:08.925 ServerApp] Not accepting cookie auth on GET /user/$JUPYTERHUB_USER/jupyterlab_nbgallery/instrumentation: HTTP 403: Forbidden ('_xsrf' argument missing from GET)

[...]

[E 2024-03-25 18:48:44.067 ServerApp] Not accepting cookie auth on POST /user/$JUPYTERHUB_USER/post/example.ipynb: HTTP 403: Forbidden ('_xsrf' argument missing from POST)
[W 2024-03-25 18:48:44.067 ServerApp] 403 POST /user/$JUPYTERHUB_USER/post/example.ipynb (127.0.0.1): '_xsrf' argument missing from POST
[W 2024-03-25 18:48:44.068 ServerApp] wrote error: "'_xsrf' argument missing from POST"
    Traceback (most recent call last):
      File "/opt/conda/lib/python3.10/site-packages/tornado/web.py", line 1769, in _execute
        result = await result  # type: ignore
      File "/opt/conda/lib/python3.10/site-packages/jupyter_server/base/handlers.py", line 750, in prepare
        await super().prepare()
      File "/opt/conda/lib/python3.10/site-packages/jupyter_server/base/handlers.py", line 632, in prepare
        self.check_xsrf_cookie()
      File "/opt/conda/lib/python3.10/site-packages/jupyterhub/services/auth.py", line 915, in <lambda>
        cls.check_xsrf_cookie = lambda handler: self.check_xsrf_cookie(handler)
      File "/opt/conda/lib/python3.10/site-packages/jupyterhub/services/auth.py", line 924, in check_xsrf_cookie
        check_xsrf_cookie(handler)
      File "/opt/conda/lib/python3.10/site-packages/jupyterhub/_xsrf_utils.py", line 181, in check_xsrf_cookie
        raise web.HTTPError(
    tornado.web.HTTPError: HTTP 403: Forbidden ('_xsrf' argument missing from POST)
[W 2024-03-25 18:48:44.069 ServerApp] 403 POST /user/$JUPYTERHUB_USER/post/example.ipynb (@127.0.0.1) 2.48ms
```
Seems like both extensions probably depended on "ServerApp.disable_check_xsrf=True" which is now being ignored.

### How to reproduce

Launch a JupyterHub server with a JupyterLab image that has jupyterlab_templates installed. The expected "template" button will be missing from the launcher and the logs will show 403s on jupyterlab_templates' handler.

#### Expected behaviour

"ServerApp.disable_check_xsrf=True" to be respected to allow extensions that depend on it to work.

#### Actual behaviour

See above.

### Your personal set up
Custom Helm chart built on top of zero-to-jupyterhub v3.3.3. 
<!--
Tell us a little about the system you're using.
Please include information about how you installed,
e.g. are you using a distribution such as zero-to-jupyterhub or the-littlest-jupyterhub.
 -->

 - OS:
 <!-- [e.g. ubuntu 20.04, macOS 11.0] -->
 - Version(s): JupyterHub 4.1.1 and Python 3.10.
 <!-- e.g. jupyterhub --version, python --version --->


<details><summary>Full environment</summary>
<!-- For reproduction, it's useful to have the full environment. For example, the output of `pip freeze` or `conda list` --->

```
# paste output of `pip freeze` or `conda list` here
```
</details>

<details><summary>Configuration</summary>
<!--
For JupyterHub, especially include information such as what Spawner and Authenticator are being used.
Be careful not to share any sensitive information.
You can paste jupyterhub_config.py below.
To exclude lots of comments and empty lines from auto-generated jupyterhub_config.py, you can do:
    grep -v '\(^#\|^[[:space:]]*$\)' jupyterhub_config.py
-->

```python
# jupyterhub_config.py
```
</details>

<details><summary>Logs</summary>
<!--
Errors are often logged by jupytehub. How you get logs depends on your deployment.
With kubernetes it might be:

    kubectl get pod # hub pod name starts with hub...
    kubectl logs hub-...
    # or for a single-user server
    kubectl logs jupyter-username

Or the-littlest-jupyterhub:

    journalctl -u jupyterhub
    # or for a single-user server
    journalctl -u jupyter-username
-->

```
# paste relevant logs here, if any
```
</details>



Discussion:
Thank you for opening your first issue in this project! Engagement like this is essential for open source projects! :hugs:
<br>If you haven't done so already, check out [Jupyter's Code of Conduct](https://github.com/jupyter/governance/blob/master/conduct/code_of_conduct.md). Also, please try to follow the issue template as it helps other other community members to contribute more effectively.
![welcome](https://raw.githubusercontent.com/jupyterhub/.github/master/images/welcome.jpg)
You can meet the other [Jovyans](https://jupyter.readthedocs.io/en/latest/community/content-community.html?highlight=jovyan#what-is-a-jovyan) by joining our [Discourse forum](http://discourse.jupyter.org/). There is also an intro thread there where you can stop by and say Hi! :wave:
<br>Welcome to the Jupyter community! :tada:


Resolving patch:
diff --git a/jupyterhub/services/auth.py b/jupyterhub/services/auth.py
--- a/jupyterhub/services/auth.py
+++ b/jupyterhub/services/auth.py
@@ -931,7 +931,9 @@ def check_xsrf_cookie(self, handler):
 
         Applies JupyterHub check_xsrf_cookie if not token authenticated
         """
-        if getattr(handler, '_token_authenticated', False):
+        if getattr(handler, '_token_authenticated', False) or handler.settings.get(
+            "disable_check_xsrf", False
+        ):
             return
         check_xsrf_cookie(handler)
 


Test patch: