NAME MojoX::Authentication - moderately opinionated support module for authentication in Mojolicious applications (local and SAML2) VERSION This document describes MojoX::Authentication version 0.100. SYNOPSIS use MojoX::Authentication; DESCRIPTION This module aims at being a batteries included facility for handling authentication in Mojolicious applications. More documentation will come, but the application in the eg sub-directory contains an example for using the three ways of authentication that are supported: local with in-memory hashes, local with database (SQLite), remote with SAML 2.0. INTERFACE app_startup $ma->app_startup($app); Perform some startup over the $app application, like adding and initializing plugin Mojolicious::Plugin::Authentication and setting a before_render hook to inject the user data in the stash, if present (see "user_stash_key" for the key used in the stash). ctr_credentials_login $ma->ctr_credentials_login($controller, $routes_for); # OR $ma->ctr_credentials_login($controller); Opinionated way of handling the login through credentials, practically acting as a wrapper around the $controller. Assumes that username and secret can be retrieved via param() with keys username and password respectively. The request MUST also carry a valid CSRF token, as checked by "csrf_protect" in Mojolicious::Validator::Validation: parameter csrf_token (put %= csrf_field inside the login form) or, for scripts, header X-CSRF-Token. Otherwise the login is refused (and logged) before any password check, like any other failed login. This protects against login CSRF, i.e. a hostile page silently logging the user in as somebody else:
The $routes_for, if present, is supposed to be a hash reference holding the routes to redirect the client for key ok (in case the interaction is successful) and key not_ok (otherwise). They default to protected_root and public_root respectively. Every attempt costs one password check, whatever the outcome (see "Owner of a username" in MojoX::Authentication::Model), and with the default settings of Crypt::Passphrase::Argon2 a check takes considerable time and memory (256 MiB). The route calling this method should be rate limited (e.g. per client address, in the application or in a reverse proxy), both against guessing passwords and against exhausting the server. Each attempt is logged through $controller->log with the username: info on success, error otherwise. Characters outside printable ASCII (newlines included) are written as \x{..} (e.g. \x{0a}, \x{e9}), so that a username cannot forge log lines. ctr_logout $ma->ctr_logout($controller, $redirect_route); # OR $ma->ctr_logout($controller); Perform the logout, if a user is authenticated. If the user's provider supports the logout method, this delegates the logout to it; otherwise, it calls the logout method over the $controller. If provided, $redirect_route is then used to call the redirect_to method over the $controller, whether a user was authenticated or not. The request MUST carry a valid CSRF token, like for "ctr_credentials_login" (e.g. %= csrf_field inside the logout form, or a csrf_button_to button). Otherwise the user stays logged in, and the redirection to $redirect_route (if provided) still happens. The logout is logged with the user identifier, escaped as in "ctr_credentials_login". ctr_saml2_login $ma->ctr_saml2_login($controller, $route_for); Opinionated way of handling the login through SAML 2.0, practically acting as a wrapper around the $controller. This is the initial request where the user is then sent to the Identity Provider. The $routes_for works like for "ctr_credentials_login", except that in case of success the redirection URL will send the user to the Identity Provider. ctr_saml2_sso_post $ma->ctr_saml2_sso_post($controller, $route_for); # OR $ma->ctr_saml2_sso_post($controller); Opinionated way of handling the login through SAML 2.0, practically acting as a wrapper around the $controller. This is the final request where the user comes back from the Identity Provider. The $routes_for works like for "ctr_credentials_login". No CSRF token is needed here, as the request is posted by the Identity Provider's page: the signed saml-id cookie set by "ctr_saml2_login" ties it to a login started by the same browser. A successful login is logged with the user identifier from the Identity Provider, escaped as in "ctr_credentials_login". A refused login is logged at the error level with the reason, escaped the same way and cut to about 500 characters: the reason can carry text from the response, which is not necessarily what the Identity Provider signed (e.g. its status), so anybody can put text there. The whole message, with any data of the exception (sometimes a full stack trace including the response), is logged as it is at the trace level, for troubleshooting: don't run production at that level. model my $model = $ma->model; Accessor to the model, most probably an instance of MojoX::Authentication::Model. It is mandatory at creation, where it can be: * an object: if it has an authentication_model method, its return value is used, otherwise the object itself; * a sub reference, called without arguments to get the model; * the arguments for creating a new MojoX::Authentication::Model instance (e.g. a hash reference with config and providers). new my $ma = MojoX::Authentication->new(%args); # OR my $ma = MojoX::Authentication->new(\%args); Constructor. Accepts initialization values for "model" (mandatory), "provider_name", and "user_stash_key". It also accepts key -startup with a Mojolicious application, in which case "app_startup" is called on it: my $ma = MojoX::Authentication->new( model => { providers => [ ... ] }, -startup => $app, ); provider_name my $string = $ma->provider_name; Accessor to the (default) provider name, mainly used for SAML 2.0. This works under the assumption that there will only be one identity provider; otherwise you will have to do some more coding on your side. If defined, it takes the precedence over the provider parameter; if neither is present, saml2 is used. This behaviour is subject to change. user_stash_key my $string = $ma->user_stash_key; Accessor to the key (a string) used to set the user in the stash, when available. Defaults to user, so in your templates you should be able to use the $user variable. See "app_startup" for its usage. BUGS AND LIMITATIONS Minimum perl version 5.24. Please report any bug or feature request through the repository of the project, available at https://codeberg.org/polettix/MojoX-Authentication. AI ASSISTANCE This module was developed with the assistance of artificial intelligence (Anthropic Claude Opus 5.5, through Claude Code). The AI was used to: * Write and run new tests. * Conduct code and security reviews, assisting in understanding the issues and checking the fixes. * Write most of the documentation (POD, Changes, and many commit messages), some parts together with the "AUTHOR". Code has generally been written by the "AUTHOR" or, in small parts, by the AI, then reviewed and corrected by the "AUTHOR", who is responsible for the module, under the terms of "COPYRIGHT AND LICENSE". Contributions by the AI can be found in the code repository, where AI-assisted commits carry a Co-Authored-By trailer; see "BUGS AND LIMITATIONS". AUTHOR Flavio Poletti