AUTH: How to more gracefully handle logins and logouts?

Normally I grouse about 3.x being needlessly obtuse relative to 2.x and 1.x.

This time, I’m wondering about something that’s ALWAYS been an issue for me with ALL versions.

I’m talking about the “You are not authorized to access that location” message that comes up when you log out and when you first hit the area you want to access. Deep links, sure, flash the error message. But if I’m on the front page, that’s ridiculous. If I have just logged out, that’s absurd.

I’ve instead opted to suppress the Auth messages entirely (ever so helpful documentation claims you can suppress it until after the user has logged in, which is an absurd proposition since once the user has logged in there is no longer a need for these messages). And try as I might, I’ve never been able to successfully edit that message (for some reason I end up with two messages that have no predictable behavior).

But this has the downside that if a user does try to access a deep link for which they need to be logged in, there’s no error message telling them that. All there is is the login form. Not terrible, but still, why have the auth error messages if you can’t use them in a user-friendly manner?

On a related note:
I would HUGELY prefer if the auth module were an invisible controller EMBED instead of redirect for users. It feels hacky to see the “/users/login” in my history. If I access a protected page, the login prompt should just appear instead of that page and once successfully logged in, the page is revealed and there is no history of the login action to go back to.

Same for logout.

If the auth error message is shown twice, I suspect you’re trying to call a custom flash from inside an isAuthorized function? In any case, if you add the “authError” key to the Auth component config you can override the default value and it shouldn’t affect the way the flash is displayed:

$this->loadComponent('Auth', [
	...
	'authError' => 'You don\'t have permissions to access this part of the site!',
	'flash' => [
		'element' => 'default',
		'key' => 'auth',
		'params' => ['class' => 'error']
	],
	...
]);

You can also configure which element to use for the auth error message and as of v 3.3.3 use html to customize every message even further :smiley:

http://book.cakephp.org/3.0/en/views/helpers/flash.html

I have no idea what you mean by an “invisible controller embed”, but I get what it is you’re looking for… Unfortunately, it’s not really possible to accomplish this with php, since php by its very nature is only active on the server side. So there has to be a page change for the whole authentification shebang to be possible. You’d need something like node.js for it to be feasible in the way you envision.

However, you could use JavaScript to accomplish something similar. I can think of two ways, one being more powerful but impractical and the other one fairly usable but somewhat limited.

So the first option would be to add an event handler that overrides the regular link clicking functionality. What should happen on a click is an ajax event should be fired to see whether the user has permissions to access that page. If yes, a redirect should occur (or the default link behavior should be allowed to take place) and if not, an appropriate auth error message should appear.

The second option is to use polling to simply test whether a user is still logged in or not, and display a message if the user has been logged out, possibly together with a login form.

Neither options are really all that great and certainly far beyond what you can expect from a php framework, so the likelyhood of this type of functionality making it into the framework is 0%.

The default functionality will probably be enough for you, though, once you get it to work :slight_smile: !

What I mean by “invisible” is:

When the request is first made for a given controller/action pair, if the user is not authenticated, then instead of Cake loading the requested controller-action, it loads the users-login pair plus rendering the users/login view template. Without redirecting the user.

Then, users/login.ctp should submit to “the current page” instead of users-login. The same intercept as before would ensure the post data made it to the users-login controller-action, which would then process the login and refresh the same page which now would show the requested controller-action because the user would be authenticated.

This way, the history would all be a single page.

This is really important to users because what I see happen over and over again is: I give users the main url for an app. The page loads. They are not authenticated. They get redirected. Then they bookmark it before logging in. Now they have a useless bookmark because the next time they go to that page and login, successful login just redirects them back to the users-login page that they bookmarked and they think they’re not logged in and don’t know what to do next.

Worse, when someone else asks them for the url, they share the /users/login one that they have bookmarked and it becomes an endemic problem with the user base.

Oh, I get it now; So instead of redirecting to users/login you want to simply render the log in view instead of the action’s regular view!

I guess it’s a rare enough use case that no one really thought it important enough to include as an option to the AuthComponent (most people should get that /login is not the URL they’re looking for - but you never know with some users, so yeah).

As far as I know, there’s no “intended” way of implementing something like this.

But I suppose you could allow everything and then in your beforeFilter do a manual check whether the current action is allowed and if not, render the log in view instead of the normal one.

If you choose to do something like that, please post an update so others can find how this works out in practice.

1 Like