From Scratch: User Authentication
Tags: fromscratch, cleancode, authentication
Published: 2018-10-13 12:38:04

---
published: true
title: From Scratch: User Authentication
tags: from-scratch, clean-code, authentication
description: How to build a clean, framework-agnostic, authentication system
cover_image: https://i1.wp.com/blog.mallow-tech.com/wp-content/uploads/2016/12/user-authentication.jpg?resize=820%2C400
---

## Definitions

User Authentication is loosely defined as identifying the user based on his credentials. In other words, it provides access control for systems, by checking to see if the user's credentials match those saved in a database, in a data authentication server, or anywhere else.

The credentials, in the other hand, could be anything: an identifier, password, pin numbers, certificate, fingerprint, retina, voice. I mean anything that differentiate a user from another.

You can get more information about the authentication, its types and factors on this wonderful [article](https://searchsecurity.techtarget.com/definition/authentication).

## Solutions

Developers and frameworks provide different solutions and visions, simple and complex, to manage user identification.

Let see some examples:

### Zend Framework 2

Zend framework provides a dedicated module [zend-authentication](https://docs.zendframework.com/zend-authentication/), which includes `adapters` for different authentication methods, and an `AuthenticationService` class.

```php
use Zend\Authentication\AuthenticationService;

// Instantiate the authentication service
$auth = new AuthenticationService();

// Instantiate a dummy authentication adapter
$authAdapter = new Adapter($email, $password);

// Attempt authentication, saving the result
$result = $auth->authenticate($authAdapter);
```

After a successful authentication attempt, subsequent requests can query the authentication service to determine if an identity is present, and, if so, retrieve it:

```php
if ($auth->hasIdentity()) {
  // Identity exists; get it
  $identity = $auth->getIdentity();
}
```

### Laravel 5

Laravel is a huge framework in fact, offering also different solutions and tools to handle authentication.

Laravel's authentication services could be accessed via the `Auth` [facade](https://laravel.com/docs/5.6/facades).

```php
use Illuminate\Support\Facades\Auth;

if (Auth::attempt($credentials)) {
  // Authentication passed
}
else {
  // Authentication failed
}
```

The `attempt` method accepts an array of key/value pairs as its first argument, and will return a `boolean` if the user is found in the database using the values in the array.

The authenticated user can be retrieved again via the `Auth` facade.

```php
use Illuminate\Support\Facades\Auth;

// Get the currently authenticated user...
$user = Auth::user();

// Get the currently authenticated user's ID...
$id = Auth::id();
```

### Symfony 4

The Symfony's solution is quite complicated. The `security` module provides multiple classes and interfaces to handle authentication.

```php
use Symfony\Component\Security\Core\Authentication\AuthenticationProviderManager;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Component\Security\Core\Exception\AuthenticationException;

// instances of Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface
$providers = array(...)

// Instantiate the authentication manager
$authenticationManager = new AuthenticationProviderManager($providers);

// create a token, containing the user's credentials
$unauthenticatedToken = new UsernamePasswordToken($username, $password, $providerKey);

// validate the given token, and return an authenticated token
try {
  $authenticatedToken = $authenticationManager->authenticate($unauthenticatedToken);
} catch (AuthenticationException $exception) {
  // authentication failed
}
```

After authentication, the User object of the current user can be accessed via the `getUser()` from inside a controller, this will look like:

```php
public function index()
{
  $user = $this->getUser();
}
```

or via the `Security` class, available from version 3.4:

```php
use Symfony\Component\Security\Core\Security;

public function indexAction(Security $security)
{
  $user = $security->getUser();
}
```

### Django 2

Django uses, by default, sessions and middlewares to hook the authentication system into request objects.

```python
from django.contrib.auth import authenticate

def my_view(request):
  user = authenticate(username='john', password='secret')

  if user is not None:
    # A backend authenticated the credentials
  else:
    # No backend authenticated the credentials
```

The user, authenticated or not, is always accessible within the `request` object:

```python
if request.user.is_authenticated:
  # Do something for authenticated users.
  ...
else:
  # Do something for anonymous users.
  ...
```

### Passport.js

Authenticating requests is as simple as calling `passport.authenticate()` and specifying which strategy to employ. `authenticate()`'s function signature is a standard [Connect](http://www.senchalabs.org/connect/) middleware, which makes it convenient to use as route middleware in [Express](http://expressjs.com/) applications.

```js
app.post('/login', passport.authenticate('strategy-name'), function (req, res) {
  // If this function gets called, authentication was successful.
  // `req.user` contains the authenticated user.
  res.redirect('/users/' + req.user.username);
});
```

Unfortunately, `passport` can only be used in an express-like applications, since `authenticate()` returns a middleware function. It doesn't provide any API to use independently.

## Conclusion

In my opinion, the Django [solution](https://docs.djangoproject.com/en/2.1/topics/auth/default/#authenticating-users) is the best one, because, unlike the others, it separates the `authentication` from `login`.
- the [authenticate](https://docs.djangoproject.com/en/2.1/topics/auth/default/#django.contrib.auth.authenticate) function checks the user credentials against each authentication backend, and returns a `User` object if the credentials are valid for a backend.
- but the [login](https://docs.djangoproject.com/en/2.1/topics/auth/default/#django.contrib.auth.login) function saves the user’s ID in the session, making it persistent for several requests.

Signing in users is application specific. But user identification is shared between apps and systems, only the `backend` differs.

From the above, and other examples not cited here, I ended up with a simple, stupid authentication manager, that dispatches the user credentials to a list of handlers.

```ts
interface AuthManager {
  /**
   * Check the credentials and return the user
   */
  attempt (credentials: object): Promise<User | undefined>

  /**
   * Register an authenticator
   */
  use (name: string, handler: Authenticator): this
}
```

The manager is an implementation of `chain of responsibility` design pattern, and internally uses authenticators with the following contract:

```ts
interface Authenticator {
  /**
   * Try to handle the credentials, or delegate to the next handler.
   */
  process (credentials: object, next: () => any): Promise<User | undefined>
}
```

I'm still working on this implementation to make it clean and framework-agnostic.
You may take a look at the [develop](https://github.com/aldojs/authentication/tree/develop) branch.

What do you think guys ?