The TYPO3 Core uses Services for the authentication process. This family of services (of type "auth") are the only Core usage that consumes the Services API.
The aim of this chapter is to describe the authentication services so that developers feel confident about writing their own.
Why Use Services?¶
Services provide the flexibility needed for such a complex process of authentication, where many methods may be desirable (single sign-on, IP-based authentication, third-party servers such as LDAP, etc.) depending on the context.
The ease with which such services can be developed is a strong point in favor of TYPO3, especially in corporate environments.
Being able to toy with priority and quality allows for precise fine-tuning of the authentication chain.
Alternative services are available in the TYPO3 Extension Repository. It is thus possible to find solutions for using LDAP as an authentication server, for example.
You can check which authentication services are installed using the System > Reports > Installed Services view:
For the Reports module to be visible, the system extension reports has to be installed. You can install it via Composer:
composer require typo3/cms-reports
The Authentication Process¶
The authentication process is not managed entirely by services.
It is handled essentially by class
for the backend (BE) and by class
for the frontend (FE), which both inherit from class
These classes are called by the
They manage the workflow of the authentication process.
Services are used strictly to identify and validate
users based on whatever form of credentials a given service
relies on (by default, a username and a password).
The authentication process kicks in on every page request, be it in the FE or the BE. However if a valid session already exists, that session is kept. Strictly speaking, no authentication is performed in such a case.
When no session exists, the authentication process is triggered
by a login request. In the frontend, this happens when a form field
logintype is submitted with value
login. The same
happens for the backend, but with a form field called
The login data¶
There is a typical set of data that is transmitted to authentication service in order to enable them to do their work:
This is the user name. This can be whatever makes sense for the available authentication services. For the default service, this will match data from the "username" column of the "be_users" or "fe_users" table for BE or FE authentication respectively.
This is the password, possibly encrypted.
This is the clear text value of the password. If the password is originally submitted in clear text, both "uident" and "uident_text" contain the same value.
Inside an authentication service, this data is available in
The "auth" services API¶
The services of type "auth" are further divided into subtypes, which correspond to various steps in the authentication process. Most subtypes exist for both FE and BE and are differentiated accordingly.
To each subtype corresponds a part of the "auth" services public API. They are listed below in the order in which they are called during the authentication process.
- processLoginDataBE, processLoginDataFE
This subtype performs preprocessing on the submitted login data.
The method to implement is
processLoginData(). It receives as argument the login data and the password transmission strategy (which corresponds to the login security level, where only 'normal' can be used. It returns the boolean value
true, when the login data has been successfully processed .
It may also return a numerical value equal to 200 or greater, which indicates that no further login data processing should take place (see The service chain).
In particular, this subtype is implemented by the TYPO3 Core
AuthenticationService, which trims the given login data.
- getUserFE, getUserBE
This subtype corresponds to the operation of searching in the database if the credentials that were given correspond to an existing user. The method to implement is
getUser(). It is expected to return an array containing the user information or
falseif no user was found.
- authUserFE, authUserBE
This subtype performs the actual authentication based on the provided credentials. The method to implement is
authUser(). It receives the user information (as returned by
getUser()) as an input and is expected to return a numerical value, which is described later.
Before any of the above-mentioned methods are called, the authentication
process will call the
initAuth() method of each service. This
sets up a lot of data for the service. It also makes it possible to
override part of the default settings with
This represents very advanced tuning and is not described here.
Please refer to
to learn more about the possibilities offered during authentication services
The service chain¶
No matter what subtype, authentication services are always called in a chain. This means that all registered "auth" services will be called, in order of decreasing priority and quality.
However, for some subtypes, there are ways to stop the chain.
For "processLoginDataBE" and "processLoginDataFE" subtypes, the
method may return a numerical value of 200 or more. In such a case
no further services are called and login data is not further
processed. This makes it possible for a service to perform
a form of final transformation on the login data.
For "authUserFE" and "authUserBE" subtypes, the
authUser() method may
return different values:
Previously, there was an error in the documentation. It did not match the actual behaviour. This has now been fixed. For details, see forge#91993.
a negative value or 0 (<=0) indicates that the authentication has definitely failed and that no other "auth" service should be called up.
a value larger than 0 and smaller than 100 indicates that the authentication was successful, but that further services should also perform their own authentication.
a value of 100 or more (>= 100) indicates that the user was not authenticated, this service is not responsible for the authentication and that further services should authenticate.
a value of 200 or more (>=200) indicates that the authentication was successful and that no further tries should be made by other services down the chain.
For "getUserFE" and "getUserBE" subtypes, the logic is reversed. The service chain will stop as soon as one user is found.
Developing an authentication service¶
When developing your own "auth" services, the chances are high that you will want to implement only the "getUser*" and "authUser*" subtypes.
There are several public extensions providing such services, so you should be able to find examples to inspire and guide you. Anyway authentication services can be very different from one another, so it wouldn't make much sense to try and provide an example in this manual.
One important thing to know is that the TYPO3 authentication process needs to have users inside database records ("fe_users" or "be_users"). This means that if you interface with a third-party server, you will need to create records on the TYPO3 side. It is up to you to choose whether this process happens on the fly (during authentication) or if you want to create an import process (as a Scheduler task, for example) that will synchronize users between TYPO3 and the remote system.
You probably do not want to store the actual password of imported
users in the TYPO3 database. It is recommended to store
an arbitrary string in such case, making sure that such string
is random enough for security reasons. TYPO3 provides method
which can be used for such a purpose.
authUser() method, you will want to take care
about the return values. If your service should be the final
authority for authentication, it should not only have a high priority,
but also return values which stop the service chain (i.e.
a negative value for failed authentication, 200 or more for a
successful one). On the other hand, if your service is an alternative
authentication, but should fall back on TYPO3 if unavailable,
you will want to return 100 on failure, so that the default service
can take over.
Things can get a bit hairy if you have a scenario with mixed sources, for example some users come from a third-party server but others exist only in TYPO3. In such a case, you want to make sure that your service returns definite authentication failures only for those users which depend on the remote system and let the default authentication proceed for "local" TYPO3 users.
There are some special configuration options which can be used to modify the behaviour of the authentication process. Some impact the inner working of the services themselves, others influence when services are called.
It is possible to force TYPO3 to go through the authentication process for every request no matter any existing session. By setting the following local configuration either for the FE or the BE:
$GLOBALS['TYPO3_CONF_VARS']['SVCONF']['auth']['setup']['BE_alwaysFetchUser'] = true; $GLOBALS['TYPO3_CONF_VARS']['SVCONF']['auth']['setup']['BE_alwaysAuthUser'] = true; $GLOBALS['TYPO3_CONF_VARS']['SVCONF']['auth']['setup']['FE_alwaysFetchUser'] = true; $GLOBALS['TYPO3_CONF_VARS']['SVCONF']['auth']['setup']['FE_alwaysAuthUser'] = true;
the authentication process will be fully run on each request. Both flags may not be necessary depending on what your service does exactly.
This would be an appropriate setting for an IP-based authentication service, as it would revalidate the IP address upon each request.
A more fine-grained approach allows for triggering the authentication process only when a valid session does not yet exist. The settings are:
$GLOBALS['TYPO3_CONF_VARS']['SVCONF']['auth']['setup']['BE_fetchUserIfNoSession'] = true; $GLOBALS['TYPO3_CONF_VARS']['SVCONF']['auth']['setup']['FE_fetchUserIfNoSession'] = true;
This could be used in a scenario where users go through a login portal and then choose to access the TYPO3 backend, for example. In such a case we would want the users to be automatically authenticated, but would not need to repeat the process upon each request.
The authentication process can also be forced to go through all services for the "getUser*" subtype by setting:
$GLOBALS['TYPO3_CONF_VARS']['SVCONF']['auth']['setup']['BE_fetchAllUsers'] = true; $GLOBALS['TYPO3_CONF_VARS']['SVCONF']['auth']['setup']['FE_fetchAllUsers'] = true;
for BE or FE respectively. This will collect all possible users rather than stopping at the first one available.