Laravel 11 Firebase Push Notification (Mobile Application with Flutter)

Jalis MahamudJalis Mahamud
3 min read

This documentation is for implementing Laravel backend push notifications for a Flutter mobile application. This feature enables sending live notifications to users

Step 01: Set up functionality for Firebase

\>Download the JSON file from Firebase

\>Install (composer require kreait/laravel-firebase)

\>migrate and model the file, make

>Route File for managing the token, device_id

\>Route for push notification

\>Helper Function

Step 02: Set up environment credentials

.env file edit the file name

FIREBASE_CREDENTIALS=app/private/your-firebase-private-file-name.json

Step 03: Set up migration, model ,and user model relationships

create_firebase_tokens_table

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('firebase_tokens', function (Blueprint $table) {
            $table->id();
            $table->foreignId('user_id')->nullable()->constrained()->cascadeOnUpdate()->restrictOnDelete();
            $table->longText('token');
            $table->longText('device_id');
            $table->enum('status', ['active', 'inactive'])->default('active');
            $table->timestamps();
        });
    }


    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('firebase_tokens');
    }
};

Set up FirebaseToken model

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Factories\HasFactory;

class FirebaseToken extends Model
{
    use HasFactory;

    protected $guarded = [];

    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }
}

Setup User model relationship

 public function firebaseTokens()
    {
        return $this->hasMany(FirebaseToken::class);
    }

Step 04: Create Controller logic

FirebaseTokenController.php

<?php

namespace App\Http\Controllers\Api\Backend;

use Exception;
use App\Models\User;
use App\Helper\Helper;
use Illuminate\Http\Request;
use App\Models\FirebaseToken;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Validator;

class FirebaseTokenController extends Controller
{
    public function test()
    {
        $user = User::find(auth('api')->user()->id);

        if ($user && $user->firebaseTokens) {
            $notifyData = [
                'title' => "test title",
                'body'  => "test body",
                'icon'  => env('APP_ICON')
            ];

            foreach ($user->firebaseTokens as $firebaseToken) {
                Helper::sendNotifyMobile($firebaseToken->token, $notifyData);
            }
        }

        return response()->json([
            'status'  => true,
            'message' => 'Token saved successfully',
            'data'    => $user ? $user->firebaseTokens : [],
            'code'    => 200,
        ], 200);
    }

    public function store(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'token'     => 'required|string',
            'device_id' => 'required|string',
        ]);

        if ($validator->fails()) {
            return response()->json(['message' => $validator->errors()->first()], 400);
        }

        $firebase = FirebaseToken::where('user_id', auth('api')->user()->id)
            ->where('device_id', $request->device_id)
            ->first();

        if ($firebase) {
            $firebase->delete();
        }

        try {
            $data = new FirebaseToken();
            $data->user_id = auth('api')->user()->id;
            $data->token = $request->token;
            $data->device_id = $request->device_id;
            $data->status = "active";
            $data->save();

            return response()->json([
                'status'  => true,
                'message' => 'Token saved successfully',
                'data'    => $data,
                'code'    => 200,
            ], 200);
        } catch (Exception $e) {
            return response()->json([
                'status'  => false,
                'message' => 'No records found',
                'code'    => 418,
                'data'    => [],
            ], 418);
        }
    }

    public function getToken(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'device_id' => 'required|string',
        ]);

        if ($validator->fails()) {
            return response()->json(['message' => $validator->errors()->first()], 400);
        }

        $user_id = auth('api')->user()->id;
        $device_id = $request->device_id;

        $data = FirebaseToken::where('user_id', $user_id)
            ->where('device_id', $device_id)
            ->get();

        if (!$data) {
            return response()->json([
                'status'  => false,
                'message' => 'No records found',
                'code'    => 404,
                'data'    => [],
            ], 404);
        }

        return response()->json([
            'status'  => true,
            'message' => 'Token fetched successfully',
            'data'    => $data,
            'code'    => 200,
        ], 200);
    }

    public function deleteToken(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'device_id' => 'required|string',
        ]);

        if ($validator->fails()) {
            return response()->json(['message' => $validator->errors()->first()], 400);
        }

        $user = FirebaseToken::where('user_id', auth('api')->user()->id)
            ->where('device_id', $request->device_id)
            ->first();

        if ($user) {
            $user->delete();

            return response()->json([
                'status'  => true,
                'message' => 'Token deleted successfully',
                'code'    => 200,
            ], 200);
        } else {
            return response()->json([
                'status'  => false,
                'message' => 'No records found',
                'code'    => 404,
            ], 404);
        }
    }
}

Step 05: Set up routes

app.php file (Those routes should be in the authenticated routes)

 // Firebase Token Module
    Route::get("firebase/test", [FirebaseTokenController::class, 'test']);
    Route::post("firebase/token/add", [FirebaseTokenController::class, 'store']);
    Route::post("firebase/token/get", [FirebaseTokenController::class, 'getToken']);
    Route::post("firebase/token/delete", [FirebaseTokenController::class, 'deleteToken']);

Step 06: Set up Helper logic

Helper.php file

use Illuminate\Support\Str;
use Kreait\Firebase\Factory;
use Illuminate\Support\Facades\Log;
use Kreait\Firebase\Messaging\CloudMessage;
use Kreait\Firebase\Messaging\Notification; 

public static function sendNotifyMobile($token, $notifyData): void
    {
        try {
            $factory = (new Factory)->withServiceAccount(storage_path(env('FIREBASE_CREDENTIALS')));
            $messaging = $factory->createMessaging();
            $notification = Notification::create($notifyData['title'], Str::limit($notifyData['body'], 100), $notifyData['icon']);
            $message = CloudMessage::withTarget('token', $token)->withNotification($notification);
            $messaging->send($message);
        } catch (Exception $exception) {
            Log::error($exception->getMessage());
        }
        return;
    }

Step 07: Test using Postman tool

Need a device ID and token


๐Ÿ’ก
Thank You!
0
Subscribe to my newsletter

Read articles from Jalis Mahamud directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Jalis Mahamud
Jalis Mahamud

๐Ÿ‘จโ€๐Ÿ’ป Laravel Developer | PHP | MySQL | REST APIs Hi, I'm a Laravel developer with experience in building web applications using PHP and modern development practices. I work on backend systems, RESTful APIs, and database structures. I enjoy writing clean code, integrating third-party services, and improving workflows for better performance. ๐Ÿ”ง Tools I often use: Laravel, MySQL, Git, Composer, REST APIs ๐Ÿš€ Focused on: Simplicity, performance, and maintainability