User authentication


1Introduction

This documentation explains step by step how to set up a passwordless authentication system in a Temma application.

The principle is simple: the user enters their email address, receives a magic link by email, and by clicking on it, they are authenticated. The link can only be used once and expires after one hour.

This system relies on two components provided by Temma:

  • The controller/plugin \Temma\Controllers\Auth: manages the login form, email sending and the user session.
  • The attribute \Temma\Attributes\Auth: restricts access to controllers and actions based on authentication, roles and services.

2Prerequisites

To follow this tutorial, you need:

  • A working Temma project (see the Installation page).
  • A MySQL or MariaDB database configured in your data sources.
  • A server capable of sending emails (for magic links).

3Database creation

The authentication system requires two tables: User (users) and AuthToken (connection tokens sent by email).

Run the following SQL queries to create these tables:

CREATE TABLE User (
    id               INT UNSIGNED NOT NULL AUTO_INCREMENT,
    date_creation    DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    date_last_login  DATETIME,
    date_last_access DATETIME,
    email            TINYTEXT CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL,
    name             TINYTEXT,
    roles            SET('admin', 'writer', 'reviewer'), -- must be customized
    services         SET('articles', 'news', 'images'), -- must be customized
    PRIMARY KEY (id),
    UNIQUE INDEX email (email(255))
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;

CREATE TABLE AuthToken (
    token         CHAR(64) CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL,
    expiration    DATETIME NOT NULL,
    user_id       INT UNSIGNED NOT NULL,
    PRIMARY KEY (token),
    INDEX expiration (expiration),
    FOREIGN KEY (user_id) REFERENCES User (id) ON DELETE CASCADE
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;

The roles and services fields in the User table are of type SET: you need to customize them according to your application's needs. Roles represent user functions (administrator, writer, etc.), and services represent the modules they have access to (articles, images, etc.).


4Configuration

You need to configure \Temma\Controllers\Auth both as a pre-plugin (to manage the user session on each request) and as a route (to make the login form accessible).

Add the following to your etc/temma.php file:

<?php

return [
    'application' => [
        'dataSources' => [
            'db' => 'mysql://user:password@localhost/myDatabase'
        ]
    ],
    'plugins' => [
        '_pre' => [
            '\Temma\Controllers\Auth'
        ]
    ],
    'routes' => [
        'auth' => '\Temma\Controllers\Auth'
    ]
];
  • Lines 5 to 7: Database connection configuration (adapt to your environment).
  • Lines 10 to 12: Pre-plugin declaration. On each request, it checks whether the user is authenticated and makes their information available.
  • Lines 14 to 16: Route declaration. The controller will be accessible via the URLs /auth/login and /auth/logout.

5Customizing the login template

The Auth controller uses a Smarty template located in templates/auth/login.tpl. The version provided by Temma is minimal; you are encouraged to create your own version.

Here is an example of a login form template:

<html>
<head>
    <title>Login</title>
</head>
<body>
    <h1>Login</h1>
    {if $authError}
        <p style="color: red;">Unknown email address.</p>
    {/if}
    {if $authSent}
        <p style="color: green;">
            A login link has been sent to your email address.
            Check your inbox.
        </p>
    {else}
        <form method="post" action="/auth/login">
            <label for="email">Email address:</label>
            <input type="email" id="email" name="email" required />
            <button type="submit">Log in</button>
        </form>
    {/if}
</body>
</html>
  • Line 7: If the email address is not found in the database, an error message is displayed.
  • Line 10: If the email was successfully sent, a confirmation message is displayed instead of the form.
  • Lines 16 to 19: The form sends the email address via POST to /auth/login.

6Testing the login

Before testing, make sure you have at least one user in the database. You can insert one manually:

INSERT INTO User (email, name) VALUES ('john@example.com', 'John');

The login process works as follows:

  1. Navigate to /auth/login in your browser.
  2. Enter the user's email address and submit the form.
  3. An email containing a login link is sent to this address.
  4. By clicking on the link, the user is authenticated and redirected to the homepage.

The login link is single-use and expires after one hour.


7Protecting pages with the Auth attribute

The Auth attribute restricts access to controllers or actions based on authentication. It relies on the $currentUser template variable set by the pre-plugin.

To protect an entire controller (all its actions require authentication):

use \Temma\Attributes\Auth as TµAuth;

#[TµAuth]
class Account extends \Temma\Web\Controller {
    public function profile() {
        // accessible only to authenticated users
    }
    public function settings() {
        // same
    }
}

To protect only specific actions:

use \Temma\Attributes\Auth as TµAuth;

class Blog extends \Temma\Web\Controller {
    // accessible to everyone
    public function list() { }

    // restricted to users with the "writer" role
    #[TµAuth('writer')]
    public function create() { }

    // restricted to users with access to the "images" service
    #[TµAuth(service: 'images')]
    public function uploadImage() { }

    // restricted to users with the "admin" or "writer" role
    #[TµAuth(['admin', 'writer'])]
    public function edit() { }
}

If an unauthorized user tries to access a protected page, they receive an HTTP 401 error by default. To redirect them to the login form, add this configuration to etc/temma.php:

<?php

return [
    'x-security' => [
        'authRedirect' => '/auth/login'
    ]
];

To store the requested URL so that the user is redirected to it after login, use the storeUrl parameter:

use \Temma\Attributes\Auth as TµAuth;

#[TµAuth(redirect: '/auth/login', storeUrl: true)]
class Account extends \Temma\Web\Controller {
    // ...
}

This way, after logging in, the user will be redirected to the page they were trying to reach.


8Using user information

The Auth pre-plugin provides two template variables, accessible in templates, controllers and plugins:

  • currentUserId: Identifier of the authenticated user (or null if not authenticated).
  • currentUser: User data (associative array containing the keys id, email, name, roles, services, etc.).

Here is an example of usage in a Smarty template:

{if $currentUserId}
    <p>Hello, {$currentUser.name}!</p>
    {if $currentUser.roles.admin}
        <a href="/admin">Administration</a>
    {/if}
    <a href="/auth/logout">Logout</a>
{else}
    <a href="/auth/login">Login</a>
{/if}

In a controller, these variables are accessible via $this['currentUserId'] and $this['currentUser']:

class Account extends \Temma\Web\Controller {
    public function profile() {
        $userId = $this['currentUserId'];
        $user = $this['currentUser'];
        $this['userName'] = $user['name'];
        $this['isAdmin'] = $user['roles']['admin'] ?? false;
    }
}

9Logout

To log a user out, redirect them to the /auth/logout URL. They will be automatically redirected to the homepage after logout.

Example logout link in a template:

<a href="/auth/logout">Logout</a>

If you want to redirect the user to a specific URL after login (and therefore also after logout and re-login), configure the redirection parameter (see the Advanced configuration section).


10Advanced configuration

All configuration options are placed under the x-security > auth key in the etc/temma.php file.

Email customization

You can customize the sender address, subject and content of the login email:

<?php

return [
    'x-security' => [
        'auth' => [
            'emailSender'  => 'no-reply@mysite.com',
            'emailSubject' => 'Your login link',
            'emailText'    => "Hi,\n\nHere is your login link:\n%s\n\nIt is valid for 1 hour.\n\nBest regards"
        ]
    ]
];

The %s marker in the text is replaced by the login URL.

Automatic registration

By default, only users already present in the database can log in. To automatically register new users:

<?php

return [
    'x-security' => [
        'auth' => [
            'registration' => true
        ]
    ]
];

Redirection after login

By default, the user is redirected to the homepage after login. You can change this URL:

<?php

return [
    'x-security' => [
        'auth' => [
            'redirection' => '/my-account'
        ]
    ]
];

Note that if the Auth attribute has stored the requested URL (storeUrl parameter), it will be used instead.

Customizing table and field names

If your tables or fields have names different from the defaults, you can redefine them:

<?php

return [
    'x-security' => [
        'auth' => [
            'userData' => [
                'base'     => 'auth_db',
                'table'    => 'tUser',
                'id'       => 'user_id',
                'email'    => 'user_mail',
                'roles'    => 'user_roles',
                'services' => 'user_services',
            ],
            'tokenData' => [
                'base'       => 'auth_db',
                'table'      => 'tToken',
                'token'      => 'token_hash',
                'expiration' => 'expiration_date',
                'user_id'    => 'fk_user_id',
            ]
        ]
    ]
];

For more details on all configuration options, refer to the full documentation of the Auth controller/plugin and the Auth attribute.