diff --git a/typo3/sysext/backend/Classes/Controller/LoginController.php b/typo3/sysext/backend/Classes/Controller/LoginController.php
index 1f85da1d10ca4ac321df3b8fe52035c93f0dd701..befdba4a414d441d7d2602a410168faf146188e3 100644
--- a/typo3/sysext/backend/Classes/Controller/LoginController.php
+++ b/typo3/sysext/backend/Classes/Controller/LoginController.php
@@ -21,7 +21,6 @@ use Psr\EventDispatcher\EventDispatcherInterface;
 use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
 use Symfony\Component\HttpFoundation\Cookie;
-use TYPO3\CMS\Backend\Authentication\PasswordReset;
 use TYPO3\CMS\Backend\LoginProvider\Event\ModifyPageLayoutOnLoginProviderSelectionEvent;
 use TYPO3\CMS\Backend\LoginProvider\LoginProviderInterface;
 use TYPO3\CMS\Backend\Routing\UriBuilder;
@@ -157,122 +156,6 @@ class LoginController
         return new HtmlResponse($this->createLoginLogoutForm($request));
     }
 
-    /**
-     * Show a form to enter an email address to request an email.
-     *
-     * @param ServerRequestInterface $request
-     * @return ResponseInterface
-     */
-    public function forgetPasswordFormAction(ServerRequestInterface $request): ResponseInterface
-    {
-        // Only allow to execute this if not logged in as a user right now
-        if ($this->context->getAspect('backend.user')->isLoggedIn()) {
-            return $this->formAction($request);
-        }
-        $this->init($request);
-        // Enable the switch in the template
-        $this->view->assign('enablePasswordReset', GeneralUtility::makeInstance(PasswordReset::class)->isEnabled());
-        $this->view->setTemplate('Login/ForgetPasswordForm');
-        $this->moduleTemplate->setContent($this->view->render());
-        return new HtmlResponse($this->moduleTemplate->renderContent());
-    }
-
-    /**
-     * Validate the email address.
-     *
-     * Restricted to POST method in Configuration/Backend/Routes.php
-     *
-     * @param ServerRequestInterface $request
-     * @return ResponseInterface
-     */
-    public function initiatePasswordResetAction(ServerRequestInterface $request): ResponseInterface
-    {
-        // Only allow to execute this if not logged in as a user right now
-        if ($this->context->getAspect('backend.user')->isLoggedIn()) {
-            return $this->formAction($request);
-        }
-        $this->init($request);
-        $passwordReset = GeneralUtility::makeInstance(PasswordReset::class);
-        $this->view->assign('enablePasswordReset', $passwordReset->isEnabled());
-        $this->view->setTemplate('Login/ForgetPasswordForm');
-
-        $emailAddress = $request->getParsedBody()['email'] ?? '';
-        $this->view->assign('email', $emailAddress);
-        if (!GeneralUtility::validEmail($emailAddress)) {
-            $this->view->assign('invalidEmail', true);
-        } else {
-            $passwordReset->initiateReset($request, $this->context, $emailAddress);
-            $this->view->assign('resetInitiated', true);
-        }
-        $this->moduleTemplate->setContent($this->view->render());
-        // Prevent time based information disclosure by waiting a random time
-        // before sending a response. This prevents that the reponse time
-        // can be an indicator if the used email exists or not.
-        // wait a random time between 200 milliseconds and 3 seconds.
-        usleep(random_int(200000, 3000000));
-        return new HtmlResponse($this->moduleTemplate->renderContent());
-    }
-
-    /**
-     * Validates the link and show a form to enter the new password.
-     *
-     * @param ServerRequestInterface $request
-     * @return ResponseInterface
-     */
-    public function passwordResetAction(ServerRequestInterface $request): ResponseInterface
-    {
-        // Only allow to execute this if not logged in as a user right now
-        if ($this->context->getAspect('backend.user')->isLoggedIn()) {
-            return $this->formAction($request);
-        }
-        $this->init($request);
-        $passwordReset = GeneralUtility::makeInstance(PasswordReset::class);
-        $this->view->setTemplate('Login/ResetPasswordForm');
-        $this->view->assign('enablePasswordReset', $passwordReset->isEnabled());
-        if (!$passwordReset->isValidResetTokenFromRequest($request)) {
-            $this->view->assign('invalidToken', true);
-        }
-        $this->view->assign('token', $request->getQueryParams()['t'] ?? '');
-        $this->view->assign('identity', $request->getQueryParams()['i'] ?? '');
-        $this->view->assign('expirationDate', $request->getQueryParams()['e'] ?? '');
-        $this->moduleTemplate->setContent($this->view->render());
-        return new HtmlResponse($this->moduleTemplate->renderContent());
-    }
-
-    /**
-     * Updates the password in the database.
-     *
-     * Restricted to POST method in Configuration/Backend/Routes.php
-     *
-     * @param ServerRequestInterface $request
-     * @return ResponseInterface
-     */
-    public function passwordResetFinishAction(ServerRequestInterface $request): ResponseInterface
-    {
-        // Only allow to execute this if not logged in as a user right now
-        if ($this->context->getAspect('backend.user')->isLoggedIn()) {
-            return $this->formAction($request);
-        }
-        $passwordReset = GeneralUtility::makeInstance(PasswordReset::class);
-        // Token is invalid
-        if (!$passwordReset->isValidResetTokenFromRequest($request)) {
-            return $this->passwordResetAction($request);
-        }
-        $this->init($request);
-        $this->view->setTemplate('Login/ResetPasswordForm');
-        $this->view->assign('enablePasswordReset', $passwordReset->isEnabled());
-        $this->view->assign('token', $request->getQueryParams()['t'] ?? '');
-        $this->view->assign('identity', $request->getQueryParams()['i'] ?? '');
-        $this->view->assign('expirationDate', $request->getQueryParams()['e'] ?? '');
-        if ($passwordReset->resetPassword($request, $this->context)) {
-            $this->view->assign('resetExecuted', true);
-        } else {
-            $this->view->assign('error', true);
-        }
-        $this->moduleTemplate->setContent($this->view->render());
-        return new HtmlResponse($this->moduleTemplate->renderContent());
-    }
-
     /**
      * This can be called by single login providers, they receive an instance of $this
      *
@@ -397,6 +280,11 @@ class LoginController
             'hasLoginError' => $this->isLoginInProgress($request),
             'action' => $action,
             'formActionUrl' => $formActionUrl,
+            'forgetPasswordUrl' => $this->uriBuilder->buildUriWithRedirectFromRequest(
+                'password_forget',
+                ['loginProvider' => $this->loginProviderIdentifier],
+                $request
+            ),
             'redirectUrl' => $this->redirectUrl,
             'loginRefresh' => $this->loginRefresh,
             'loginProviders' => $this->loginProviders,
diff --git a/typo3/sysext/backend/Classes/Controller/ResetPasswordController.php b/typo3/sysext/backend/Classes/Controller/ResetPasswordController.php
new file mode 100644
index 0000000000000000000000000000000000000000..dd045dde8ee334dffce186d2d3fb20d1d6c765b1
--- /dev/null
+++ b/typo3/sysext/backend/Classes/Controller/ResetPasswordController.php
@@ -0,0 +1,271 @@
+<?php
+
+declare(strict_types=1);
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+namespace TYPO3\CMS\Backend\Controller;
+
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
+use TYPO3\CMS\Backend\Authentication\PasswordReset;
+use TYPO3\CMS\Backend\Routing\UriBuilder;
+use TYPO3\CMS\Backend\Template\ModuleTemplate;
+use TYPO3\CMS\Backend\Template\ModuleTemplateFactory;
+use TYPO3\CMS\Backend\View\AuthenticationStyleInformation;
+use TYPO3\CMS\Core\Configuration\Features;
+use TYPO3\CMS\Core\Context\Context;
+use TYPO3\CMS\Core\Http\HtmlResponse;
+use TYPO3\CMS\Core\Http\PropagateResponseException;
+use TYPO3\CMS\Core\Http\RedirectResponse;
+use TYPO3\CMS\Core\Information\Typo3Information;
+use TYPO3\CMS\Core\Localization\LanguageService;
+use TYPO3\CMS\Core\Localization\Locales;
+use TYPO3\CMS\Core\Page\PageRenderer;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Extbase\Mvc\View\ViewInterface;
+
+/**
+ * Controller responsible for rendering and processing password reset requests
+ *
+ * @internal This class is a specific Backend controller implementation and is not considered part of the Public TYPO3 API.
+ */
+class ResetPasswordController
+{
+    protected string $loginProvider = '';
+    protected ?ViewInterface $view = null;
+    protected ?ModuleTemplate $moduleTemplate = null;
+
+    protected Context $context;
+    protected Locales $locales;
+    protected Features $features;
+    protected UriBuilder $uriBuilder;
+    protected PageRenderer $pageRenderer;
+    protected PasswordReset $passwordReset;
+    protected Typo3Information $typo3Information;
+    protected ModuleTemplateFactory $moduleTemplateFactory;
+    protected AuthenticationStyleInformation $authenticationStyleInformation;
+
+    public function __construct(
+        Context $context,
+        Locales $locales,
+        Features $features,
+        UriBuilder $uriBuilder,
+        PageRenderer $pageRenderer,
+        PasswordReset $passwordReset,
+        Typo3Information $typo3Information,
+        ModuleTemplateFactory $moduleTemplateFactory,
+        AuthenticationStyleInformation $authenticationStyleInformation
+    ) {
+        $this->context = $context;
+        $this->locales = $locales;
+        $this->features = $features;
+        $this->uriBuilder = $uriBuilder;
+        $this->pageRenderer = $pageRenderer;
+        $this->passwordReset = $passwordReset;
+        $this->typo3Information = $typo3Information;
+        $this->moduleTemplateFactory = $moduleTemplateFactory;
+        $this->authenticationStyleInformation = $authenticationStyleInformation;
+    }
+
+    /**
+     * Show a form to enter an email address to request a password reset email.
+     *
+     * @param ServerRequestInterface $request
+     * @return ResponseInterface
+     */
+    public function forgetPasswordFormAction(ServerRequestInterface $request): ResponseInterface
+    {
+        $this->initializeForgetPasswordView($request);
+        $this->moduleTemplate->setContent($this->view->render());
+        return new HtmlResponse($this->moduleTemplate->renderContent());
+    }
+
+    /**
+     * Validate the email address.
+     *
+     * Restricted to POST method in Configuration/Backend/Routes.php
+     *
+     * @param ServerRequestInterface $request
+     * @return ResponseInterface
+     */
+    public function initiatePasswordResetAction(ServerRequestInterface $request): ResponseInterface
+    {
+        $this->initializeForgetPasswordView($request);
+        $emailAddress = $request->getParsedBody()['email'] ?? '';
+        $this->view->assign('email', $emailAddress);
+        if (!GeneralUtility::validEmail($emailAddress)) {
+            $this->view->assign('invalidEmail', true);
+        } else {
+            $this->passwordReset->initiateReset($request, $this->context, $emailAddress);
+            $this->view->assign('resetInitiated', true);
+        }
+        $this->moduleTemplate->setContent($this->view->render());
+        // Prevent time based information disclosure by waiting a random time
+        // before sending a response. This prevents that the response time
+        // can be an indicator if the used email exists or not. Wait a random
+        // time between 200 milliseconds and 3 seconds.
+        usleep(random_int(200000, 3000000));
+        return new HtmlResponse($this->moduleTemplate->renderContent());
+    }
+
+    /**
+     * Validates the link and show a form to enter the new password.
+     *
+     * @param ServerRequestInterface $request
+     * @return ResponseInterface
+     */
+    public function passwordResetAction(ServerRequestInterface $request): ResponseInterface
+    {
+        $this->initializeResetPasswordView($request);
+        if (!$this->passwordReset->isValidResetTokenFromRequest($request)) {
+            $this->view->assign('invalidToken', true);
+        }
+        $this->moduleTemplate->setContent($this->view->render());
+        return new HtmlResponse($this->moduleTemplate->renderContent());
+    }
+
+    /**
+     * Updates the password in the database.
+     *
+     * Restricted to POST method in Configuration/Backend/Routes.php
+     *
+     * @param ServerRequestInterface $request
+     * @return ResponseInterface
+     */
+    public function passwordResetFinishAction(ServerRequestInterface $request): ResponseInterface
+    {
+        // Token is invalid
+        if (!$this->passwordReset->isValidResetTokenFromRequest($request)) {
+            return $this->passwordResetAction($request);
+        }
+        $this->initializeResetPasswordView($request);
+        if ($this->passwordReset->resetPassword($request, $this->context)) {
+            $this->view->assign('resetExecuted', true);
+        } else {
+            $this->view->assign('error', true);
+        }
+        $this->moduleTemplate->setContent($this->view->render());
+        return new HtmlResponse($this->moduleTemplate->renderContent());
+    }
+
+    protected function initializeForgetPasswordView(ServerRequestInterface $request): void
+    {
+        $this->initialize($request);
+        $this->view->setTemplate('Login/ForgetPasswordForm');
+        $parameters = array_filter(['loginProvider' => $this->loginProvider]);
+        $this->view->assignMultiple([
+            'formUrl' => $this->uriBuilder->buildUriWithRedirectFromRequest('password_forget_initiate_reset', $parameters, $request),
+            'returnUrl' => $this->uriBuilder->buildUriWithRedirectFromRequest('login', $parameters, $request)
+        ]);
+    }
+
+    protected function initializeResetPasswordView(ServerRequestInterface $request): void
+    {
+        $this->initialize($request);
+        $token = $request->getQueryParams()['t'] ?? '';
+        $identity = $request->getQueryParams()['i'] ?? '';
+        $expirationDate = $request->getQueryParams()['e'] ?? '';
+        $parameters = array_filter(['loginProvider' => $this->loginProvider]);
+        $formUrl = $this->uriBuilder->buildUriWithRedirectFromRequest(
+            'password_reset_finish',
+            array_filter(array_merge($parameters, [
+               't' => $token,
+               'i' => $identity,
+               'e' => $expirationDate
+            ])),
+            $request
+        );
+        $this->view->setTemplate('Login/ResetPasswordForm');
+        $this->view->assignMultiple([
+            'token' => $token,
+            'identity' => $identity,
+            'expirationDate' => $expirationDate,
+            'formUrl' => $formUrl,
+            'restartUrl' => $this->uriBuilder->buildUriWithRedirectFromRequest('password_forget', $parameters, $request)
+        ]);
+    }
+
+    protected function initialize(ServerRequestInterface $request): void
+    {
+        // Only allow to execute this if not logged in as a user right now
+        if ($this->context->getAspect('backend.user')->isLoggedIn()) {
+            throw new PropagateResponseException(
+                new RedirectResponse($this->uriBuilder->buildUriFromRoute('login'), 303),
+                1618342858
+            );
+        }
+
+        // Fetch login provider from the request
+        $this->loginProvider = $request->getQueryParams()['loginProvider'] ?? '';
+
+        // Try to get the preferred browser language
+        $httpAcceptLanguage = $request->getServerParams()['HTTP_ACCEPT_LANGUAGE'];
+        $preferredBrowserLanguage = $this->locales->getPreferredClientLanguage($httpAcceptLanguage);
+
+        // If we found a $preferredBrowserLanguage and it is not the default language
+        // initialize $this->getLanguageService() again with $preferredBrowserLanguage
+        if ($preferredBrowserLanguage !== 'default') {
+            $this->getLanguageService()->init($preferredBrowserLanguage);
+            $this->pageRenderer->setLanguage($preferredBrowserLanguage);
+        }
+
+        $this->getLanguageService()->includeLLFile('EXT:backend/Resources/Private/Language/locallang_login.xlf');
+
+        $this->moduleTemplate = $this->moduleTemplateFactory->create($request);
+        $this->moduleTemplate->setTitle('TYPO3 CMS Login: ' . ($GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'] ?? ''));
+
+        $this->view = $this->moduleTemplate->getView();
+        $this->view->getRequest()->setControllerExtensionName('Backend');
+        $this->view->assignMultiple([
+            'enablePasswordReset' => $this->passwordReset->isEnabled(),
+            'referrerCheckEnabled' => $this->features->isFeatureEnabled('security.backend.enforceReferrer'),
+            'loginUrl' => (string)$request->getUri(),
+        ]);
+
+        $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Login');
+        $this->provideCustomLoginStyling();
+    }
+
+    protected function provideCustomLoginStyling(): void
+    {
+        if (($backgroundImageStyles = $this->authenticationStyleInformation->getBackgroundImageStyles()) !== '') {
+            $this->pageRenderer->addCssInlineBlock('loginBackgroundImage', $backgroundImageStyles);
+        }
+        if (($footerNote = $this->authenticationStyleInformation->getFooterNote()) !== '') {
+            $this->view->assign('loginFootnote', $footerNote);
+        }
+        if (($highlightColorStyles = $this->authenticationStyleInformation->getHighlightColorStyles()) !== '') {
+            $this->pageRenderer->addCssInlineBlock('loginHighlightColor', $highlightColorStyles);
+        }
+        if (($logo = $this->authenticationStyleInformation->getLogo()) !== '') {
+            $logoAlt = $this->authenticationStyleInformation->getLogoAlt();
+        } else {
+            $logo = $this->authenticationStyleInformation->getDefaultLogo();
+            $logoAlt = $this->getLanguageService()->getLL('typo3.altText');
+            $this->pageRenderer->addCssInlineBlock('loginLogo', $this->authenticationStyleInformation->getDefaultLogoStyles());
+        }
+        $this->view->assignMultiple([
+            'logo' => $logo,
+            'logoAlt' => $logoAlt,
+            'images' => $this->authenticationStyleInformation->getSupportingImages(),
+            'copyright' => $this->typo3Information->getCopyrightNotice(),
+        ]);
+    }
+
+    protected function getLanguageService(): LanguageService
+    {
+        return $GLOBALS['LANG'];
+    }
+}
diff --git a/typo3/sysext/backend/Configuration/Backend/Routes.php b/typo3/sysext/backend/Configuration/Backend/Routes.php
index fef158bda195d91a2a87d19d15c74d8874e61d8f..b91d0fb32c52421b38949c729c22cc9618af26ec 100644
--- a/typo3/sysext/backend/Configuration/Backend/Routes.php
+++ b/typo3/sysext/backend/Configuration/Backend/Routes.php
@@ -36,25 +36,25 @@ return [
     'password_forget' => [
         'path' => '/login/password-reset/forget',
         'access' => 'public',
-        'target' => Controller\LoginController::class . '::forgetPasswordFormAction'
+        'target' => Controller\ResetPasswordController::class . '::forgetPasswordFormAction'
     ],
     // Send out the password reset email
     'password_forget_initiate_reset' => [
         'path' => '/login/password-reset/initiate-reset',
         'access' => 'public',
         'methods' => ['POST'],
-        'target' => Controller\LoginController::class . '::initiatePasswordResetAction'
+        'target' => Controller\ResetPasswordController::class . '::initiatePasswordResetAction'
     ],
     'password_reset_validate' => [
         'path' => '/login/password-reset/validate',
         'access' => 'public',
-        'target' => Controller\LoginController::class . '::passwordResetAction'
+        'target' => Controller\ResetPasswordController::class . '::passwordResetAction'
     ],
     'password_reset_finish' => [
         'path' => '/login/password-reset/finish',
         'access' => 'public',
         'methods' => ['POST'],
-        'target' => Controller\LoginController::class . '::passwordResetFinishAction'
+        'target' => Controller\ResetPasswordController::class . '::passwordResetFinishAction'
     ],
 
     // Register login frameset
diff --git a/typo3/sysext/backend/Configuration/Services.yaml b/typo3/sysext/backend/Configuration/Services.yaml
index 1a70905c40dbab47e68bf619fa327a4b7f3f1457..b212c1ce0af3e05f4e8a7ba2d80b604778276501 100644
--- a/typo3/sysext/backend/Configuration/Services.yaml
+++ b/typo3/sysext/backend/Configuration/Services.yaml
@@ -73,6 +73,9 @@ services:
   TYPO3\CMS\Backend\Controller\LoginController:
     tags: ['backend.controller']
 
+  TYPO3\CMS\Backend\Controller\ResetPasswordController:
+    tags: ['backend.controller']
+
   TYPO3\CMS\Backend\Controller\HelpController:
     tags: ['backend.controller']
 
diff --git a/typo3/sysext/backend/Resources/Private/Templates/Login/ForgetPasswordForm.html b/typo3/sysext/backend/Resources/Private/Templates/Login/ForgetPasswordForm.html
index 9c4829211f8cb4cd690cfda0f664dcc821dff214..48efe428a10abfc49d57e57374633c107b23e48d 100644
--- a/typo3/sysext/backend/Resources/Private/Templates/Login/ForgetPasswordForm.html
+++ b/typo3/sysext/backend/Resources/Private/Templates/Login/ForgetPasswordForm.html
@@ -11,7 +11,7 @@
                     <div class="callout-body"><f:translate key="LLL:EXT:backend/Resources/Private/Language/locallang_reset_password.xlf:email_sent.message" arguments="{0: email}" /></div>
                 </div>
                 <p class="pull-right">
-                    <f:be.link route="login"><f:translate key="LLL:EXT:backend/Resources/Private/Language/locallang_reset_password.xlf:button.back_to_login" /></f:be.link>.
+                    <a href="{returnUrl}"><f:translate key="LLL:EXT:backend/Resources/Private/Language/locallang_reset_password.xlf:button.back_to_login" /></a>.
                 </p>
             </f:then>
             <f:else>
@@ -19,8 +19,7 @@
                     <f:be.infobox message="{f:translate(key: 'LLL:EXT:backend/Resources/Private/Language/locallang_reset_password.xlf:error.invalid_email')}" state="1" />
                 </f:if>
                 <p><f:translate key="LLL:EXT:backend/Resources/Private/Language/locallang_reset_password.xlf:instructions.email" /></p>
-                <form action="{f:be.uri(route: 'password_forget_initiate_reset')}" method="post" name="forget-password-form" id="typo3-forget-password-form">
-                    <f:form.hidden name="loginProvider" value="{loginProviderIdentifier}" />
+                <form action="{formUrl}" method="post" name="forget-password-form" id="typo3-forget-password-form">
                     <div class="form-group">
                         <div class="form-control-wrap">
                             <div class="form-control-holder">
@@ -41,7 +40,7 @@
                     </small>
                 </p>
                 <p class="pull-right">
-                    <f:be.link route="login"><f:translate key="LLL:EXT:backend/Resources/Private/Language/locallang_reset_password.xlf:button.back_to_login" /></f:be.link>.
+                    <a href="{returnUrl}"><f:translate key="LLL:EXT:backend/Resources/Private/Language/locallang_reset_password.xlf:button.back_to_login" /></a>.
                 </p>
             </f:else>
         </f:if>
diff --git a/typo3/sysext/backend/Resources/Private/Templates/Login/ResetPasswordForm.html b/typo3/sysext/backend/Resources/Private/Templates/Login/ResetPasswordForm.html
index 071d260877b5c7ee5c9cd29bd368bffbee50048e..226c50825c1e4d7ec98183020ecc5991e86bc4df 100644
--- a/typo3/sysext/backend/Resources/Private/Templates/Login/ResetPasswordForm.html
+++ b/typo3/sysext/backend/Resources/Private/Templates/Login/ResetPasswordForm.html
@@ -8,7 +8,9 @@
             <f:then>
                 <f:be.infobox message="{f:translate(key: 'LLL:EXT:backend/Resources/Private/Language/locallang_reset_password.xlf:error.token_expired')}" title="" state="1" />
                 <p>
-                    <f:be.link class="btn btn-block btn-login" route="password_forget" parameters="{loginProvider: loginProviderIdentifier}"><f:translate key="LLL:EXT:backend/Resources/Private/Language/locallang_reset_password.xlf:button.restart" /></f:be.link>
+                    <a class="btn btn-block btn-login" href="{restartUrl}">
+                        <f:translate key="LLL:EXT:backend/Resources/Private/Language/locallang_reset_password.xlf:button.restart" />
+                    </a>
                 </p>
             </f:then>
             <f:else if="{resetExecuted}">
@@ -26,8 +28,7 @@
                     <f:be.infobox message="{f:translate(key: 'LLL:EXT:backend/Resources/Private/Language/locallang_reset_password.xlf:error.password')}" state="1" />
                 </f:if>
                 <p><f:translate key="LLL:EXT:backend/Resources/Private/Language/locallang_reset_password.xlf:instructions.password" /></p>
-                <form action="{f:be.uri(route: 'password_reset_finish', parameters: '{i: identity, t: token, e: expirationDate}')}" method="post" name="forget-password-form" id="typo3-forget-password-form">
-                    <f:form.hidden name="loginProvider" value="{loginProviderIdentifier}" />
+                <form action="{formUrl}" method="post" name="forget-password-form" id="typo3-forget-password-form">
                     <div class="form-group">
                         <div class="form-control-wrap">
                             <div class="form-control-holder">
diff --git a/typo3/sysext/backend/Resources/Private/Templates/UserPassLoginForm.html b/typo3/sysext/backend/Resources/Private/Templates/UserPassLoginForm.html
index b47560516864d9e393470680819f995a7ab650fb..d803ee70a261372f02189e461ec3d82978de1d1d 100644
--- a/typo3/sysext/backend/Resources/Private/Templates/UserPassLoginForm.html
+++ b/typo3/sysext/backend/Resources/Private/Templates/UserPassLoginForm.html
@@ -29,7 +29,7 @@
 <f:section name="ResetPassword">
     <div class="forgot-password">
         <div class="text-right">
-            <f:be.link route="password_forget" parameters="{loginProvider: loginProviderIdentifier}"><f:translate key="login.password_forget" /></f:be.link>
+            <a href="{forgetPasswordUrl}"><f:translate key="login.password_forget" /></a>
         </div>
     </div>
 </f:section>
diff --git a/typo3/sysext/backend/Tests/Functional/Controller/ResetPasswordControllerTest.php b/typo3/sysext/backend/Tests/Functional/Controller/ResetPasswordControllerTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..2b57f9e8816ddf4f0f8e3087ba51965cfe12d5f8
--- /dev/null
+++ b/typo3/sysext/backend/Tests/Functional/Controller/ResetPasswordControllerTest.php
@@ -0,0 +1,177 @@
+<?php
+
+declare(strict_types=1);
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+namespace TYPO3\CMS\Backend\Tests\Functional\Controller;
+
+use Prophecy\Argument;
+use Psr\Http\Message\ServerRequestInterface;
+use TYPO3\CMS\Backend\Authentication\PasswordReset;
+use TYPO3\CMS\Backend\Controller\ResetPasswordController;
+use TYPO3\CMS\Backend\Routing\UriBuilder;
+use TYPO3\CMS\Backend\Template\ModuleTemplateFactory;
+use TYPO3\CMS\Backend\View\AuthenticationStyleInformation;
+use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
+use TYPO3\CMS\Core\Configuration\Features;
+use TYPO3\CMS\Core\Context\Context;
+use TYPO3\CMS\Core\Context\UserAspect;
+use TYPO3\CMS\Core\Core\SystemEnvironmentBuilder;
+use TYPO3\CMS\Core\Http\PropagateResponseException;
+use TYPO3\CMS\Core\Http\ServerRequest;
+use TYPO3\CMS\Core\Information\Typo3Information;
+use TYPO3\CMS\Core\Localization\LanguageServiceFactory;
+use TYPO3\CMS\Core\Localization\Locales;
+use TYPO3\CMS\Core\Page\PageRenderer;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase;
+
+class ResetPasswordControllerTest extends FunctionalTestCase
+{
+    protected ResetPasswordController $subject;
+    protected ServerRequestInterface $request;
+
+    protected $configurationToUseInTestInstance = [
+        'EXTENSIONS' => [
+            'backend' => [
+                'loginHighlightColor' => '#abcdef'
+            ]
+        ]
+    ];
+
+    protected function setUp(): void
+    {
+        parent::setUp();
+
+        $passwordResetProphecy = $this->prophesize(PasswordReset::class);
+        $passwordResetProphecy->isEnabled()->willReturn(true);
+        $passwordResetProphecy->isValidResetTokenFromRequest(Argument::any())->willReturn(true);
+        $passwordResetProphecy->resetPassword(Argument::any(), Argument::any())->willReturn(true);
+
+        $this->subject = new ResetPasswordController(
+            $this->getService(Context::class),
+            $this->getService(Locales::class),
+            $this->getService(Features::class),
+            $this->getService(UriBuilder::class),
+            $this->getService(PageRenderer::class),
+            $passwordResetProphecy->reveal(),
+            $this->getService(Typo3Information::class),
+            $this->getService(ModuleTemplateFactory::class),
+            $this->getService(AuthenticationStyleInformation::class),
+        );
+
+        $this->request = (new ServerRequest())
+            ->withAttribute('applicationType', SystemEnvironmentBuilder::REQUESTTYPE_BE);
+
+        $GLOBALS['BE_USER'] = new BackendUserAuthentication();
+        $GLOBALS['BE_USER']->initializeUserSessionManager();
+        $GLOBALS['LANG'] = GeneralUtility::makeInstance(LanguageServiceFactory::class)->create('default');
+    }
+
+    /**
+     * @test
+     */
+    public function throwsPropagateResponseExceptionOnLoggedInUser(): void
+    {
+        $backendUser = new BackendUserAuthentication();
+        $backendUser->user['uid'] = 13;
+        GeneralUtility::makeInstance(Context::class)->setAspect('backend.user', new UserAspect($backendUser));
+
+        $this->expectExceptionCode(1618342858);
+        $this->expectException(PropagateResponseException::class);
+        $this->subject->forgetPasswordFormAction($this->request);
+    }
+
+    /**
+     * @test
+     */
+    public function customStylingIsApplied(): void
+    {
+        $response = $this->subject->forgetPasswordFormAction($this->request)->getBody()->getContents();
+        self::assertStringContainsString('/*loginHighlightColor*/', $response);
+        self::assertRegExp('/\.btn-login { background-color: #abcdef; }.*\.card-login \.card-footer { border-color: #abcdef; }/s', $response);
+    }
+
+    /**
+     * @test
+     */
+    public function queryArgumentsAreKept(): void
+    {
+        $queryParams = [
+          'loginProvider'  => '123456789',
+          'redirect' => 'web_list',
+          'redirectParams' => 'id=123'
+        ];
+        $request = $this->request->withQueryParams($queryParams);
+
+        // Both views supply "go back" links which should contain the defined queryParams
+        $expected = htmlspecialchars(http_build_query($queryParams));
+
+        self::assertStringContainsString($expected, $this->subject->forgetPasswordFormAction($request)->getBody()->getContents());
+        self::assertStringContainsString($expected, $this->subject->initiatePasswordResetAction($request)->getBody()->getContents());
+        self::assertStringContainsString($expected, $this->subject->passwordResetAction($request)->getBody()->getContents());
+        self::assertStringContainsString($expected, $this->subject->passwordResetFinishAction($request)->getBody()->getContents());
+    }
+
+    /**
+     * @test
+     */
+    public function initiatePasswordResetPreventsTimeBasedInformationDisclosure(): void
+    {
+        $start = microtime(true);
+        $this->subject->initiatePasswordResetAction($this->request);
+        self::assertGreaterThan(0.2, microtime(true) - $start);
+    }
+
+    /**
+     * @test
+     */
+    public function initiatePasswordResetValidatesGivenEmailAddress(): void
+    {
+        self::assertStringContainsString(
+            'The entered email address is invalid. Please try again.',
+            $this->subject->initiatePasswordResetAction(
+                $this->request->withParsedBody(['email' =>'email..email@example.com'])
+            )->getBody()->getContents()
+        );
+    }
+
+    /**
+     * @test
+     */
+    public function resetPasswordFormUrlContainsQueryParameters(): void
+    {
+        $queryParams = [
+          't'  => 'some-token-123',
+          'i' => 'some-identifier-456',
+          'e' => '1618401660'
+        ];
+        $request = $this->request->withQueryParams($queryParams);
+
+        // Expect the form action to contain the necessary reset query params
+        $expected = '<form action="/typo3/login/password-reset/finish?' . htmlspecialchars(http_build_query($queryParams));
+
+        self::assertStringContainsString($expected, $this->subject->passwordResetAction($request)->getBody()->getContents());
+    }
+
+    protected function getService(string $service, array $constructorArguments = [])
+    {
+        $container = $this->getContainer();
+
+        return $container->has($service)
+            ? $container->get($service)
+            : GeneralUtility::makeInstance($service, ...$constructorArguments);
+    }
+}