Custom Laravel auth driver with Firebase
Firebase Authentication is a super powerful and easy-to-use service to authenticate users to your app. It comes with a bunch of auth providers such as traditional email/password authentication, GitHub, Google, password-less mobile number authentication, and more.
It's pretty straightforward to authenticate a user in your frontend app, but you may need to authenticate the user on the backend api as well. When a user gets authenticated, Firebase will give the user a JWT token that contains the user info. By sending the JWT to the backend api, you can decode and verify the JWT and retrieve the user info on the backend. For more details, check out my blog post on how to verify Firebase JWT using Laravel.
In this post, I will show you how to customise Laravel auth driver using Firebase. I'm going to use the FirebaseToken
class that I shared in my previous post.
Link Firebase users with users table
I assume that you have users
table in your Laravel app for storing user data while using Firebase for authentication. We wouldn't store any additional attributes on Firebase user since it's not meant be used as a database.
This means that we need to link Firebase users with the users
table records. We are going to store Firebase user id as the id
column in the users
table. Let's change the id
column to string (i.e. varchar) type and drop unnecessary columns. Most of the default columns are not required if you use Firebase Authentication.
Schema::table('users', function (Blueprint $table) {
$table->string('id')->change();
$table->dropColumn('email_verified_at');
$table->dropColumn('password');
$table->dropColumn('remember_token');
});
Since we changed the primary key to a string column, we need to update the User
eloequent model like below.
class User extends Authenticatable
{
use HasFactory;
use Notifiable;
/**
* The primary key associated with the table.
*
* @var string
*/
protected $primaryKey = 'id';
/**
* Indicates if the IDs are auto-incrementing.
*
* @var bool
*/
public $incrementing = false;
/**
* The "type" of the auto-incrementing ID.
*
* @var string
*/
protected $keyType = 'string';
////
}
Create a new user
Now that you can store Firebase user id in the users
table, let's create an endpoint to store a new user. Usually, you retrieve user info from the request body, however, we will retrieve it from JWT token that is passed via Authorization
HTTP header.
public function store(Request $request)
{
$token = new FirebaseToken($request->bearerToken());
try {
$payload = $token->verify(config('services.firebase.project_id'));
} catch (\Exception $e) {
// return error response
}
$user = User::create([
'id' => $payload->user_id,
'email' => $payload->email,
'name' => $payload->name,
'avatar' => $payload->avatar,
]);
return (new UserResource($user))
->response()
->setStatusCode(Response::HTTP_CREATED);
}
Custom authentication driver
Next, create a custom authentication driver so that you can authenticate the user in subsequent requests.
Call the Auth::viaRequest
method within the boot
method of your AuthServiceProvider
. The second argument passed to the method is a closure that receives the incoming HTTP request and returns a user instance or, if authentication fails, null.
public function boot()
{
$this->registerPolicies();
Auth::viaRequest('firebase', function (Request $request) {
$token = $request->bearerToken();
try {
$payload = (new FirebaseToken($token))->verify(
config('services.firebase.project_id')
);
return User::find($payload->user_id);
} catch (\Exception $e) {
return null;
}
});
}
Once you define custom auth driver, you can configure it as a driver within the guards
configuration of your config/auth.php
.
'guards' => [
'api' => [
'driver' => 'firebase',
],
],
Authenticate requests
Now, let's use the auth guard middleware and retreive the authenticated user data.
Route::middleware('auth:api')->group(function () {
Route::apiResource('posts', PostController::class);
}
class PostController extends Controller
{
public function index(Request $request)
{
// retrieve an authenticated user via request
$request->user();
////
}
}
Wrap up
You can use Firebase for authentication and store the user data in your Laravel application by decoding/verifying the JWT token. This way, you can leverage both Firebase's powerful authentication and Laravel's authentication guard. If you have any questions or comments, please comment in this Twitter thread!