User Authorization and Privileges

Little to none web applications need no mechanism for user login or checking user privileges. In this chapter, we'll talk about:

  • user login and logout
  • verifying user privileges
  • securing against vulnerabilities
  • how to create custom authenticators and authorizators
  • Access Control List

Before we fully emerge this topic, we should note that all examples use user service, which is a Nette\Security\User object. You can access the service directly in the presenter by calling $user = $this->getUser() or you can require it using Dependency Injection.


Authentication means user login, ie. the process during which user's identity is verified. User usually identifies himself using username and password.

Logging user in with username and password:

$user->login($username, $password);

Checking if user is logged in:

echo $user->isLoggedIn() ? 'yes' : 'no';

And logging him out:


Simple, right?

Logging in requires users to have cookies enabled – other methods are not safe!

Besides logging the user out with the logout() method, it can be done automatically based on specified time interval or closing the browser window. For this configuration we have to call setExpiration() during the login process. As an argument, it takes a relative time in seconds, UNIX timestamp, or textual representation of time. The second argument specifies whether the user should be logged out when the browser is closed.

// login expires after 30 minutes of inactivity or after closing browser
$user->setExpiration('30 minutes', TRUE);

// login expires after two days of inactivity
$user->setExpiration('2 days', FALSE);

// login expires when a browser is closed, but not sooner (ie. without a time limit)
$user->setExpiration(0, TRUE);

Expiration must be set to value equal or lower than the expiration of sessions.

The reason of last logout can be obtained by method $user->getLogoutReason(), which returns one of these constants: IUserStorage::INACTIVITY if time expired, IUserStorage::BROWSER_CLOSED when user has closed the browser or IUserStorage::MANUAL when the logout() method was called.

To make the example above work, we in fact have to create an object that verifies user's name and password. It's called authenticator. Its trivial implementation is the class Nette\Security\SimpleAuthenticator, which in its constructor accepts an associative array:

$authenticator = new Nette\Security\SimpleAuthenticator([
    'john' => 'IJ^%4dfh54*',
    'kathy' => '12345', // Kathy, this is a very weak password!

If the login credentials are not valid, authenticator throws an Nette\Security\AuthenticationException:

try {
    // we try to log the user in
    $user->login($username, $password);
    // ... and redirect upon success

} catch (Nette\Security\AuthenticationException $e) {
    echo 'Login error: ', $e->getMessage();

We usually configure authenticator inside a config file, which only creates the object if it's requested by the application. The example above would be set in config.neon as follows:

    authenticator: Nette\Security\SimpleAuthenticator([
            john: IJ^%4dfh54*
            kathy: 12345

Custom authenticator

We will create a custom authenticator that will check validity of login credentials against a database table. Every authenticator must be an implementation of Nette\Security\IAuthenticator, with its only method authenticate(). Its only purpose is to return an identity or to throw an Nette\Security\AuthenticationException. Framework defines few error codes, that can be used to determine the reason login was not successful, such as self-explaining IAuthenticator::IDENTITY_NOT_FOUND or IAuthenticator::INVALID_CREDENTIAL.

use Nette\Security as NS;

class MyAuthenticator implements NS\IAuthenticator
    public $database;

    function __construct(Nette\Database\Connection $database)
        $this->database = $database;

    function authenticate(array $credentials)
        list($username, $password) = $credentials;
        $row = $this->database->table('users')
            ->where('username', $username)->fetch();

        if (!$row) {
            throw new NS\AuthenticationException('User not found.');

        if (!NS\Passwords::verify($password, $row->password)) {
            throw new NS\AuthenticationException('Invalid password.');

        return new NS\Identity($row->id, $row->role, ['username' => $row->username]);

Class MyAuthenticator communicates with the database using Nette\Database layer and works with table users, where it grabs username and bcrypt hash of password in the appropriate columns. If the password check is successful, it returns new identity with user ID, role, which we will mention later and an array with additional data (e.g. username).

This authenticator would be configured in the config.neon file like this:

    authenticator: MyAuthenticator


Identity presents a set of user information, as returned by autheticator. It's an object implementing Nette\Security\IIdentity interface, with default implementation Nette\Security\Identity. Class has methods getId(), that returns users ID (for example primary key for the respective database row), and getRoles(), which returns an array of all roles user is in. User data can be access as if they were identity properties.

Identity is not erased when the user is logged out. So, if identity exists, it by itself does not grant that the user is also logged in. If we would like to explicitly delete the identity for some reason, we logout the user by calling $user->logout(TRUE).

Service user of class Nette\Security\User keeps the identity in session and uses it to all authorizations. Identity can be access with getIdentity upon $user:

if ($user->isLoggedIn()) {
    echo 'User logged in: ' . $user->getIdentity()->getId();
    // or a shortcut
    echo 'User logged in: ' . $user->id;

    // username passed to the identity data
    echo ' ' . $user->getIdentity()->username;
} else {
    echo 'User is not logged in';

As mentioned before, identity is stored in the session. If we e.g. change the role of some of the logged in users, old data will be kept in the identity until he logs in again.


Authorization detects whether the user has enough privilege to do some action, for example opening a file or deleting an article. Authorization assumes that the user has been successfully authenticated (logged in).

Nette Framework authorization may be based on what groups the user belongs to or on which roles were assigned to the user. We will start from the very beginning.

For simple web sites with administration, where all users share same privileges, it is sufficient to use already mentioned isLoggedIn() method. Simply put, if the user is logged in, he has permissions to all actions, and vice versa.

if ($user->isLoggedIn()) { // is user logged in?
    deleteItem(); // if so, he may delete an item


The purpose of roles is to offer a more precise privilege control while remaining independent on the user name. As soon as user logs in, he is assigned one or more roles. Roles themselves may be simple strings, such as admin, member, guest, etc. They are specified in the second argument of Identity constructor, either as a string or an array.

This time we will use the isInRole() method to check if the user is allowed to perform some action:

if ($user->isInRole('admin')) { // is the admin role assigned to the user?
    deleteItem(); // if so, he may delete an item

As you already know, logging user out does not erase his identity. Therefore the getIdentity() method still returns an Identity object, with all the assigned roles regardless on logout. Nette Framework adheres to the “less code, more security” principle, which is why it doesn't want to force coders to write if ($user->isLoggedIn() && $user->isInRole('admin')) everywhere and therefore the isInRole() method works with efective roles. If the user is logged in, roles assigned to identity are used, if he is logged out, an automatic special role guest is used instead.


Authorizator decides, whether the user has permission to take some action. It's an implementation of Nette\Security\IAuthorizator interface with only one method isAllowed(). Purpose of this method is to determine, whether given role has the permission to perform certain operation with specific resource.

  • role is a user attribute – for example moderator, editor, visitor, registered user, administrator, …
  • resource is a logical unit of the application – article, page, user, menu item, poll, presenter, …
  • privilege is a specific activity, which user may or may not do with resource – view, edit, delete, vote, …

An implementation skeleton looks like this:

class MyAuthorizator implements Nette\Security\IAuthorizator

    function isAllowed($role, $resource, $privilege)
        return ...; // returns either TRUE or FALSE


And an example of use:

// registers the authorizator
$user->setAuthorizator(new MyAuthorizator);

if ($user->isAllowed('file')) { // is user allowed to do everything with resource 'file'?

if ($user->isAllowed('file', 'delete')) { // is user allowed to delete a resource 'file'?

Do not confuse two different methods isAllowed: one belongs to the authorizator and the other one to the User class, where first argument is not $role.

Because user may have many roles, he is granted the permission only if at least one of roles has the permission. Both arguments are optional and their default value is everything.

Permission ACL

Nette Framework has a complete authorizator, class Nette\Security\Permission which offers a light weight and flexible ACL layer for permission and access control. When we work with this class, we define roles, resources and individual privileges. Roles and resources may form hierarchies, as shown in the following example:

  • guest: visitor that is not logged in, allowed to read and browse public part of the web, ie. articles, comments, and to vote in a poll
  • registered: logged in user, which may on top of that post comments
  • administrator: may write and administer articles, comments and polls

So we have defined certain roles (guest, registered and administrator) and metioned resources (article, comments, poll), which the users may access or take actions on (view, vote, add, edit).

We create an instance of Presmission and define the user roles. As roles may inherit each other, we may for example specify that administrator may do the same as an ordinary visitor (and of course more).

$acl = new Nette\Security\Permission;

// roles definition
$acl->addRole('registered', 'guest'); // registered inherits from guest
$acl->addRole('administrator', 'registered'); // and administrator inherits from registered

Trivial, isn't it? This ensures all the properties of the parents will be inheritted by their children.

Do note the method getRoleParents(), which returns an array of all direct parent roles, and the method roleIntheritsFrom(), which checks whether a role extends another. Their usage:

$acl->roleInheritsFrom('administrator', 'guest'); // TRUE
$acl->getRoleParents('administrator'); // ['registered'] - only direct parents

Now is the right time to define the set of resources that the users may acccess:


Also resources may use inheritance. The API offers similar methods, only the names are slightly different: resourceInheritsFrom(), removeResource().

And now the most important part. Roles and resources alone would do us no good, we have to create rules defining who can do what with whatever:

// everything is denied now

// guest may view articles, comments and polls
$acl->allow('guest', ['article', 'comment', 'poll'], 'view');
$acl->allow('guest', 'poll', 'vote');

// registered user has also right to add comments
$acl->allow('registered', 'comment', 'add');

// administrator may also edit and add everything
$acl->allow('administrator', Permission::ALL, ['view', 'edit', 'add']);

// administrator cannot edit polls, that would be undemocractic.
$acl->deny('administrator', 'poll', 'edit');

What if we want to prevent someone ** particular resource access **?

// administrators will not see ads
$acl->deny('administrator', 'ad', 'view');

Now when we have created the set of rules, we may simply ask the authorization queries:

// can guest view articles?
echo $acl->isAllowed('guest', 'article', 'view'); // TRUE
// can guest edit an article?
echo $acl->isAllowed('guest', 'article', 'edit'); // FALSE
// may guest add comments?
echo $acl->isAllowed('guest', 'comments', 'add'); // FALSE

The same is true for the registered user, though he is allowed to add a comment:

echo $acl->isAllowed('registered', 'article', 'view'); // TRUE
echo $acl->isAllowed('registered', 'comments', 'add'); // TRUE
echo $acl->isAllowed('registered', 'backend', 'view'); // FALSE

Administrator is allowed to do everything, except edit polls:

echo $acl->isAllowed('administrator', 'article', 'view'); // TRUE
echo $acl->isAllowed('administrator', 'commend', 'add'); // TRUE
echo $acl->isAllowed('administrator', 'poll', 'edit'); // FALSE

Admin rules may possibly be defined without any restrictions (without inheriting from any other roles):

$acl->allow('supervisor');  // all privileges for all resources for supervisor

Whenever during the application runtime we may remove roles with removeRolle(), resources with removeResource() or rules with removeAllow() or removeDeny().

Roles may inherit form one or more other roles. But what happens, if one ancestor has certain action allowed and the other one has it denied? Then the role weight comes into play – the last role in the array of roles to inherit has the greatest weight, first one the lowest:

$acl = new Permission();


$acl->allow('admin', 'backend');
$acl->deny('guest', 'backend');

// example A: role admin has lower weight than role guest
$acl->addRole('john', ['admin', 'guest']);
$acl->isAllowed('john', 'backend'); // FALSE

// example B: role admin has greater weight than role guest
$acl->addRole('mary', ['guest', 'admin']);
$acl->isAllowed('mary', 'backend'); // TRUE

Usage in application

We can configure Permission in the config.neon like this:

        class: Nette\Security\Permission
            - addRole(admin)
            - addRole(guest)

            - addResource(backend)

            - allow(admin, backend)
            - deny(guest, backend)

            # example A: role admin has lower weight than role guest
            - addRole(john, [admin, guest])

            # example B: role admin has greater weight than role guest
            - addRole(mary, [guest, admin])

and then we can verify privileges in Presenter e.g. in the startup method:

protected function startup()
    if (!$this->getUser()->isAllowed('backend')) {
        throw new Nette\Application\ForbiddenRequestException;

Following solution is alternative to the previous one. We create factory service, where we can setup Permission:


namespace App\Model;

use Nette;

class AuthorizatorFactory
    /** @return Nette\Security\Permission */
    public static function create()
        $acl = new Nette\Security\Permission;
        //if we want, we can load roles from database


        $acl->allow('admin', 'backend');
        $acl->deny('guest', 'backend');

// example A: role admin has lower weight than role guest
        $acl->addRole('john', array('admin', 'guest'));
        $acl->isAllowed('john', 'backend'); // FALSE

// example B: role admin has greater weight than role guest
        $acl->addRole('mary', array('guest', 'admin'));
        $acl->isAllowed('mary', 'backend'); // TRUE

        return $acl;

Then we have to register factory to the config.neon and use it as factory for Permission:

acl: App\Model\AuthorizatorFactory::create #here we specify, that AuthorizationFactory will be factory for Permission

Multiple authentications in the application

An application (server, session) could also be split into multiple separate segments, each with independent authentication logic. If we would for example like to have frontend and backend, each with separated authentication, we will just set a unique namespace for each of them:


It's necessary to keep in mind that this must be set at all places belonging to the same segment. When using presenters, we will set the namespace in the common ancestor – usually the BasePresenter. In order to do so we will extend the checkRequirements() method:

public function checkRequirements($element)

Events: onLoggedIn, onLoggedOut

user service offers events: onLoggedIn and onLoggedOut, useful for logging authorization activities on the website. onLoggedIn event is called only when the user has logged in successfully and the other one onLoggedOut when the user has logged out.