Kirby()->user() returns null when Kirby is installed in a Sub Folder

Hi!

I have added a custom route (/foo/bar) that’s defined inside config.php which should only be executable if the user is logged in inside the panel:

return [
    ...
    'routes' => [
        [
          'pattern' => 'foo/bar',
          'action'  => function () {
              $user = kirby()->user();
              if ($user->isLoggedIn()) {
                  // logic if user is logged in here ...
                  return [
                      'status' => 200
                  ]
              }
              return [
                  'status' => 401
              ]
          }
        ]
    ]
]

This works in general. However, once I moved Kirby in a sub directory (/cms), the user object is always null and in return an exception is thrown:

For reference, this is my .htaccess file where I only added a folder (frontend) that should not be accessible and adjusted the rewrite rule regarding installing Kirby in a sub folder:

# Kirby .htaccess
# revision 2023-07-22

# rewrite rules
<IfModule mod_rewrite.c>

# enable awesome urls. i.e.:
# http://yourdomain.com/about-us/team
RewriteEngine on

# make sure to set the RewriteBase correctly
# if you are running the site in a subfolder;
# otherwise links or the entire site will break.
#
# If your homepage is http://yourdomain.com/mysite,
# set the RewriteBase to:
#
RewriteBase /cms

# In some environments it's necessary to
# set the RewriteBase to:
#
# RewriteBase /

# block files and folders beginning with a dot, such as .git
# except for the .well-known folder, which is used for Let's Encrypt and security.txt
RewriteRule (^|/)\.(?!well-known\/) index.php [L]

# block all files in the content folder from being accessed directly
RewriteRule ^content/(.*) index.php [L]

# block all files in the site folder from being accessed directly
RewriteRule ^site/(.*) index.php [L]

# block direct access to Kirby and the Panel sources
RewriteRule ^kirby/(.*) index.php [L]

# make site links work
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*) index.php [L]

# block frontend code folder from accessing
RewriteRule ^frontend/ - [F]

</IfModule>

# pass the Authorization header to PHP
SetEnvIf Authorization "(.+)" HTTP_AUTHORIZATION=$1

# compress text file responses
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE text/javascript
AddOutputFilterByType DEFLATE application/json
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/x-javascript
</IfModule>

# set security headers in all responses
<IfModule mod_headers.c>

# serve files as plain text if the actual content type is not known
# (hardens against attacks from malicious file uploads)
Header set Content-Type "text/plain" "expr=-z %{CONTENT_TYPE}"
Header set X-Content-Type-Options "nosniff"

</IfModule>

Why is it null? How can I check if the user is logged in or not in my case? Is this maybe a Bug?

Thanks

This code is not really valid. kirby()->user() (without an id as param) only returns a user object if a user is logged in, so you cannot check if a user is logged in if there is no logged in user.

So change this to

if ($user = kirby()->user()) {
  return [ 'status' => 200]
}

return [ 'status' => 401]

Thank you for your fast reply!

Sadly, your suggested code does not work either - it still does not state that I am logged in. Maybe worth mentioning what I am doing: Via some JS I have added a button to the panel frontend to send a request to the route. Unfortunately, the login check still returns a json with the status of 401 with your suggested code (even though I am logged in):

This is the code now (cms/site/config.php):

return [
    ...
    'routes' => [
        [
          'pattern' => 'foo/bar',
          'action'  => function () {
              if ($user = kirby()->user()) {
                return [ 'status' => 200];
              }
              
              return [ 'status' => 401];
          }
        ]
    ]
]

If it matters: I only have one user (admin@example.com) and I just want to check if the user is currently logged in or not in the browser.

What I don’t get is, before moving everything to a Sub Folder this worked (as suggested here Check for logged-in user from within router plugin - #2 by texnixe):

if (($user = kirby()->user()) && $user->isLoggedIn()) {
  // do stuff
}

Well, the purpose of my code suggestion was to prevent the “Calling function x on null” error.

At least that problem is solved.

But I have no idea how your subfolder setup together with the rewrite rule relates to the user not being found.

Does the route work on its own, if you just open it in the browser?

Maybe set up a virtual host for the subfolder instead and remove the rewrite rules, should solve the issue.

1 Like

Thanks to your hint checking the route directly, I noticed the issue: Instead of doing the fetch request to /cms/foo/bar (because Kirby is installed in a Sub Directory), I was doing the request to /foo/bar, which interestingly still worked as a route to return something but I guess it was not in the right “kirby context”.