Laravel 8 — Send Web Push Notification Using Firebase

In this article, we’ll create a working example which will send web push notification using Firebase and Laravel 8. Just follow below steps carefully and at the end you’ll have an working demo which will show whatever data you submit in a form as a web push notification whenever you open this project.

Firebase provides free open source push notification feature which you can easily implement using your google account (everyone has google account).

Before we start, you should have below things ready:

  1. Google Account
  2. Firebase Account (you can use this via your Google account)
  3. Fresh copy of Laravel 8 installed in your system
  4. Knowledge of how Laravel routes, views, models, controllers, migrations works

Once you have above things ready, its time to move forward with next steps. Here I’ve listed things we’re going to do in this article:

  1. Create Firebase Project
  2. Work on Auth using scaffold
  3. Create Migrations
  4. Create Route
  5. Update Controller
  6. Update Blade File
  7. Configure Firebase
  8. Test Web Push Notification

Lot’s of steps… so let’s start without any delay!!

1. Create Firebase Project

In this step we’ll create Firebase project and create an app inside it:

Open Firebase Console and then click on “+ Add Project”

You’ll see following screen where you need to provide a name of your project

Now create a web app with and give it a name like I’ve done it in screenshot

Once you do that, you’ll receive Firebase SDK which you need to save somewhere as we’re going to use that code in next steps.

2. Prepare Auth UI

In this step, we’re going to use Auth scaffold to create auth related pages real quick. So just run following commands:

composer require laravel/ui

php artisan ui bootstrap ––auth

npm install

npm run dev

3. Prepare Migrations, Model, Routes and Controller

In this step, we’re going to change lots of things and also going to add new things. So, read carefully each and every steps without any distractions:

First, we’ll add new table using migration

php artisan make:migration add_column_device_token

database/migrations/2020_10_23_144523_add_column_device_token.php

<?php
  
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
  
class AddColumnDeviceToken extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->string('device_token')->nullable();
        });
    }
  
    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
           
    }
}

app/Models/User.php

<?php
  
namespace App\Models;
  
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
  
class User extends Authenticatable
{
    use HasFactory, Notifiable;
  
    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name',
        'email',
        'password',
        'device_token'
    ];
  
    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];
  
    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];
}

now, let’s run migrations —

php artisan migrate

Now, its time to create route and modify controller..

routes/web.php

<?php
  
use Illuminate\Support\Facades\Route;
  
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
  
Route::get('/', function () {
    return view('welcome');
});
  
Auth::routes();
   
Route::get('/home', [App\Http\Controllers\HomeController::class, 'index'])->name('home');
Route::post('/save-token', [App\Http\Controllers\HomeController::class, 'saveToken'])->name('save-token');
Route::post('/send-notification', [App\Http\Controllers\HomeController::class, 'sendNotification'])->name('send.notification');

In order to modify controller, we need to add methods to it and our method needs “Server Key” from our Firebase project. You can get it from Project credentials section by going to Setting icon -> Cloud Messaging tab.

app/Http/Controllers/HomeController.php

<?php
  
namespace App\Http\Controllers;
  
use Illuminate\Http\Request;
use App\Models\User;
  
class HomeController extends Controller
{
    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('auth');
    }
  
    /**
     * Show the application dashboard.
     *
     * @return \Illuminate\Contracts\Support\Renderable
     */
    public function index()
    {
        return view('home');
    }
  
    /** 
     * Write code on Method
     *
     * @return response()
     */
    public function saveToken(Request $request)
    {
        auth()->user()->update(['device_token'=>$request->token]);
        return response()->json(['token saved successfully.']);
    }
  
    /**
     * Write code on Method
     *
     * @return response()
     */
    public function sendNotification(Request $request)
    {
        $firebaseToken = User::whereNotNull('device_token')->pluck('device_token')->all();
          
        $SERVER_API_KEY = 'XXXXXX';
  
        $data = [
            "registration_ids" => $firebaseToken,
            "notification" => [
                "title" => $request->title,
                "body" => $request->body,  
            ]
        ];
        $dataString = json_encode($data);
    
        $headers = [
            'Authorization: key=' . $SERVER_API_KEY,
            'Content-Type: application/json',
        ];
    
        $ch = curl_init();
      
        curl_setopt($ch, CURLOPT_URL, 'https://fcm.googleapis.com/fcm/send');
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $dataString);
               
        $response = curl_exec($ch);
  
        dd($response);
    }
}

4. Let’s prepare our blade file

In this step, we’ll be going to update our blade file to add Firebase related stuff so that whenever this file is called from route it can show Web Push notification. Paste following content in home.blade.php file and update firebaseConfig with your SDK config which you got from step #1

resources/views/home.blade.php

@extends('layouts.app')
@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <center>
                <button id="btn-nft-enable" onclick="initFirebaseMessagingRegistration()" class="btn btn-danger btn-xs btn-flat">Allow for Notification</button>
            </center>
            <div class="card">
                <div class="card-header">{{ __('Dashboard') }}</div>
                <div class="card-body">
                    @if (session('status'))
                    <div class="alert alert-success" role="alert">
                        {{ session('status') }}
                    </div>
                    @endif
                    <form action="{{ route('send.notification') }}" method="POST">
                        @csrf
                        <div class="form-group">
                            <label>Title</label>
                            <input type="text" class="form-control" name="title">
                        </div>
                        <div class="form-group">
                            <label>Body</label>
                            <textarea class="form-control" name="body"></textarea>
                        </div>
                        <button type="submit" class="btn btn-primary">Send Notification</button>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
<script>
    var firebaseConfig = {
        apiKey: "XXXX",
        authDomain: "XXXX.firebaseapp.com",
        databaseURL: "https://XXXX.firebaseio.com",
        projectId: "XXXX",
        storageBucket: "XXXX",
        messagingSenderId: "XXXX",
        appId: "XXXX",
        measurementId: "XXX"
    };
      
    firebase.initializeApp(firebaseConfig);
    const messaging = firebase.messaging();
    
    function initFirebaseMessagingRegistration() {
            messaging
            .requestPermission()
            .then(function () {
                return messaging.getToken()
            })
            .then(function(token) {
                console.log(token);
    
                $.ajaxSetup({
                    headers: {
                        'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
                    }
                });
    
                $.ajax({
                    url: '{{ route("save-token") }}',
                    type: 'POST',
                    data: {
                        token: token
                    },
                    dataType: 'JSON',
                    success: function (response) {
                        alert('Token saved successfully.');
                    },
                    error: function (err) {
                        console.log('User Chat Token Error'+ err);
                    },
                });
    
            }).catch(function (err) {
                console.log('User Chat Token Error'+ err);
            });
    }  

    initFirebaseMessagingRegistration()
      
    messaging.onMessage(function(payload) {
        const noteTitle = payload.notification.title;
        const noteOptions = {
            body: payload.notification.body,
            icon: payload.notification.icon,
        };
        new Notification(noteTitle, noteOptions);
    });
    
</script>
@endsection

5. Almost done, create firebase-messaging-sw.js file

public/firebase-messaging-sw.js

/*
Give the service worker access to Firebase Messaging.
Note that you can only use Firebase Messaging here, other Firebase libraries are not available in the service worker.
*/
importScripts('https://www.gstatic.com/firebasejs/7.23.0/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/7.23.0/firebase-messaging.js');
   
/*
 * Initialize the Firebase app in the service worker by passing in the messagingSenderId.
 */
firebase.initializeApp({
        apiKey: "XXXX",
        authDomain: "XXXX.firebaseapp.com",
        databaseURL: "https://XXXX.firebaseio.com",
        projectId: "XXXX",
        storageBucket: "XXXX",
        messagingSenderId: "XXXX",
        appId: "XXXX",
        measurementId: "XXX"
    });
  
/*
Retrieve an instance of Firebase Messaging so that it can handle background messages.
*/
const messaging = firebase.messaging();
messaging.setBackgroundMessageHandler(function(payload) {
    console.log(
        "[firebase-messaging-sw.js] Received background message ",
        payload,
    );
    /* Customize notification here */
    const notificationTitle = "Background Message Title";
    const notificationOptions = {
        body: "Background Message body.",
        icon: "/itwonders-web-logo.png",
    };
  
    return self.registration.showNotification(
        notificationTitle,
        notificationOptions,
    );
});

After you’ve created above file, do not forget to replace configurations with your configurations.

6. Finally, update layout file

Copy and paste following content under app.js script like this:

resource/views/layouts/app.blade.php:

<!-- Scripts -->
<script src="{{ asset('js/app.js') }}" defer></script>
<script src="https://www.gstatic.com/firebasejs/7.23.0/firebase.js"></script>
<script>
if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('./firebase-messaging-sw.js').then(function(registration) {
    console.log('Firebase Worker Registered');

    }).catch(function(err) {
    console.log('Service Worker registration failed: ', err);
    });
}
</script>

Above steps is to register our Firebase worker with our application.

Alrighty, now we’re good to go!! Let’s test this via executing following command:

php artisan serve

Once your Laravel app starts, follow these steps to see your web push notifications in actions:

  1. Open http://localhost:8000/
  2. Click on Register and submit signup form
  3. Once you’re registered successfully, you’ll be redirected to http://localhost:8000/home and you can see popup “Token saved successfully
  4. Now, open http://localhost:8000/home on another tab and submit it after filling up title and body
  5. Once you’ve submitted, you can see notification containing your Title and Body

If you got stuck anywhere in any step, just post a comment below.

UPDATE :: GitHub link — https://github.com/harshdoshi999/laravel-8-web-push-notification-firebase

2 thoughts on “Laravel 8 — Send Web Push Notification Using Firebase

Leave a Reply

Your email address will not be published.

three × four =