Skip to content
Advertisement

How do we implement custom API-only authentication in Laravel

This isn’t a question so much in need of an answer, but further suggestions and answers and recommendations are welcome. I want to share with the world how I resolved this issue and hope it helps others.

Laravel comes with several pre-designed authentication solutions that you can spin up with a few artisan commands. These include:

  • standard users table authentication
  • OAuth2 (via the Laravel Passport package)
  • Social media based authentication (via the Laravel Socialite package)

As useful as all of these are, in this age of micro-services, Laravel doesn’t provide much in the way of an out-of-the-box bootstrap for API-only authentication using custom APIs.

I was faced with this problem several months ago and I searched Google and Stackoverflow for an answer. I found helpful articles which helped to point the way, and these are cited. It took some effort to understand how to glue them together and step-debugging to iron out the kinks.

The answer is provided in the hope that it helps others – and myself, where I have to do the same thing again in the future.

Assumptions and Scope:

  • you’ve created your own API like https://example.com/login and https://example.com/logout
  • you’re running a website that requires authentication, but not via models and tables or social media
  • your API manages interactions with tables, including user-login/logout
  • you use the Laravel Passport add-on for OAuth2 authentication (acknowledgements to @ShuvoJoseph for bringing this to my attention)

Advertisement

Answer

The solution involves seven PHP files

  • app/Http/Controllers/HomeController.php – homepage controller; the destination for an authenticated user
  • app/Providers/ApiUserProvider.php – a custom provider to bootstrap and register the logged-in user, and implements the interface IlluminateContractsAuthUserProvider
  • app/CoreExtensions/SessionGuardExtended.php – custom guard-controller to log-in the user and receives the authentication values and stores them in session array; extends class IlluminateAuthSessionGuard
  • app/ApiUser – if you’re using OAuth2 (Laravel’s Passport); custom user class that exposes the OAuth access_token; extends IlluminateAuthGenericUser and implements the interface IlluminateContractsAuthAuthenticatable
  • config/auth.php – the auth config which instructs the Auth() facade to return the custom session guard
  • app/Providers/AuthServiceProvider.php – the auth bootstrap
  • app/Providers/AppServiceProvider.php – the main application bootstrap

Source research/investigation material are cited for you to investigate for yourself and comprehend the background context to their existence. I make no claims to be a genius who created the solution from scratch through my own mojo, but rather that – like all innovators – I build on the efforts of others. The unique selling point of my article is that I provide a complete packaged solution, whereas the cited sources provide solutions to niche parts of the overall answer. Together, after much trial and error, they helped me to form a complete solution.

A really useful article to understands how config/auth.php affects execution in AuthManager.php is https://www.2hatslogic.com/blog/laravel-custom-authentication/

No code modifications are made to the following, but they’re included to acknowledge the role they play and their importance in the process:

  • vendor/laravel/framework/src/Illuminate/Auth/AuthManager.php – main authorization factory manager
  • Auth() facade – returns the shrink-wrapped IlluminateAuthSessionGuard class instance by default, unless it’s instructed to do otherwise through the config/auth.php file – Auth() is used ubiquitously throughout Laravel code to retrieve the session guard

The Code

app/Http/Controllers/HomeController.php

JavaScript

app/Providers/ApiUserProvider.php

Sources:

JavaScript

app/CoreExtensions/SessionGuardExtended.php

Sources:

JavaScript

app/ApiUser

Sources:

JavaScript

app/Providers/AuthServiceProvider.php

JavaScript

app/Providers/AppServiceProvider.php

Sources:

Note:

There is a couple of nuanced issues regarding the change to coding in this PHP file. If you want to understand more, look at vendor/laravel/framework/src/Illuminate/Auth/AuthManager.php, AuthManager::resolve() in particular.

  1. References to config/auth.php ‘session’ and ‘token’ are served by hard-coded methods AuthManager::createSessionDriver() and AuthManager::createTokenDriver() (Tell me please if you know of a way to extend AuthManager.php in the app)
  2. AppServiceProvider.php to the rescue! Custom guards can be registered in AppServiceProvider::boot() and intercepted before the default code can be executed.
  3. I’m OK with point 2 above, but couldn’t we do something clever like return the custom session-guard name or instance from AppServiceProvider, have setCookieJar(), setDispatcher(), setRequest() in a specialized public method in AuthManager.php, which can be hooked into AppServiceProvider.php or driven by config/auth.php to execute after creating the custom session-guard in AuthManager.php?
  4. Without the cookies or sessions, the user’s identity isn’t preserved through the redirect. The only way to resolve this is to include the setCookieJar(), setDispatcher() and setRequest() in AppServiceProvider within our current solution.
JavaScript

config/auth.php

Sources:

JavaScript

How To Use This Solution

Very simple. There’s no change in the overall approach. In other words, we use the Auth() facade.

When logging in with your custom API /login?username=<username>&password=<password>

JavaScript

When logging out with your custom API /logout

JavaScript
User contributions licensed under: CC BY-SA
4 People found this is helpful
Advertisement