For Laravel 5.2+ multi-auth in the FormRequest, you can avoid having to remember which guard to pass into its user() method. Declare a base class and override that method to discover the guard based on which route was requested.


An older still-active OAuth API in the /api/v1/* URI space and fresh JWT token-based endpoints in /api/v2/*? The above approach can be used so you now don’t have to remember three difference guard names and which ones to pass in. Just call $this->user()!

Assuming you use route-based authorization, I like to declare a base authorize() method in case a policy or resource access check isn’t required in all requests classes.

These are just common expressions (*ahem* idioms Wow, I never realized how much we rely on idioms.) that make writing code easier.

Some authorization guard background

Laravel 5.2 introduced multi-auth to our web apps, so now we can support typical cookie-based sessions for web browsers while also having mobile apps accessing API endpoints authorized with public/secret keys or temporary JWT tokens. Your codebase is likely now filled with Auth::user() and Auth::guard('api')->user().

When working on features, depending on where in the architecture you have to jump in, this new feature requires a contextual shift in thinking.

A typical POST form request being processed in a controller? I can use Auth::check() or a method-injected $request->user() or facade-accessed Request::user().

Now I have this API service, so maybe global helper function request()->user('api') will get me the account accessing this endpoint.

It’s the sort of cognitive overhead that will cause unexpected null exceptions. e.g., mistakenly getting the web session user when you need the API token-accessed user. In a team of 3+ devs, it slows their ability to just get stuff done. Retrieving the logged in user should be second nature.

In a large-scale project with complex business requirements, controllers quickly get out of hand. For this reason I enforce custom FormRequest classes to apply rules to request parameters. Sometimes these classes are shared by both session controllers and API controllers, with the former invoking the latter using Laravel sub-requests (a blog post for another day.)

Third-party package laravel-jsvalidation enforces input validation using jQuery in the browser so it doesn’t hit your server to assert everything is good. This has FormRequest support to get those validation rules. It’s kind of a neat unified solution if it weren’t for the limitations that require a three-part series describing why web development drives individuals to madness.

A Request macro for user() would be nice

Since this is a child of the base Illuminate\Http\Request, to check resource policies or pull user-dependent data into validation rules, you’ll use $this->user() or $this->user('api'). I don’t want to think which to call.

Laravel has a great macro feature in some of its god classes where you can patch them with your own methods. Unfortunately Illuminate\Http\Request concrete user() will be used over any Illuminate\Support\Facades\Request::macro('user') you define. At least in FormRequest, you can override that method in your own app’s class that all others will extend.

Take this example that works for the default guard in your app:

If that were used by an API endpoint, parameter 'api' would have to be passed into the user() method.

FormRequest auth guard by laravel-jsvalidation package

This package instantiates the FormRequest directly so you wouldn’t have a route to get the auth guard. I just assume it’s for the frontend so use the default 'web' guard through the Auth facade.

Caveats

  • New team members must be on-boarded to this idiom and reminded how the project differs from Laravel’s documentation.
  • This assumes internal structures in the Laravel framework that even minor releases may break in ways integration tests may not detect.
  • I still haven’t resolved the universal Auth::user() / Auth::check() / request()->user() multi-auth problem without declaring separate macros that avoid Laravel’s class methods altogether. Based on route you should know what guard’s in use!