Add _csrf_confirm_form_route option for to the user/logout route

Created on 9 April 2025, 4 months ago

Problem/Motivation

This is a followup issue to https://www.drupal.org/project/openid_connect/issues/3508791 πŸ› Add CSRF protection for /user/logout Active .

In that issue, we added CSRF protection to the logout link provided by OpenID Connect. The next step is to add a confirmation form to the route to follow the Core best practices (see: https://www.drupal.org/node/3152693 β†’ ).

Steps to reproduce

1. Login with an OpenID provider.
2. Browse to `user/logout`
3. Currently receive a 403 access denied (because of the missing CSRF token).

Proposed resolution

Add the `_csrf_confirm_form_route` token to the logout route and provide the confirmation form to allow the logout action without the csrf token in the route.

Remaining tasks

[ ] Add the route option
[ ] Add the confirmation form
[ ] Add testing.

✨ Feature request
Status

Active

Version

3.0

Component

Code

Created by

πŸ‡ΊπŸ‡ΈUnited States pfrilling Minster, OH

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

  • Issue created by @pfrilling
  • πŸ‡ΊπŸ‡ΈUnited States pfrilling Minster, OH

    I was able to get this working. It took a pretty big refactor of the logout redirect. I ended up moving that logic to a separate service so that it could be reused across the new confirmation form as well as the logout controller. If anyone has some time to manually test this, that would be appreciated.

  • πŸ‡ΊπŸ‡ΈUnited States pfrilling Minster, OH
  • πŸ‡ΊπŸ‡ΈUnited States ben.hamelin Adirondack Mountains, NY

    @pfrilling code review looks good.

  • Status changed to Needs work 16 days ago
  • When I navigate to /user/logout and click to confirm and log out, I get this error:

    The website encountered an unexpected error. Try again later.

    TypeError: Cannot access offset of type Drupal\openid_connect\Entity\OpenIDConnectClientEntity on array in Drupal\Core\Entity\EntityStorageBase->load() (line 263 of core/lib/Drupal/Core/Entity/EntityStorageBase.php).
    Drupal\Core\Entity\EntityBase::load() (Line: 188)
    openid_connect_windows_aad_openid_connect_redirect_logout_alter() (Line: 552)
    Drupal\Core\Extension\ModuleHandler->alter() (Line: 115)
    Drupal\openid_connect\Service\LogoutService->getLogoutRedirectResponse() (Line: 45)
    Drupal\openid_connect\Form\UserLogoutConfirmation->submitForm()
    call_user_func_array() (Line: 129)
    Drupal\Core\Form\FormSubmitter->executeSubmitHandlers() (Line: 67)
    Drupal\Core\Form\FormSubmitter->doSubmitForm() (Line: 609)
    Drupal\Core\Form\FormBuilder->processForm() (Line: 326)
    Drupal\Core\Form\FormBuilder->buildForm() (Line: 73)
    Drupal\Core\Controller\FormController->getContentResult()
    call_user_func_array() (Line: 123)
    Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 637)
    Drupal\Core\Render\Renderer->executeInRenderContext() (Line: 121)
    Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext() (Line: 97)
    Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 181)
    Symfony\Component\HttpKernel\HttpKernel->handleRaw() (Line: 76)
    Symfony\Component\HttpKernel\HttpKernel->handle() (Line: 53)
    Drupal\Core\StackMiddleware\Session->handle() (Line: 48)
    Drupal\Core\StackMiddleware\KernelPreHandle->handle() (Line: 28)
    Drupal\Core\StackMiddleware\ContentLength->handle() (Line: 32)
    Drupal\big_pipe\StackMiddleware\ContentLength->handle() (Line: 48)
    Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle() (Line: 51)
    Drupal\Core\StackMiddleware\NegotiationMiddleware->handle() (Line: 36)
    Drupal\Core\StackMiddleware\AjaxPageState->handle() (Line: 51)
    Drupal\Core\StackMiddleware\StackedHttpKernel->handle() (Line: 741)
    Drupal\Core\DrupalKernel->handle() (Line: 19)

  • πŸ‡¬πŸ‡§United Kingdom alt36

    I use a custom plugin whivh extends OpenIDConnectClientBase . My sites use Azure-backed oauth2, and my plugin effectively just implements getEndpoints() to return the correct set of URLs for our environment. I have now added the correct 'end_session' URL to the list returned, specifically:

    $site_url = Url::fromRoute('', [], ['absolute' => TRUE])->toString();
    $urls[ 'end_session'] = 'https://login.microsoftonline.com/common/oauth2/v2.0/logout?post_logout_...' . urlencode($site_url),

    and then logged in. With commit 9079d85 , I can confirm:

    1. the logout link in the Drupal toolbar is /user/logout/?token=$TOKENVALUE . Clicking that takes me sucessfully through the logout process

    2. Manually visiting /user/logout redirects me to /user/logout/confirm with a "log out" button. Clicking that then takes me sucessfully through the logout process.

  • Manually tested, and I confirmed that it works now.

  • πŸ‡ΊπŸ‡ΈUnited States pfrilling Minster, OH

    Thanks for testing everyone! This has been merged.

  • Automatically closed - issue fixed for 2 weeks with no activity.

Production build 0.71.5 2024