NAME

    MojoX::Authentication - moderately opinionated support module for
    authentication in Mojolicious applications (local and SAML2)

VERSION

    This document describes MojoX::Authentication version 0.099.

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:

       <form method="POST" action="/public/login">
          %= csrf_field
          <input type="text" name="username">
          <input type="password" name="password">
          <input type="submit" value="login">
       </form>

    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 <flavio@polettix.it>

COPYRIGHT AND LICENSE

    Copyright 2026 by Flavio Poletti <flavio@polettix.it>

    Licensed under the Apache License, Version 2.0 (the "License"); you may
    not use this file except in compliance with the License. You may obtain
    a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
    implied. See the License for the specific language governing
    permissions and limitations under the License.

