title: Cakephp 3.7, Middleware, Authentication and Routing
body: <p>I'm using Cakephp 3.7 and authentication middleware.</p>
  
  <p>My app is hosted locally at <a href="http://192.168.33.10/scoring" rel="nofollow noreferrer">http://192.168.33.10/scoring</a>.</p>
  
  <p>I'm using the following middleware method in my Application.php.  </p>
  
  <pre><code>&lt;?php
  /**
  * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
  * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  *
  * Licensed under The MIT License
  * For full copyright and license information, please see the LICENSE.txt
  * Redistributions of files must retain the above copyright notice.
  *
  * @copyright Copyright (c) Cake Software Foundation, Inc. 
  (https://cakefoundation.org)
  * @link      https://cakephp.org CakePHP(tm) Project
  * @since     3.3.0
  * @license   https://opensource.org/licenses/mit-license.php MIT License
  */
  namespace App;
  
  
  use Authentication\AuthenticationService;
  use Authentication\AuthenticationServiceProviderInterface;
  use Authentication\Middleware\AuthenticationMiddleware;
  use Cake\Core\Configure;
  use Cake\Core\Exception\MissingPluginException;
  use Cake\Error\Middleware\ErrorHandlerMiddleware;
  use Cake\Http\BaseApplication;
  use Cake\Routing\Middleware\AssetMiddleware;
  use Cake\Routing\Middleware\RoutingMiddleware;
  use Cake\Routing\Router;
  use Psr\Http\Message\ResponseInterface;
  use Psr\Http\Message\ServerRequestInterface;
  
  /**
  * Application setup class.
  *
  * This defines the bootstrapping logic and middleware layers you
  * want to use in your application.
  */
  class Application extends BaseApplication implements 
  AuthenticationServiceProviderInterface
  {
  /**
   * {@inheritDoc}
   */
  public function bootstrap()
  {
  
      $this-&gt;addPlugin('CakeDC/Enum');
  
      $this-&gt;addPlugin('Muffin/Trash');
  
      $this-&gt;addPlugin('AuditStash');
  
      // Call parent to load bootstrap from files.
      parent::bootstrap();
  
      // include required plugins
      $this-&gt;addPlugin('Authentication');
  
      if (PHP_SAPI === 'cli') {
          try {
              $this-&gt;addPlugin('Bake');
          } catch (MissingPluginException $e) {
              // Do not halt if the plugin is missing
          }
  
          $this-&gt;addPlugin('Migrations');
      }
  
      /*
       * Only try to load DebugKit in development mode
       * Debug Kit should not be installed on a production system
       */
      if (Configure::read('debug')) {
          $this-&gt;addPlugin(\DebugKit\Plugin::class);
      }
  }
  
  /**
   * Returns a service provider instance.
   *
   * @param \Psr\Http\Message\ServerRequestInterface $request Request
   * @param \Psr\Http\Message\ResponseInterface $response Response
   * @return \Authentication\AuthenticationServiceInterface
   */
  public function getAuthenticationService(ServerRequestInterface $request, ResponseInterface $response)
  {
      $service = new AuthenticationService();
  
      $fields = [
          'username' =&gt; 'email',
          'password' =&gt; 'password'
      ];
  
      // Load identifiers
      //$service-&gt;loadIdentifier('Authentication.Password', compact('fields'));
      $service-&gt;loadIdentifier('Development', compact('fields'));
  
      // Load the authenticators, you want session first
      $service-&gt;loadAuthenticator('Authentication.Session');
      $service-&gt;loadAuthenticator('Authentication.Form', [
          'fields' =&gt; $fields
      ]);
  
      return $service;
  }
  
  /**
   * Setup the middleware queue your application will use.
   *
   * @param \Cake\Http\MiddlewareQueue $middlewareQueue The middleware queue to setup.
   * @return \Cake\Http\MiddlewareQueue The updated middleware queue.
   */
  public function middleware($middlewareQueue)
  {
  
      // Add the authentication middleware
      $authentication = new AuthenticationMiddleware($this, [
          'unauthenticatedRedirect' =&gt; Router::url(['controller' =&gt; 'Users', 'action' =&gt; 'login']),
      ]);
  
      $middlewareQueue
  
          // Catch any exceptions in the lower layers,
          // and make an error page/response
          -&gt;add(new ErrorHandlerMiddleware(null, Configure::read('Error')))
  
          // Handle plugin/theme assets like CakePHP normally does.
          -&gt;add(new AssetMiddleware([
              'cacheTime' =&gt; Configure::read('Asset.cacheTime')
          ]))
  
          // Add routing middleware.
          // Routes collection cache enabled by default, to disable route caching
          // pass null as cacheConfig, example: `new RoutingMiddleware($this)`
          // you might want to disable this cache in case your routing is extremely simple
          -&gt;add(new RoutingMiddleware($this, '_cake_routes_'))
  
          // Add the authentication middleware to the middleware queue
          -&gt;add($authentication);
  
      return $middlewareQueue;
  }
  </code></pre>
  
  <p>}</p>
  
  <p>I have the following in config/routes.php:</p>
  
  <pre><code>&lt;?php
      /**
       * Routes configuration
       *
       * In this
  
   file, you set up routes to your controllers and their actions.
   * Routes are very important mechanism that allows you to freely connect
   * different URLs to chosen controllers and their actions (functions).
   *
   * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
   * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
   *
   * Licensed under The MIT License
   * For full copyright and license information, please see the LICENSE.txt
   * Redistributions of files must retain the above copyright notice.
   *
   * @copyright     Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
   * @link          https://cakephp.org CakePHP(tm) Project
   * @license       https://opensource.org/licenses/mit-license.php MIT License
   */
  use Cake\Http\Middleware\CsrfProtectionMiddleware;
  use Cake\Routing\RouteBuilder;
  use Cake\Routing\Router;
  use Cake\Routing\Route\DashedRoute;
  
  /**
   * The default class to use for all routes
   *
   * The following route classes are supplied with CakePHP and are appropriate
   * to set as the default:
   *
   * - Route
   * - InflectedRoute
   * - DashedRoute
   *
   * If no call is made to `Router::defaultRouteClass()`, the class used is
   * `Route` (`Cake\Routing\Route\Route`)
   *
   * Note that `Route` does not do any inflections on URLs which will result in
   * inconsistently cased URLs when used with `:plugin`, `:controller` and
   * `:action` markers.
   *
   * Cache: Routes are cached to improve performance, check the RoutingMiddleware
   * constructor in your `src/Application.php` file to change this behavior.
   *
   */
  Router::defaultRouteClass(DashedRoute::class);
  
  Router::scope('/', function (RouteBuilder $routes) {
      // Register scoped middleware for in scopes.
      $routes-&gt;registerMiddleware('csrf', new CsrfProtectionMiddleware([
          'httpOnly' =&gt; true
      ]));
  
      /**
       * Apply a middleware to the current route scope.
       * Requires middleware to be registered via `Application::routes()` with `registerMiddleware()`
       */
      $routes-&gt;applyMiddleware('csrf');
  
      /**
       * Here, we are connecting '/' (base path) to a controller called 'Pages',
       * its action called 'display', and we pass a param to select the view file
       * to use (in this case, src/Template/Pages/home.ctp)...
       */
      $routes-&gt;connect('/', ['controller' =&gt; 'Pages', 'action' =&gt; 'display', 'home']);
  
      //connect login route
      $routes-&gt;connect('/login', ['controller' =&gt; 'Users', 'action' =&gt; 'login']);
  
      //connect logout route
      $routes-&gt;connect('/logout', ['controller' =&gt; 'Users', 'action' =&gt; 'logout']);
  
      /**
       * ...and connect the rest of 'Pages' controller's URLs.
       */
      $routes-&gt;connect('/pages/*', ['controller' =&gt; 'Pages', 'action' =&gt; 'display']);
  
      /**
       * Connect catchall routes for all controllers.
       *
       * Using the argument `DashedRoute`, the `fallbacks` method is a shortcut for
       *
       * ```
       * $routes-&gt;connect('/:controller', ['action' =&gt; 'index'], ['routeClass' =&gt; 'DashedRoute']);
       * $routes-&gt;connect('/:controller/:action/*', [], ['routeClass' =&gt; 'DashedRoute']);
       * ```
       *
       * Any route class can be used with this method, such as:
       * - DashedRoute
       * - InflectedRoute
       * - Route
       * - Or your own route class
       *
       * You can remove these routes once you've connected the
       * routes you want in your application.
       */
      $routes-&gt;fallbacks(DashedRoute::class);
  });
  
  /**
   * If you need a different set of middleware or none at all,
   * open new scope and define routes there.
   *
   * ```
   * Router::scope('/api', function (RouteBuilder $routes) {
   *     // No $routes-&gt;applyMiddleware() here.
   *     // Connect API actions here.
   * });
   * ```
   */
  
  Router::prefix('admin', function ($routes) {
      // All routes here will be prefixed with `/admin`
      // And have the prefix =&gt; admin route element added.
  
      $routes-&gt;fallbacks(DashedRoute::class);
  
  
  });
  </code></pre>
  
  <p>The issue I'm having is that the redirect goes to <a href="http://192.168.33.10/login" rel="nofollow noreferrer">http://192.168.33.10/login</a> rather than going to <a href="http://192.168.33.10/scoring/login" rel="nofollow noreferrer">http://192.168.33.10/scoring/login</a>.  </p>
  
  <p>In troubleshooting my issue, I've discovered that the Router::url method will return /login if run in Application.php, but will return /scoring/login if run from AppController.php.</p>
  
  <p>Obviously there's something I'm not seeing that's crossing up between the Routing middleware and the authentication middleware.  I'm fairly new to the latest version of Cakephp and the integration of middleware, so I'm sure I've made an error somewhere.  </p>
  
  <p>Can someone help identify my error?</p>