Require login before viewing restricted pages on the frontend

I’m creating a restricted website that requires users to log in before viewing pages on the frontend.

So I’m thinking I have to use route hooks for this, but I’m struggling to get it right in my config.php. Here is the basic idea of what I’m thinking:

// make sure users are logged in before viewing any frontend page
return [
  'hooks' => [
    'route:before' => function ($route, $path, $method) {
      // only redirect if the user is not logged in, 
      // and didn't request the panel directly
      if ($path != '/panel' && !kirby()->user()) {
        // not working correctly yet, get ERR_TOO_MANY_REDIRECTS
        Header::redirect('/panel', 302, true);
        // tried this as well, also ERR_TOO_MANY_REDIRECTS
        go('/panel', 302);

        // once login is successful, redirect back to
        // whatever route the user requested...
      }
    }
  ]
];

Is my idea correct? Can anyone help me out?

Or is there a different way to do this?

Have you tried using panel without the leading slash?

Nope, thanks! That fixed the too many redirects error. Now it seems like it is redirecting correctly (to /panel/login), but I’m getting a different Kirby error instead:

Unexpected token < in JSON at position 0 :sob:

from app.js:1

I didn’t manage to get it to work… Trying a different approach, trying get my head around these hooks…

Let’s say on every page there is a restricted toggle field.

If the user is not logged in and visits a page that has restricted set to true, how can I simply redirect him to the front page? Or to the panel for a login? Or simply give a 500 error?

I think it is correct to use hooks here, I’m just having a real hard time wrapping my head around them. Here is my basic idea:

'hooks' => [
  // hide restricted pages if user not logged in
  'route:before' => function ($route, $path, $method) {
    if ($this->site()->page()->restricted()->isTrue() && !kirby()->user()) {
      Header::forbidden(true);
    }
  }
]

*edits: changed some code, using $this to access the Kirby instance as described in the docs. Still not correct though.

Ancient thread, I know, but just dropping this here as I was looking for something similar and created a working piece of code – in case anybody ever needs this snippet:

'route:before' => function ($route, $path, $method) {
	if (!kirby()->user() && $path != 'panel' && substr($path, 0, 4) != 'api/') {
		go('panel', 302);
	}
},

It’s important to also exclude any requests to Kirby’s API, as the Panel application communicates with it (hence the Unexpected token < in JSON at position 0 error described above).