Middleware for Access control

You can apply access control manually using the is() method. Alteratively, if you’re using a PSR-7 compatible router, you can use middleware. AuthMiddleware implements PSR-15 MiddlewareInterface.

Pass a PSR-17 ResponseFactory as last argument. It’s used to create a 401 Unauthorized or 403 Forbidden response.

Authorization

The constructor takes a callback as second argument, which should get the required authorization role / level from the request.

The callback may return null to indicate that anybody can visit the page. Returning true means a the request will only be handled if a user is logged in, and false means that the user may not be logged in.

use Jasny\Auth\AuthMiddleware;
use Psr\Http\Message\ServerRequestInterface ;

$middleware = new AuthMiddleware(
    $auth,
    function (ServerRequestInterface $request) {
        if (strpos($request->getUri()->getPath(), '/account/') === 0) {
            return true; // Pages under `/account/` are only available if logged in
        }
        
        if ($request->getUri()->getPath() === '/signup') {
            return false; // Don't signup if you're already logged in
        }
    
        return null;
    },
    $responseFactory,
);

$router->add($middleware);

If the callback returns a string, the middleware will check if the user is authorized for that role.

$middleware = new AuthMiddleware(
    $auth,
    function (ServerRequestInterface $request) {
        return $request->getAttribute('route.auth');
    },
    $responseFactory,
);

$router->add($middleware);

If an array of strings is returned, the user should be authorized for at least one of the roles. So returning ['admin', 'provider'] means the user needs to be an admin OR provider.

Initialization

The middleware will initialize the auth service. To use a different session service than PhpSessions, pass a callback to withSession(). The callback takes a PSR-7 ServerRequestInterface object and must return a session service.

$middleware = new AuthMiddleware(/* ... */)
    ->withSession(fn(ServerRequestInterface $request) => new BearerAuth($request));

$router->add($middleware);

A common case is to choose between bearer auth (for the API) and sessions based on the path.

$middleware = new AuthMiddleware(/* ... */)
    ->withSession(function (ServerRequestInterface $request) {
        $isApi = strpos($request->getUri()->getPath(), '/api/') === 0);

        return $isApi
            ? new BearerAuth($request)
            : new SessionObject($request->getAttribute('session', new ArrayObject())); 
    });

$router->add($middleware);

For multiple requests

Normally the Auth service should be initialized only once. Trying to initialize it a second time will throw an exception. For testing (and in some rare other cases), you want to the service to be able to handle multiple request, reading the session information each time. With forMultipleRequests() you get a copy of the service that allows re-initialization.

if (getenv('APPLICATION_ENV') === 'tests') {
    $auth = $auth->forMultipleRequests();
}

Double pass middleware

Some HTTP dispatchers accept double pass middlware rather than adhering to PSR-15. This is supported via the asDoublePass() method. In this case, the request factory may be omitted from the constructor.

$middleware = new AuthMiddleware(/* ... */)
    ->withSession(function (ServerRequestInterface $request) {
        return new BearerAuth();
    });

$router->add($middleware->asDoublePass());