Update: I created a diagram to show the usage of RFC authentication and RFC authorization.
RFC: authentication module for Expressive and PSR-7 apps
Following the RFC for Authorization Middleware, I now propose an authentication module for middleware applications.
An authentication middleware checks user credentials provided in the HTTP request and blocks the pipeline execution on authentication failure.
The goal of this RFC is to build a general authentication module for Expressive and PSR-7 applications. The idea is to authenticate user credentials based on username and password or using a token (e.g. using OAuth2).
The authentication middleware should be able to check against different authentication mechanisms using specific adapters (e.g. HTTP Basic/Digest Authentication, PHP Session, OAuth2, etc.).
The users should be managed using adapters, to be able to retrieve credential via different data storage mechanisms (e.g. htpasswd file, PDO-backed database, etc.).
I proposed an implementation of the authentication middleware using the following adapter interface:
* Authenticate the PSR-7 request and return a valid user
* or null if not authenticated.
public function authenticate(ServerRequestInterface $request) : ?UserInterface;
* Generate the unauthorized response
public function unauthorizedResponse(ServerRequestInterface $request) : ResponseInterface;
This interface defines 2 methods
unauthorizedResponse(). The first is used to authenticate a PSR-7 request, returning a
UserInterface object or null if not authenticated. The second function is used to generate the unauthorized response.
For instance, using Basic Access Authentication, the authentication is provided using an
Authorization header as follows:
Authorization: Basic QWxhZGRpbjpPcGVuU2VzYW1l
In situations where the HTTP request does not contain this header, authentication must respond with a
401 Unauthorized status with the following header:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Basic realm="User Visible Realm"
Where the realm is a string that defines the protection space, in case of multiple authentication systems on the same server resource.
In the case of a valid credential, the
authenticate() method returns a
UserInterface instance. This is a simple interface described as follows:
* Get the username
public function getUsername() : string;
* Get the user role
public function getUserRole() : string;
This interface defines 2 methods, one each for retrieving the username and the user role. This information can be consumed by Authorization middleware to check for authorized users to perform specific actions (e.g. see the zend-expressive-authorization proposal).
In order to use different user repositories for credentials (e.g., to perform lookups using different storage backends), I propose the following interface:
* Authenticate the credential (username) using a password
* or using only the credential string (e.g. token based credential)
* It returns the authenticated user or null.
* @param string $credential Can be also a token
* @param string $password
* @return UserInterface|null
public function authenticate(string $credential, string $password = null) : ?UserInterface;
This interface contains only one function, authenticate. This function can be used to check if the username (
password are valid or not. The
password argument is optional, in case we need to authenticate against a single token string, specified by the
If the user is authenticated it will return a
UserInterface object or
null if not authenticated.
Using these level of abstractions we should be able to manage all authentication mechanisms using different user repositories.
To configure the proposed authentication middleware we can use alias services. We can use
Zend\Expressive\Authentication\AuthenticationInterface::class name for the authentication adapter and
Zend\Expressive\Authentication\UserRepositoryInterface::class for the user register adapter.
The default configuration provided by a
ConfigProvider class for the proposed module might look like the following:
* Return the configuration array.
public function __invoke() : array
'dependencies' => $this->getDependencies(),
'authentication' => include __DIR__ . '/../config/authentication.php',
* Returns the container dependencies
public function getDependencies() : array
'aliases' => [
// Change the alias value for Authentication adapter and
// UserRepository adapter
AuthenticationInterface::class => Adapter\BasicAccess::class,
UserRepositoryInterface::class => UserRepository\Htpasswd::class,
'factories' => [
AuthenticationMiddleware::class => AuthenticationMiddlewareFactory::class,
Adapter\BasicAccess::class => Adapter\BasicAccessFactory::class,
UserRepository\Htpasswd::class => UserRepository\HtpasswdFactory::class,
UserRepository\PdoDatabase::class => UserRepository\PdoDatabaseFactory::class
The config/authentication.php file contains specific configuration used by the adapters.
I have prototyped an implementation of the authentication middleware in ezimuel/zend-expressive-authentication. Currently, I only implement HTTP Basic Authentication using 2 user repositories: htpasswd file or PDO database.