Mojolicious: Disable Session Support

I’ve been experimenting with different ways of handling sessions with Mojolicious. While the built-in session support does work very well, particularly for Mojo full-stack apps, I wanted to try other mechanics instead, like JWT. Once I got that implemented (which will be its own post soon), I hit a snag: there’s no obvious way in Mojolicious to not enabled its own session handle. Problem? Not really, but it it does lead to at least one effect I wanted to avoid. Namely, a line in the application log:

[2024-03-04 14:07:33.75630] [22] [trace] Your secret passphrase needs to be changed (see FAQ for more)

The reasons for this message are quite clear: I was no longer informing Mojolicious of my secret key, using it for JWT encoding/decoding instead. Again, it would’ve been very easy to workaround this warning by just giving it a random string, but I sought a cleaner solution.

Searching for this error in the Mojo codebase, I easily found it in Mojolicious.pm:

has secrets            => sub {
  my $self = shift;

  # Warn developers about insecure default
  $self->log->trace('Your secret passphrase needs to be changed (see FAQ for more)');

  # Default to moniker
  return [$self->moniker];
};

This snippet shows a Moose-style object attribute secrets whose default value is generated by this anonymous function. Unless it’s overridden, the warning will be printed out when the attribute is accessed. Interesting, but doesn’t really help us.

What I want is to disable sessions entirely, anyway, so I considered the “nuclear” option:

$app->session(undef);

Unfortunately, this immediately led to Internal Server Errors when accessing the backend, so back to the logs:

[2024-03-04 15:00:54.31443] [25] [error] [1_zK-Vk4x63Q] Can't call method "load" on an undefined value at /carton/local/lib/perl5/Mojolicious/Controller.pm line 210.
Mojo::Reactor::Poll: I/O watcher failed: Can't call method "store" on an undefined value at /carton/local/lib/perl5/Mojolicious/Controller.pm line 189.

Seems pretty obvious that we can’t just pass undef but let’s look at the code and make sure. At line 189 of Controller.pm I see

$app->sessions->store($self);

It’s in a conditional within the rendered method, but I don’t really want to mess with mojo.* stash values to avoid executing this (and a bunch of other important stuff would be skipped along with it anyway, so that’s a no-go).

So if Mojolicious won’t let me replace its session manager with nothing, the next-best option seems to be to supply one that simply does nothing:

sub startup ($self) {
  $self->sessions(bless({},'__NoSession'));
  {
    no strict 'refs';
    *{'__NoSession::load'} = *{'__NoSession::store'} = sub{};
  }
}

I didn’t want to have to create a separate file or even a package for this because it’s so stupidly simple, but neither does perl offer the ability to trivially create anonymous classes. So I took the middle ground and used bless to create an anonymous object in a “private” namespace, then tagged onto it the store and load methods, both mapped to a no-op subroutine.


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *