Login in Joomla
Every Joomla website has a door. You walk through it every time you open /administrator/ and type your username and password. That door is a small but important core component called com_login.
This article explains how Joomla login really works. It covers the basics for owners and editors, the daily setup for administrators, and the technical details for developers. You will learn the difference between the backend login and the frontend login, how the login modules work, what actually happens when you press the button, and how authentication plugins decide whether to let you in.
Login is not one feature. It is a small component, a set of modules, and a chain of plugins working together.
The goal is simple: help you understand Joomla login well enough to configure it, secure it, and debug it with confidence.
1. The Basics
1.1 What is com_login?
The Login component (com_login) is the core component that shows the backend login form and handles the login and logout of administrators. It is the screen you see at /administrator/ before you are signed in.
It is a deliberately tiny component. It stores no data of its own, has a single view, and accepts only two tasks: login and logout. Everything else, such as checking the password or starting the session, is handled by Joomla's shared authentication layer and by plugins.
1.2 Two Doors, Not One
This is the single most important idea in this article. Joomla has two separate logins:
| Login | Handled by | URL |
|---|---|---|
| Backend (administrator) | com_login + admin mod_login |
/administrator/ |
| Frontend (site) | com_users (Login view) + site mod_login |
index.php?option=com_users&view=login |
Both doors use the same underlying engine, but they are wired up by different extensions. When someone says "the Joomla login", always ask: front or back?
1.3 Where to Find It
You never browse to com_login from a menu. Joomla shows it automatically when an unauthenticated visitor reaches the administrator area:
/administrator/index.php?option=com_login&view=login
If your session times out while you are working in the backend, Joomla quietly drops you back onto this same view.
Back to top2. The Backend Login Screen
2.1 What You See
The backend login screen is small on purpose: a username field, a password field, an optional secret key field for multi-factor authentication, and a language selector. There is no registration link and no "create account" option, because the backend is for staff, not for the public.
2.2 The Screen Is Built From a Module
Just like the Control Panel, the login screen is not a hard-coded form. The component view renders an administrator login module (mod_login) and any other modules published to the special login position:
// administrator/components/com_login/tmpl/login/default.php
$loginmodule = LoginModel::getLoginModule('mod_login');
echo ModuleHelper::renderModule($loginmodule, ['id' => 'section-box']);
This means you can add extra boxes (a notice, a logo, a security warning) to the backend login by publishing modules to the login position on the administrator side.
2.3 A Built-in Clickjacking Defence
When the login view renders, the controller sends an extra HTTP header:
$this->app->setHeader('X-Frame-Options', 'SAMEORIGIN');
This stops another website from loading your login form inside a hidden frame and tricking an administrator into clicking on it. It is a small detail, but it shows that login is treated as a security-sensitive screen from the very first request.
Back to top3. The Frontend Login
3.1 A Different Component
The frontend login is not part of com_login. It lives in com_users, the same component that handles registration, password reset, and user profiles. The login form a visitor sees comes from the Login view of com_users or from the site version of mod_login.
To give visitors a login page, you create a menu item of type Users → Login Form. You can also drop a site mod_login module into any template position.
3.2 Login Redirects
The frontend login module has two useful settings most owners overlook:
- Login Redirect: the page a user lands on after a successful login (for example a members dashboard).
- Logout Redirect: the page a user lands on after logging out (for example the homepage).
You can leave them empty to return the user to the same page, or set them to guide members to the right place.
3.3 The Guest Trick
A classic pattern is to show the login module only to visitors who are not yet logged in. Set the module's Access level to Guest, and Joomla hides it automatically the moment the visitor signs in. Pair it with a "My Account" module set to Registered, and the right box always shows.
Back to top4. The Login Modules
4.1 One Name, Two Clients
There are two mod_login modules in Joomla, one for each client:
| Module | Client | Job |
|---|---|---|
Site mod_login |
Frontend (client_id = 0) |
Visitor login box on the public site. |
Administrator mod_login |
Backend (client_id = 1) |
The form rendered by com_login. |
4.2 The Failsafe That Saves Locked-out Admins
The login model loads the backend login module in an unusual way. It ignores the module's published state and its access level on purpose. The core comment explains why:
"This is put in as a failsafe to avoid super user lock out caused by an unpublished login module or by a module set to have a viewing access level that is not Public."
In plain terms: even if you accidentally unpublish the backend login module or set its access to a non-public level, you can still log in. The login form will always render. This is a deliberate safety net, not a bug.
4.3 Remember Me
The site login module offers a Remember Me checkbox. When ticked, Joomla stores a long-lived cookie so the visitor stays logged in across browser sessions. This feature depends on the Authentication - Cookie plugin being enabled, which the next section explains.
Back to top5. What Happens When You Log In
5.1 The Four Steps
Pressing the login button starts a clear, four-step chain inside Joomla's application object:
1. AUTHENTICATE Who are you? Is the password correct?
→ event onUserAuthenticate (authentication plugins)
2. AUTHORISE Are you allowed to log in to this client?
→ event onUserAuthorisation
3. LOGIN Start the session, fire side effects.
→ event onUserLogin (user plugins)
4. REDIRECT Send you to the return URL or the dashboard.
The component itself only kicks off the chain with a single call:
$app->login($credentials, ['action' => 'core.login.admin']);
The action tells Joomla which door is being used: core.login.admin for the backend, core.login.site for the frontend.
5.2 Authentication vs Authorisation
These two words sound alike but mean different things, and login uses both:
- Authentication answers "are you who you say you are?" It checks the password (or a passkey, or an LDAP server).
- Authorisation answers "are you allowed in here?" A valid user with no backend login permission passes authentication but fails authorisation.
A user can have a perfectly correct password and still be refused at the backend door, because authentication and authorisation are separate gates.
5.3 What the Login Event Does
When login succeeds, the onUserLogin event fires and the core User - Joomla plugin does the real work: it writes the session, records the visit, and loads the user's groups. This is why you must never disable the User - Joomla plugin. Without it, nobody can log in.
6. Authentication Plugins
6.1 The Plugin Decides, Not the Component
Joomla does not hard-code how a password is checked. Instead it asks every enabled authentication plugin the question "do these credentials check out?" through the onUserAuthenticate event. Each plugin returns success, failure, or "not my job".
Joomla 6 ships three core authentication plugins:
| Plugin | What it does |
|---|---|
| Authentication - Joomla | The default. Checks the username and the bcrypt password hash in #__users. Keep this enabled. |
| Authentication - Cookie | Powers the Remember Me feature with a secure long-lived cookie. |
| Authentication - LDAP | Checks credentials against an external LDAP or Active Directory server. Off by default. |
6.2 How Passwords Are Stored
The Authentication - Joomla plugin never deals with a plain-text password in storage. Joomla saves each password as a salted bcrypt hash in the password column of #__users, created with PHP's native password hashing API. A stored value looks like this:
$2y$10$Ux3... (algorithm, cost, salt, and hash in one string)
Two consequences matter in practice:
- Even a Super User cannot read a user's password. A forgotten password can only be reset, never recovered.
- Joomla rehashes on login. When you sign in, the plugin checks whether the stored hash still uses the current algorithm and cost. If it does not, Joomla transparently re-hashes the password and saves the stronger version. Your stored credentials get safer over time without anyone lifting a finger.
6.3 The Secret Key Field and MFA
The third field on the login form, the secret key, feeds Joomla's multi-factor authentication. After the password is accepted, Joomla can require a second factor (a TOTP code, a passkey, an email code) before the session is fully trusted. This is the captive login flow: a logged-in user with an unmet MFA requirement is held on the verification page until they complete it.
6.4 Single Sign-On and Custom Logins
Because authentication is plugin-based, you can extend it. Need login via Google, Microsoft, SAML, or your own API? You write (or install) an authentication plugin that subscribes to onUserAuthenticate. You never edit com_login itself. This is the same decoupling pattern Joomla uses everywhere: the core asks a question, and plugins answer.
7. Permissions and Access
7.1 The Two Login Permissions
Whether a user group may log in at all is an ACL decision, set in System → Global Configuration → Permissions:
| Action | Meaning |
|---|---|
Site Login (core.login.site) |
The group may log in on the frontend. |
Administrator Login (core.login.admin) |
The group may log in on the backend. |
These are exactly the action values passed to $app->login(). A group without Administrator Login set to Allowed cannot reach the backend, no matter how correct the password is.
7.2 Why You Cannot Lock Yourself Out of the Login Form
The login component removes its own ACL gate. Its dispatcher overrides the access check with an empty method:
protected function checkAccess()
{
// com_login does not require check permission
}
If com_login enforced a permission, a single bad ACL change could lock every administrator out of the backend with no way back in. By leaving the gate open, Joomla guarantees the login form is always reachable. The real access decision happens one step later, during the authorisation step of the login itself.
8. Under the Hood (Developer View)
8.1 Component Structure
com_login exists only on the administrator side. There is no frontend folder and no sql/ folder, because the component stores nothing:
administrator/components/com_login/
├─ services/provider.php (DI container wiring)
├─ src/
│ ├─ Controller/DisplayController.php
│ ├─ Dispatcher/Dispatcher.php
│ ├─ Model/LoginModel.php
│ └─ View/Login/HtmlView.php
├─ tmpl/login/default.php (renders the login module)
└─ login.xml (manifest)
8.2 The Dispatcher Restricts the Tasks
The component will only ever do two things. The dispatcher throws away any task that is not login or logout:
$task = $this->input->get('task');
if ($task != 'login' && $task != 'logout') {
$this->input->set('task', '');
}
This narrows the attack surface: you cannot trick the component into running some other controller method.
8.3 The Controller: login and logout
The controller is short. The login task checks the CSRF token, reads the credentials from the model, calls $app->login(), then redirects:
public function login()
{
$this->checkToken();
$app = $this->app;
$model = $this->getModel('login');
$credentials = $model->getState('credentials');
$return = $model->getState('return');
$app->login($credentials, ['action' => 'core.login.admin']);
if (Uri::isInternal($return) && !str_contains($return, 'tmpl=component')) {
$app->redirect($return);
} else {
$app->redirect('index.php');
}
}
Two security details stand out. The checkToken() call blocks cross-site request forgery, and the Uri::isInternal() check stops an open-redirect attack: a crafted return URL can never bounce you to an external site after login.
8.4 The Model Reads the Credentials Safely
The model collects the submitted values with strict input filters and decodes the return URL from Base64, again validating that it stays internal:
$credentials = [
'username' => $input->get('username', '', 'USERNAME'),
'password' => $input->get('passwd', '', 'RAW'),
'secretkey' => $input->get('secretkey', '', 'RAW'),
];
if ($return = $input->get('return', '', 'BASE64')) {
$return = base64_decode($return);
if (!Uri::isInternal($return)) {
$return = '';
}
}
8.5 Logging Out in Code
Logout mirrors login. It checks the token, then calls the application:
$app->logout($userid, ['clientid' => $clientid]);
The clientid decides which session to end. If shared_session is on, logging out of one client logs the user out everywhere. The onUserLogout event fires so plugins can clean up, for example removing the Remember Me cookie.
8.6 The Events You Can Hook
For custom login logic, subscribe to these events in a plugin instead of touching the component:
| Event | Plugin type | Fires when |
|---|---|---|
onUserAuthenticate |
authentication | Credentials are checked. |
onUserAuthorisation |
authentication | Joomla decides if login is allowed. |
onUserLogin |
user | Login succeeds; start the session. |
onUserLoginFailure |
user | Login fails (useful for lockout logic). |
onUserLogout |
user | The user logs out. |
8.7 The Tables Login Touches
| Table | Role in login |
|---|---|
#__users |
Holds the username, the bcrypt password hash, and the lastvisitDate updated on each login. |
#__session |
One row per active session. A successful login creates or upgrades a row here. |
#__user_keys |
Stores the secure tokens for the Remember Me cookie plugin. |
#__user_mfa |
Multi-factor methods checked when a secret key is required. |
The login component owns none of these tables. It only triggers the shared login flow that reads and writes them.
8.8 Logging In From Your Own Extension
The same $app->login() call the component uses is available to your own code. A custom portal, an SSO bridge, or an importer can log a user in programmatically:
$app = Factory::getApplication();
$credentials = [
'username' => 'john',
'password' => 'secret',
];
// Fires the same event chain as the login form.
$app->login($credentials, ['action' => 'core.login.site']);
This runs the full authenticate → authorise → onUserLogin chain, so every plugin and permission check still applies. Use it with care: never hard-code real credentials, and always think through the security impact before you sign a user in outside the normal form.
8.9 Session Storage and Performance
A successful login writes a session, and every later request reads it. Where that session lives is a configuration choice under Global Configuration → System → Session Handler:
| Handler | When to use it |
|---|---|
| Database | The default. Sessions live in #__session. Fine for most sites. |
| Filesystem | Sessions stored as files on disk. Simple, but slower on networked storage. |
| Redis / Memcached | In-memory stores. Fast, and they keep session writes off the database. |
On a high-traffic site, moving sessions to Redis or Memcached is one of the most effective ways to cut database load, because every visitor, logged in or not, touches the session on every request.
Back to top9. Login for the Web Services API
9.1 No Form, No Session
The Joomla Web Services API does not use com_login at all. There is no form and no session cookie. Instead, each request carries a token that identifies the user. The login component even refuses non-HTML requests outright, returning a 403.
9.2 Token Authentication
The User - Joomla API Token plugin (plg_user_token) gives each user a personal token. You enable the plugin, generate a token on the user's profile, then send it as a header on every API call:
curl -H "X-Joomla-Token: <your-token>" \
https://example.test/api/index.php/v1/users
The token does the same job a username and password do on the website: it proves who you are. The user's groups and permissions still apply, so a token is only as powerful as the user behind it.
9.3 Keep Tokens Safe
A token is a password in a different shape. Send it only over HTTPS, never put it in a public repository or a client-side script, and revoke it from the user's profile the moment it might be exposed.
Back to top10. SEO and Metadata
Login pages are not pages you want search engines to rank. The backend login at /administrator/ should never be crawled at all, and a frontend login page carries no useful content for search results.
Two practical points matter here. First, set the menu item for any frontend login page to noindex in its Metadata tab, so search engines skip it. Second, keep login behind HTTPS; modern browsers and search engines both penalise password forms served over plain HTTP. A login page does not help your SEO directly, but a secure, well-behaved one protects the trust signals that do.
Back to top11. Common Mistakes and Pitfalls
11.1 Disabling the User - Joomla Plugin
Symptom: nobody can log in, on the frontend or the backend, even with the correct password.
Fix: re-enable the User - Joomla plugin. It runs the onUserLogin event that starts the session. If you cannot reach the backend, enable it directly in the #__extensions table by setting enabled = 1 for that plugin.
11.2 Confusing the Two Logins
Symptom: a user can log in to the website but is refused at /administrator/.
Fix: that is expected. Backend access needs the Administrator Login permission, which the website login does not. Grant core.login.admin to the right group in Global Configuration.
11.3 Forgetting the Remember Me Plugin
Symptom: the Remember Me checkbox appears but never keeps anyone logged in.
Fix: enable the Authentication - Cookie plugin. Without it the checkbox does nothing.
11.4 Expecting com_login to Have Options
Symptom: you look for login settings inside com_login and find none.
Fix: there are no component options. Login behaviour lives in the login modules (redirects, Remember Me), the authentication plugins (methods), and Global Configuration (permissions and session length).
11.5 An Open Redirect Through the Return URL
Symptom: a third-party login link tries to send users to an external site after login.
Fix: Joomla already blocks this. The component validates the return URL with Uri::isInternal(). Do not remove that check if you build a custom login.
11.6 Session Timeouts That Feel Random
Symptom: administrators are logged out mid-task and bounced to the login screen.
Fix: raise the Session Lifetime in Global Configuration → System, and make sure the session handler (database or filesystem) is healthy. A short lifetime or a full session table forces early logouts.
12. Best Practices
If you remember only a few things from this article, remember these:
- The backend login is
com_login; the frontend login iscom_users. Know which one you are configuring. - Never disable the User - Joomla plugin. Without it, login stops working everywhere.
- Control who may log in through the Site Login and Administrator Login permissions, not by editing files.
- Enable multi-factor authentication for every backend user, and enforce it for admin groups.
- Serve every login page over HTTPS, and set frontend login pages to noindex.
- Add new login methods (SSO, social, LDAP) with an authentication plugin; never patch
com_login. - Protect API tokens like passwords, and revoke them the moment they might leak.
13. Quick Reference
BACKEND LOGIN com_login /administrator/
FRONTEND LOGIN com_users (Login) index.php?option=com_users&view=login
LOGIN MODULE mod_login (one per client: site and admin)
TASKS login, logout (the only two com_login accepts)
LOGIN CALL $app->login($credentials, ['action' => 'core.login.admin'])
LOGOUT CALL $app->logout($userid, ['clientid' => $clientid])
PERMISSIONS core.login.site Site Login (frontend)
core.login.admin Administrator Login (backend)
AUTH PLUGINS Joomla (password), Cookie (Remember Me), LDAP (external)
KEY EVENTS onUserAuthenticate → onUserAuthorisation
→ onUserLogin / onUserLoginFailure / onUserLogout
NEVER DISABLE User - Joomla plugin (runs onUserLogin)
TABLES #__users (hash, lastvisitDate)
#__session (active sessions)
#__user_keys (Remember Me tokens)
#__user_mfa (multi-factor methods)
API LOGIN X-Joomla-Token header (plg_user_token), no session, HTTPS only
Back to top14. Summary
Joomla login looks like a single form, but it is a small system of cooperating parts:
- com_login is the tiny admin-only component behind the backend login form; it stores no data and accepts only
loginandlogout. - com_users and
mod_loginprovide the frontend login, redirects, and the Remember Me option. - Authentication plugins decide how credentials are checked, so you can add SSO, LDAP, or social login without touching the core.
- Permissions (
core.login.siteandcore.login.admin) decide who may walk through each door. - Built-in defences (CSRF tokens, internal-only redirects, the clickjacking header, and the lockout failsafe) make login secure by default.
- The Web Services API replaces the form with a personal token.
Once you see login as a component plus modules plus a plugin chain, the whole system becomes predictable. You know where to set redirects, where to grant access, where to add a new login method, and where to look when something breaks.
If your site suffers from random logouts, locked-out administrators, or a login flow you are not sure is secure, those symptoms usually trace back to one of the layers above. Checking them in the right order is exactly the kind of methodical work a Joomla specialist does first, and it is often the difference between a site you can trust and one you cannot.
Back to top

Joomla specialist and Linux admin for fast, secure and scalable websites.


