Using zend-expressive-csrf with zend-form in Expressive 3

If you followed my post about authentication and authorization posts with Expressive 3, this time, I write another session related post for securing request, which uses zend-expressive-csrf with zend-form.

Setup

We already installed session and form components, so, we can just require the zend-expressive-csrf component via command:

$ composer require \
zendframework/zend-expressive-csrf:^1.0.0alpha1

On Login route, we register the csrf middleware before the LoginPageHandler:

In above __construct(), I call init() immediatelly on __construct() to add form elements on form creation, as we are going to inject the Form with Zend\Expressive\Csrf\SessionCsrfGuard instance on LoginPageHandler which pulled from request object.

We then can add new element, for example, named: csrf as hidden input, as follows:

Above, we supply a callback validator (you can create a special validator just for it) with call the Zend\Expressive\Csrf\SessionCsrfGuard::validateToken($value) which returns true when valid, and false when invalid. On invalid token, we will get callbackValue message key which we can customize its value.

The LoginPageHandler

As the Zend\Expressive\Csrf\SessionCsrfGuard instance will be injected at the LoginPageHandler itself, we can remove the LoginForm from LoginPageHandler dependency, so, we just need to have TemplateRendererInterface:

As the token csrf is a one time token, and we use a single page for both GET (show form) and POST (authenticate), we can create a function to get generated token to be called before POST method check, and when authentication failure or the form is invalid to ensure next retry will use newly generated token:

All done, now, when the request is not using the session generated token, it will show form error:

The form submitted did not originate from the expected site

like the following screenshot:

Better Practice and Possible Refactor

For real application, it is better to use PRG or use another handler to handle it to be redirected back to the form when failure, so you don’t need to tweak the token regeneration as when form re-displayed again, it already in next request and we can just use the new token. I’ve written new post for create middleware for Post/Redirect/Get in Expressive 3 for it.