Catalyst::Plugin::Authentication::Internals - All about authentication Stores
Catalyst::Plugin::Authentication provides a standard authentication interface to
application developers using the Catalyst framework. It is designed to allow
application developers to use various methods of user storage and credential
verification. It is also designed to provide for minimal change to the
application when switching between different storage and credential
While Catalyst::Plugin::Authentication provides the interface to the application
developer, the actual work of verifying the credentials and retrieving users
is delegated to separate modules. These modules are called Credentials
and storage backends, or Stores
, respectively. For authentication to
function there must be at least one credential and one store. A pairing of a
store and a credential is referred to as a Realm
. There may be any
number of realms defined for an application, though most applications will not
require more than one or two.
The details of using this module can be found in the
What follows is an explanation of how the module functions internally and what
is required to implement a credential or a store.
There are two main entry points you need to be aware of when writing a store or
credential module. The first is initialization and the second is during the
actual call to the Catalyst application's authenticate method.
A simplified description of the authentication process follows:
- for each realm:
1) The Realm is instantiated using
2) The Store is instantiated using new()
3) The Credential Instantiated using new()
4) Credential and Store objects tied to realm for use during requests
"$c->authenticate( $userinfo, $realm
1) Credential object retrieved for realm
2) Credential's authenticate()
method called with authinfo and realm
object for current realm
The realm object and the authinfo hash are
provided to the credential object's authenticate call. In most cases the
credential object will attempt to retrieve a user using the realm's
find_user() method, which by default relays the call directly to the
Store's find_user() method. It will then usually compare the retrieved
user's information with the information provided in the $authinfo hash. This
is how the default 'Password' credential functions. If the credentials match,
the authenticate() method should return a user object.
3) User object stored in session
If the user object supports session storage,
the successfully authenticated user will be placed in session storage. This is
done by calling the realm object's persist_user() method. The
persist_user() routine by default calls the Store's
for_session() method, which should return serialized data (IE a
scalar). This serialized data is passed back to the store via the
from_session() method, so the data should contain enough information
for the store to recreate / reload the user.
- Per-Request operations
When any user-related activity occurs, and
$c->authenticate has not yet been called, the
Catalyst::Plugin::Authentication module will attempt to restore the persisted
user (normally from the session if one is available). There is only one step
in this process:
1) Store object's from_session() is
The serialized data previously returned by the store's for_session()
method is provided to the from_session()
method should return a valid user object.
Note that the for_session()
is only called during the original $c->
call, so if changes are made to the user that need to be
reflected in your session data, you will want to call the $c->
method - which will perform the session storage process
again (complete with call to for_session()
More detailed information about these processes is below.
When the authentication module is loaded, it reads it's configuration to
determine the realms to set up for the application and which realm is to be
the default. For each realm defined in the application's config,
Catalyst::Plugin::Authentication instantiates both a new credential object and
a new store object. See below for the details of how credentials and stores
: The instances created will remain active throughout the entire
lifetime of the application, and so should be relatively lightweight. Care
should be taken to ensure that they do not grow, or retain information per
request, because they will be involved in each authentication request and
could therefore substantially hurt memory consumption over time.
When "$c->authenticate()" is called from within an application, the
objects created in the initialization process come into play.
"$c->authenticate()" takes two arguments. The first is a hash
reference containing all the information available about the user. This will
be used to locate the user in the store and verify the user's credentials. The
second argument is the realm to authenticate against. If the second argument
is omitted, the default realm is assumed.
The main authentication module then locates the credential and store objects for
the realm specified and calls the credential object's
"authenticate()" method. It provides three arguments, first the
application object, or $c, then a reference to the store object, and finally
the hashref provided in the "$c->authenticate" call. The main
authentication module expects the return value to be a reference to a user
object upon successful authentication. If it receives anything aside from a
reference, it is considered to be an authentication failure. Upon success, the
returned user is marked as authenticated and the application can act
accordingly, using "$c->user" to access the authenticated user,
Astute readers will note that the main Catalyst::Plugin::Authentication module
does not interact with the store in any way, save for passing a reference to
it to the credential. This is correct. The credential object is responsible
for obtaining the user from the provided store using information from the
userinfo hashref and/or data obtained during the credential verification
There are two parts to an authentication store, the store object and the user
Writing a store is actually quite simple. There are only five methods that must
be implemented. They are:
new() - instantiates the store object
find_user() - locates a user using data contained in the hashref
for_session() - prepares a user to be stored in the session
from_session() - does any restoration required when obtaining a user from the session
user_supports() - provides information about what the user object supports
- new( $config, $app, $realm )
- The "new()" method is called only once, during
the setup process of Catalyst::Plugin::Authentication. The first argument,
$config, is a hash reference containing the configuration information for
the store module. The second argument is a reference to the Catalyst
Note that when new() is called, Catalyst has not yet loaded the
various controller and model classes, nor is it definite that other
plugins have been loaded, so your new() method must not rely on any
of those being present. If any of this is required for your store to
function, you should defer that part of initialization until the first
The "new()" method should return a blessed reference to your store
- find_user( $authinfo, $c )
- This is the workhorse of any authentication store. It's job
is to take the information provided to it via the $authinfo hashref and
locate the user that matches it. It should return a reference to a user
object. A return value of anything else is considered to mean no user was
found that matched the information provided.
How "find_user()" accomplishes it's job is entirely up to you, the
author, as is what $authinfo is required to contain. Many stores will
simply use a username element in $authinfo to locate the user, but more
advanced functionality is possible and you may bend the $authinfo to your
needs. Be aware, however, that both Credentials and Stores usually work
with the same $authinfo hash, so take care to avoid overlapping element
Please note that this routine may be called numerous times in various
circumstances, and that a successful match for a user here does NOT
necessarily constitute successful authentication. Your store class should
never assume this and in most cases $c should not be modified by
your store object.
- for_session( $c, $user )
- This method is responsible for preparing a user object for
storage in the session. It should return information that can be placed in
the session and later used to restore a user object (using the
"from_session()" method). It should therefore ensure that
whatever information provided can be used by the
"from_session()" method to locate the unique user being saved.
Note that there is no guarantee that the same Catalyst instance will
receive both the "for_session()" and "from_session()"
calls. You should take care to provide information that can be used to
restore a user, regardless of the current state of the application. A good
rule of thumb is that if "from_session()" can revive the user
with the given information even if the Catalyst application has just
started up, you are in good shape.
- from_session( $c, $frozenuser )
- This method is called whenever a user is being restored
from the session. $frozenuser contains the information that was stored in
the session for the user. This will under normal circumstances be the
exact data your store returned from the previous call to
"for_session()". "from_session()" should return a
valid user object.
OPTIONAL STORE METHODS
- user_supports( $feature, ... )
- This method allows credentials and other objects to inquire
as to what the underlying user object is capable of. This is pretty-well
free-form and the main purpose is to allow graceful integration with
credentials and applications that may provide advanced functionality based
on whether the underlying user object can do certain things. In most cases
you will want to pass this directly to the underlying user class'
"supports" method. Note that this is used as a class
method against the user class and therefore must be able to function
without an instantiated user object.
If you want your store to be able to auto- create users, then you can implement
auto_update_user( $authinfo, $c, $res )
This method is called if the realm's auto_update_user setting is true.
auto_create_user( $authinfo, $c )
This method is called if the realm's auto_create_user setting is true.
The user object is an important piece of your store module. It will be the part
of the system that the application developer will interact with most. As such,
the API for the user object is very rigid. All user objects MUST
inherit from Catalyst::Authentication::User.
The routines required by the Catalyst::Plugin::Authentication plugin are below.
Note that of these, only get_object is strictly required, as the
Catalyst::Authentication::User base class contains reasonable implementations
of the rest. If you do choose to implement only the "get_object()"
routine, please read the base class code and documentation so that you fully
understand how the other routines will be implemented for you.
Also, your user object can implement whatever additional methods you require to
provide the functionality you need. So long as the below are implemented, and
you don't overlap the base class' methods with incompatible routines, you
should experience no problems.
- id( )
- The "id()" method should return a unique id
(scalar) that can be used to retrieve this user from the store. Often this
will be provided to the store's "find_user()" routine as
"id => $user->id" so you should ensure that your store's
"find_user()" can cope with that.
- supports( $feature, $subfeature ... )
- This method checks to see if the user class supports a
particular feature. It is implemented such that each argument provides a
subfeature of the previous argument. In other words, passing 'foo', 'bar'
would return true if the user supported the 'foo' feature, and the 'bar'
feature of 'foo'. This is implemented in Catalyst::Authentication::User,
so if your class inherits from that, you do not need to implement this and
can instead implement supported_features().
Note: If you want the authentication module to be able to save your
user in the session you must return true when presented with the feature
- supported_features( )
- This method should return a hashref of features supported
by the user class. This is for more flexible integration with some
Credentials / applications. It is not required that you support anything,
and returning "undef" is perfectly acceptable and in most cases
what you will do.
- get( $fieldname )
- This method should return the value of the field matching
fieldname provided, or undef if there is no field matching that fieldname.
In most cases this will access the underlying storage mechanism for the
user data and return the information. This is used as a standard method of
accessing an authenticated user's data, and MUST be implemented by all
Note: There is no equivalent 'set' method. Each user class is likely
to vary greatly in how data must be saved and it is therefore impractical
to try to provide a standard way of accomplishing it. When an application
developer needs to save data, they should obtain the underlying object /
data by calling get_object, and work with it directly.
- get_object( )
- This method returns the underlying user object. If your
user object is backed by another object class, this method should return
that underlying object. This allows the application developer to obtain an
editable object. Generally speaking this will only be done by developers
who know what they are doing and require advanced functionality which is
either unforeseen or inconsistent across user classes. If your object is
not backed by another class, or you need to provide additional
intermediate functionality, it is perfectly reasonable to return
Compared to writing a store, writing a credential is very simple. There is only
one class to implement, and it consists of only two required routines. They
new() - instantiates the credential object
authenticate() - performs the authentication and returns a user object
- new( $config, $app, $realm )
- Like the Store method of the same name, the
"new()" method is called only once, during the setup process of
Catalyst::Plugin::Authentication. The first argument, $config, is a hash
reference containing the configuration information for the credential
module. The second argument is a reference to the Catalyst application.
$realm is the instantiated Realm object, which you may use to access realm
routines - such as find_user.
Again, when the credential's new() method is called, Catalyst has not
yet loaded the various controller and model classes.
The new method should perform any necessary setup required and instantiate
your credential object. It should return your instantiated
- authenticate( $c, $realm, $authinfo )
- This is the workhorse of your credential. When
$c->authenticate() is called the
Catalyst::Plugin::Authentication module retrieves the realm object and
passes it, along with the $authinfo hash to your credential's authenticate
method. Your module should use the $authinfo hash to obtain the user from
the realm passed, and then perform any credential verification steps
necessary to authenticate the user. This method should return the user
object returned by the authentication store if credential verification
succeeded. It should return undef on failure.
How your credential module performs the credential verification is entirely
up to you. In most cases, the credential will retrieve a user from the
store first (using the stores find_user() method), and then
validate the user's information. However, this does not have to be the
It is perfectly acceptable for your credential to perform other tasks prior
to attempting to retrieve the user from the store. It may also make sense
for your credential to perform activities which help to locate the user in
question, for example, finding a user id based on an encrypted token. In
these scenarios, the $authinfo hash passed to find_user() can be
different than that which is passed in to $c-> authenticate().
Once again this is perfectly acceptable if it makes sense for your
credential, though you are strongly advised to note this behavior clearly
in your credential's documentation - as application authors are almost
certainly expecting the user to be found using the information provided to
Look at the Catalyst::Authentication::Credential::Password module source to
see this in action. In order to avoid possible mismatches between the
encrypted and unencrypted passwords, the password credential actually
removes the provided password from the authinfo array. It does this
because, in many cases, the store's password field will be encrypted in
some way, and the password passed to $c->authenticate is almost
certainly in plaintext.
NOTE: You should always assume that a store is going to use all the
information passed to it to locate the user in question. If there are
fields in the $authinfo hash that you are sure are specific to your
credential, you may want to consider removing them before user retrieval.
A better solution is to place those arguments that are specific to your
credential within their own subhash named after your module.
The Catalyst::Authentication::Store::DBIx::Class module does this in order
to encapsulate arguments intended specifically for that module. See the
Catalyst::Authentication::Store::DBIx::Class::User source for
Jay Kuri, "email@example.com"
Copyright (c) 2005 the aforementioned authors. All rights reserved. This program
is free software; you can redistribute it and/or modify it under the same
terms as Perl itself.