Unauthorized access redirect to URL without App.base value

Hello. I setup my app in a subdirectory, say it’s ‘/my_app’. The authentication and authorization are working well except unauthorized page direction. I want to show a message so that a user can see the message saying it’s not authorized.

The below is a part from ‘middleware’ function in /src/Application.php. I set the ‘url’ to ‘/pages/unauthorized’. And my ‘App.base’ in /config/app.php is set to ‘/my_app’.

If a user trys to something not authorized, it’s redirected to /pages/unauthorized instead of /my_app/pages/unauthorized. And it generate 404 error. I can add ‘/my_app’ to the ‘url’ of unauthorizedHandler, and it shows the page if I do so. But I wonder if my setting the app in subdirectory is not configured correctly. Or, is it an expected behavior?

I tried default ‘App.base’ value which is ‘false’. But it’s the same.

So far, this is the only known issue with setting up an app in the subdirectory. I would appreciate it if someone can help me!

->add(new AuthorizationMiddleware($this, [
	'unauthorizedHandler' => [
		'className' => 'Authorization.Redirect', // Use the built-in Redirect handler
		'url' => '/pages/unauthorized', // Redirect to the **login** page
		'queryParam' => 'redirectUrl', // Add a query parameter for the original URL
		'exceptions' => [
			ForbiddenException::class, // Handle ForbiddenException specifically
		],
	],

Instead of ‘/pages/unauthorized’

Try a Router array or use Router::url to generate the redirect URL which should properly prepend the sub directory.

'url' => [ 'controller' => 'Pages', 'action' => 'unauthorized' ];
1 Like

Thank you, jmcd73.

I don’t fully understand your suggestions but I could not make it work. I replaced the ‘/pages/unauthorized’ with your array, [ ‘controller’ => ‘Pages’, ‘action’ => ‘unauthorized’ ], and throws error saying it has to be string instead of array.

Then I tried with:
'url' => Router::url([ ‘controller’ => ‘Pages’, ‘action’ => ‘display’, ‘unauthorized’ ])
but that throws ‘A route matching `array ( ‘controller’ => ‘Pages’, ‘action’ => ‘display’, 0 => ‘unauthorized’, ‘plugin’ => NULL, ‘_ext’ => NULL, )` could not be found.‘ error.

I tried to add a route like the below but it did not help:
$routes->connect(‘/unauthorized’, [‘controller’ => ‘Pages’, ‘action’ => ‘display’, ‘unauthorized’]);

I would really appreciate it if you can explain me more details of your suggestions.

Sounds like something else might be wrong.

Have you setup Pages/unauthenticated.php so it can be accessed without being authenticated? Can you access it directly without being logged in?

What version of CakePHP are you using. How are you serving it? (e.g. Apache,nginx, bin/cake server)

I was thinking using Router::url would prepend the subdir correctly. I create the unauthenticated url dynamically.

private function getRedirect(): array
    {
        return [
            'prefix' => false,
            'plugin' => null,
            'controller' => 'Users',
            'action' => 'login',
        ];
    }

    public function getAuthenticationService(ServerRequestInterface $request): AuthenticationServiceInterface
    {
        $authenticationService = new AuthenticationService();

        $loginUrl = Router::url($this->getRedirect());

        $authenticationService->setConfig([
            'unauthenticatedRedirect' => $loginUrl,
            'queryParam' => 'redirect',
        ]);

Thank you very much, James.

My CakePHP is version 5.2.6, PHP is 8.2.15, on Debian 11 with Apache 2.4.59
I have not setup Pages/authenticated.php, because I thought “unauthorized“ would take care of it.

Anyway, I only have Pages/unauthorized.php. And if I try it without authentication, it redirects to users/login.php. And that is what I expect. My app is for a small business but with several different roles. And I want users to see the unauthorized message if any actions are not appropriate.

Anyway, for getAuthenticationService() functions, I do not have any issue. The below is a copy, and it goes to /myapp/users/login. And I only have an issue with “authorization”.

I am sorry if I did not make myself clear before. But I would appreciate your help!

	public function getAuthenticationService(ServerRequestInterface $request): AuthenticationServiceInterface
	{
		$authenticationService = new AuthenticationService([
			'unauthenticatedRedirect' => Router::url('/https/discourse.cakephp.org/users/login'),
			'queryParam' => 'redirect',
		]);

		 $loginUrl = Router::url($this->getRedirect());
		
		// Load the authenticators, you want session first
		$authenticationService->loadAuthenticator('Authentication.Session');
		// Configure form data check to pick email and password
		$authenticationService->loadAuthenticator('Authentication.Form', [
			'fields' => [
				'username' => 'email',
				'password' => 'password',
			],
			'loginUrl' => Router::url('/https/discourse.cakephp.org/users/login'),
			'identifier' => [
				'Authentication.Password' => [
					'fields' => [
						'username' => 'email',
						'password' => 'password',
					],
				],
			],
		]);

		return $authenticationService;
	}

Hi James, I was able to fix my problem!

I don’t know why it did not work before but your suggestion of “Router::url” works now.Thank you!

I set subdirectory name: ‘App’ => [‘base’ => ‘/myapp’], instead of ‘false’. And the below ‘Router::url()’ gets the subdirectory name of ‘myapp’.

Thank you, thank you, thank you!!!

			->add(new AuthorizationMiddleware($this, [
				'unauthorizedHandler' => [
					'className' => 'Authorization.Redirect',
					// 'url' => '/pages/unauthorized',
					'url' => Router::url('/https/discourse.cakephp.org/pages/unauthorized'),
					'queryParam' => 'redirectUrl',
					'exceptions' => [
						MissingIdentityException::class,
						ForbiddenException::class,
						OtherException::class,
					],
				],
			]));