Keep your forms alive, avoid `TokenMismatchException` by gently poking your Laravel app.

Overview

Poke

Latest Version on Packagist Latest stable test run Codecov coverage Maintainability Laravel Octane Compatibility

Keep your forms alive, avoid TokenMismatchException by gently poking your Laravel app.

Keep this package free

Your support allows me to keep this package free, up-to-date and maintainable. Alternatively, you can spread the word!

Requirements

  • PHP 8.0 or later.
  • Laravel 9.x or later.

Installation

Require this package into your project using Composer:

composer require laragear/poke

How does it work?

This package pokes your App with an HTTP HEAD request to the /poke route at given intervals. In return, while your application renews the session lifetime, it returns an HTTP 204 status code, which is an OK Response without body.

This amounts to barely 0.8 KB sent!

Automatic Reloading on CSRF token expiration

The Poke script will detect if the CSRF session token is expired based on the last successful poke, and forcefully reload the page if there is Internet connection.

This is done by detecting when the browser or tab becomes active, or when the device user becomes online again.

This is handy in situations when the user laptop is put to sleep, or the phone loses signal. Because the session may expire during these moments, the page is reloaded to get the new CSRF token when the browser wakes up or the phone becomes online.

Usage

There are three ways to turn on Poke in your app.

  • auto (easy hands-off default)
  • middleware
  • blade (best performance)

You can change the default mode using your environment file:

POKE_MODE=auto

auto

Just install this package and look at it go. This will append a middleware in the web group that will look into all your Responses content where:

  • the request accepts HTML, and
  • an input with csrf token is present.

If there is any match, this will inject the Poke script in charge to keep the forms alive just before the </body> tag.

This mode won't inject the script on error responses or redirections.

It's recommended to use the other modes if your application has many routes or Responses with a lot of text.

middleware

This mode does not push the middleware to the web group. Instead, it allows you to use the poke middleware only in the routes you decide.

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\Auth\RegisterController;

Route::get('register', RegisterController::class)->middleware('poke');

This will inject the script into the route response if there is an input with a CSRF token. You can also apply this to a route group.

You may want to use the force option to forcefully inject the script at the end of the <body> tag, regardless of the CSRF token input presence. This may be handy when you expect to dynamically load forms on a view after its loaded, or SPA.

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\StatusController;

Route::get('status', StatusController::class)->middleware('poke:force');

As with auto mode, this mode won't inject the script on errors or redirections.

blade

The blade mode disables middleware injection, so you can use the <x-poke.script /> component freely to inject the script anywhere in your view, preferably before the closing </body> tag.

<body>
    <h2>Try to Login:</h2>
    <form action="/login" method="post">
        @csrf
        <input type="text" name="username" required>
        <input type="password" name="password" required>
        <button type="submit">Log me in!</button>
    </form>
    
    <x-poke.script /> <!-- This is a good place to put it -->
</body>

This may be useful if you have large responses, like blog posts, articles or galleries, since the framework won't spend resources inspecting the response, but just rendering the component.

Don't worry if you have duplicate Poke components in your view. The script is rendered only once, and even if not, the script only runs once.

Configuration

For fine-tuning, you can publish the poke.php config file.

php artisan vendor:publish --provider="Laragear\Poke\PokeServiceProvider" --tag="config"

Let's examine the configuration array:

return [
    'mode' => env('POKE_MODE', 'auto'),
    'times' => 4,
    'poking' => [
        'route' => 'poke',
        'name' => 'poke',
        'domain' => null,
        'middleware' => 'web',
    ]
];

Times (Interval)

How many times the poking will be done relative to the global session lifetime. The more times, the shorter the poking interval. The default 4 should be fine for any normal application.

For example, if our session lifetime is the default of 120 minutes:

  • 3 times will poke the application each 40 minutes,
  • 4 times will poke the application each 30 minutes,
  • 5 times will poke the application each 24 minutes,
  • 6 times will poke the application each 20 minutes, and so on...

In other words, session lifetime / times = poking interval.

  • 🔺 Raise the intervals if you expect users idling in your site for several minutes, even hours.
  • 🔻 Lower the intervals if you expect users with a lot of activity.

Poking

This is the array of settings for the poking route which receives the Poke script request.

return [
    'poking' => [
        'route' => 'poke',
        'name' => 'poke',
        'domain' => null,
        'middleware' => ['web'],
    ]
];

Route

The route (relative to the root URL of your application) that will be using to receive the pokes.

return [
    'poking' => [
        'route' => '/dont-sleep'
    ],
];

The poke routes are registered at boot time.

Name

Name of the route, to find the poke route in your app for whatever reason.

return [
    'poking' => [
        'name' => 'my-custom-poking-route'
    ],
];

Domain

The Poke route is available on all domains. Setting a given domain will scope the route to that domain.

In case you are using a domain or domain pattern, it may be convenient to put the Poke route under a certain one. A classic example is to make the poking available at http://user.myapp.com/poke but no http://api.myapp.com/poke.

return [
    'poking' => [
        'domain' => '{user}.myapp.com'
    ],
];

Middleware

The default Poke route uses the web middleware group to function properly, as this group handles session, cookies and CSRF tokens.

You can add your own middleware here if you need to.

return [
    'poking' => [
        'middleware' => ['web', 'validates-ip', 'my-custom-middleware']
    ],
];

You can also use the "bare minimum" middleware if you feel like it, thus it may be problematic if you don't know what you're doing.

return [
    'poking' => [
        'middleware' => [
            \Illuminate\Cookie\Middleware\EncryptCookies::class,
            \Illuminate\Session\Middleware\StartSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
        ],
    ]
]

Script View

Poke injects the script as a Blade component at all times.

You can override the script by publishing it under the views tag:

php artisan vendor:publish --provider="Laragear\Poke\PokeServiceProvider" --tag="views"

Some people may want to change the script to use a custom Javascript HTTP library, minify the response, make it compatible for older browsers, or even create a custom Event when CSRF token expires.

The view receives three variables:

  • $route: The relative route where the poking will be done.
  • $interval: The interval in milliseconds the poking should be done.
  • $lifetime: The session lifetime in milliseconds.

Laravel Octane compatibility

  • Only the InjectsScript middleware is bound as a singleton, and it saves the mode, which will persist across all the process lifetime. The mode is not intended to change request-by-request.

There should be no problems using this package with Laravel Octane.

Security

If you discover any security related issues, please email [email protected] instead of using the issue tracker.

License

This specific package version is licensed under the terms of the MIT License, at time of publishing.

Laravel is a Trademark of Taylor Otwell. Copyright © 2011-2022 Laravel LLC.

You might also like...
Todo App with Laravel 8

Todo App with Laravel 8 Demo: https://phplaravel-664318-2249917.cloudwaysapps.com/ username: [email protected] password: demodemo Features 2 Models

Laravel implementation of the RealWorld app

Laravel implementation of RealWorld app This Laravel app is part of the RealWorld project and implementation of the Laravel best practices. See how th

Todo App using Laravel 8 + Vuejs

Todo App using Laravel 8 + Vuejs

A mini social media like web app built using Laravel 8 & Vue JS 3

About Laravel Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experie

Laravel Back-End for "Expiry Cart" App

About Laravel Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experie

Hotel Management App using Laravel & Orchid for admin

Hotel Management System Installation Open a terminal session in the project's root. Install dependencies by running the command: composer install Run

Laravel 9 Web App - Our client José Gustavo, passionate about soccer and technology, wants to have an application that simulates the soccer leagues in his neighborhood, called My League.

Laravel 9 Web App - Our client José Gustavo, passionate about soccer and technology, wants to have an application that simulates the soccer leagues in his neighborhood, called My League.

A Real time chat app made in Next.js, Laravel and Ably.

Chat App with Next.js, Laravel and Ably This repository serves as a code container for the tutorial I wrote on Ably's Blog. Blog link will be updated

Instagram Clone App made with Laravel a PHP Framework

About Laravel Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experie

Comments
  • [1.x] Fix: ReferenceError in JavaScript code preventing refresh

    [1.x] Fix: ReferenceError in JavaScript code preventing refresh

    Description

    Const variables will be locally scoped to the block instead of scoped to the global object. Therefore, when the if body for poke_reload_window's type executes, the poke_reload_window will only be defined in that if body's block. This means that the call in poke_expire_check will not succeed as the function is not defined in that scope. Hence a ReferenceError will occur and the page will not be refreshed. Fix this by just replacing the call to poke_reload_window by its contents.

    More specifically, this is the error in the JS console: Uncaught (in promise) ReferenceError: poke_reload_window is not defined.

    Code samples

    N/A. It is reproducible by having the poke script trying to refresh the page.

    opened by nielsdos 2
  • Unable to locate a class or view for component [poke.script].

    Unable to locate a class or view for component [poke.script].

    Hi, I have tried to use the <x-poke.script /> component to inject the script in my view but it does not work.

    Unable to locate a class or view for component [poke.script].

    opened by padre 1
Releases(v1.0.4)
  • v1.0.4(Nov 17, 2022)

    What's Changed

    • Apply fixes from StyleCI by @DarkGhostHunter in https://github.com/Laragear/Poke/pull/4
    • [1.x] Fix: ReferenceError in JavaScript code preventing refresh by @nielsdos in https://github.com/Laragear/Poke/pull/5

    New Contributors

    • @nielsdos made their first contribution in https://github.com/Laragear/Poke/pull/5

    Full Changelog: https://github.com/Laragear/Poke/compare/v1.0.3...v1.0.4

    Source code(tar.gz)
    Source code(zip)
  • v1.0.3(Feb 24, 2022)

  • v1.0.1(Feb 23, 2022)

Owner
Laragear
Packages for Laravel
Laragear
DaybydayCRM an open-source CRM, to help you keep track of your daily workflow.

====================== DaybydayCRM is an everyday customer relationship management system (CRM) to help you keep track of your customers, tasks, appoi

Casper Bottelet 2.1k Jan 3, 2023
A dynamic Laravel Livewire component for tab forms

Livewire component that provides you with a tabs that supports multiple tabs form while maintaining state.

Vildan Bina 36 Nov 8, 2022
Scrumwala: Your very own Scrum, Agile project management web app - built with Laravel

Scrumwala Your very own Scrum/Agile web app built with Laravel Features Create and manage projects with plan and work views Group issues in a project

null 255 Nov 2, 2022
Web app to share your favorite photos, made with laravel

Kuro Photos Web app to share your favorite photos, made with laravel. This web app was made for educationals purposes only. I enjoyed so much learning

Julian Salcedo Torres 4 Dec 29, 2022
📇A contacts app for Nextcloud. Easily sync contacts from various devices with your Nextcloud and edit them online.

Nextcloud Contacts A contacts app for Nextcloud. Easily sync contacts from various devices with your Nextcloud and edit them online. This app only sup

Nextcloud 485 Dec 30, 2022
A simple Lumen web app to send basic commands and fetch the current status to your Ford vehicle with Sync 3 enabled

FordPass Access This is a simple Lumen web app to send basic commands and fetch the current status to your Ford vehicle with Sync 3 enabled. Local dev

Sam 4 Nov 21, 2022
Laravel web app for signing up for community service opportunities

Community Service A Laravel web app for registering for service opportunities. Installation Make sure the following are installed on your system: Node

North Point Ministries 0 Mar 6, 2019
A Visual Bookmark App built on top of Laravel 5

Laravel Bookmark Visual bookmark organizer application in Laravel ![screenshot](https://rivario.com/bookmark/images/bookmark.png ""bookmark"") Working

YongHun Byun 155 Mar 25, 2022
A Powerful Laravel Help Desk and Lead Management App

Handesk Description Handesk has been created by our need (At Revo Systems www.revo.works) to have a powerful yet simple Ticketing system, we needed a

Jordi Puigdellívol 1.2k Jan 2, 2023
A good, non-specialized Laravel base site for faster app development

Larastrap This is a non-specialized Laravel base site containing generalized components for faster development of nearly any type of site. It includes

Memphis PHP 2 Jul 31, 2022