Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

yagrasdemonde's avatar

Advices for a licensing system on Laravel

Hello,

I need some advices on the thinking / algorithm to set up a license system on my Laravel application.

Explanations: I have an application on which I want to ensure annual maintenance, via a system of "license" but without online payment on it.

I want to set a start date and an end date. And the idea is that one month before the deadline, a first email is sent to the customer, then 15 days before expiration another email.

At the end of the term, if the license has not been renewed, at the customer's identification on the application, he has access only the page indicating that his license has expired and not to others.

And frankly, I am in complete limbo to put this system in place on Laravel.

I am interested in all your advices, procedures, tracks etc.

Thank you all

0 likes
10 replies
Tray2's avatar

For the expire part you could use a middleware to check the status of the subscription. The emails you could check with a job that you run once a day to see if how many days there are left.

Something like this.

class CheckSubsription
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if ($request->today >= $user->dueDate) {
            return redirect('paynowtocontinue');
        }

        return $next($request);
    }
}

Read more here https://laravel.com/docs/5.7/middleware

if ($this->daysLeft == 30) {
 SubscriptionReminder::ThirtyDayNotice();
else if ($this->daysLeft == 15) {
 SubscriptionReminder::FifteenDayNotice();
}

Read more here https://laravel.com/docs/5.7/scheduling#scheduling-queued-jobs

Cronix's avatar

@D9705996 He said "but without online payment on it."

@yagrasdemonde Is this software that you will be hosting yourself, or will the clients have the source code and be able to self host? If you're the only one with access to the source code, this is pretty easy. If they have access to it, it's a LOT harder, if not impossible.

I want to set a start date and an end date. And the idea is that one month before the deadline, a first email is sent to the customer, then 15 days before expiration another email.

At the end of the term, if the license has not been renewed, at the customer's identification on the application, he has access only the page indicating that his license has expired and not to others.

That part would be easy to do with a daily() scheduled task.

  1. check accounts that expire a month from now, send initial email
  2. check accounts that expire 15 days from now, send 2nd email
  3. check accounts that expire today, set is_active (or whatever) to false on the user table and check that flag when trying to login. If they have is_active = 0, redirect them to the page showing their subscription has expired.

https://laravel.com/docs/5.6/scheduling

yagrasdemonde's avatar

@Cronix Yes my application is hosted on my server. So my clients can't access to source code.

What is the best way : use an middleware or event/listener or anything way ?

Actually I did a little test like this in my LoginController (in authenticated method)

protected function authenticated()
    {
        $message = 'Expired licence';
        if(!auth()->user()->hasRole('Admin')){
            $licenceDebut = Carbon::createFromFormat('d/m/Y', config('config_app.licenceStart'));
            $licenceFin = Carbon::createFromFormat('d/m/Y', config('config_app.licenceEnd'));
            if(Carbon::now('Europe/Paris')->between($licenceStart, $licenceEnd)){
                //licence valid
            }else{
                $errors = new MessageBag();
                $errors->add('licence_expired', $message);

                auth()->logout();

                return back()->withErrors($errors);
            }
        }
    }

In this way I return on my login page and show the error message. But before going further (send mails with jobs) I don't know if is the good idea to do this.

And @Cronix, I'll prefer don't add a field is_active on my user table

Cronix's avatar

I think all you'd need to check is whether today is >= licenseEnd. It doesn't matter if today is between start and end, does it? Only that it's past the expired date.

Are all the clients going to have their own instance of the app? I ask because you're hardcoding the start/end dates in a config file instead of on the user (or other) table. Presumably each client would have their own start/stop dates?

What is the best way : use an middleware or event/listener or anything way ?

I like to do it on login, because then it only checks once. If it's in middleware, it will check it on every request, which seems a bit overboard for this. Just don't let them login if the subscription is expired.

There is already a Illuminate\Auth\Events\Authenticated event that you can listen to, and do the subscription check there. It's really the same as what you have above though, but keeps the code separate. Either way it does the same thing, so just comes down to how you prefer to structure your code. https://laravel.com/docs/5.7/authentication#events

D9705996's avatar

@Cronix- licence checking on login would not work if session time is long.

It might be worth trying to isolate the routes that are impacted by changes to the licence and applying the middleware to them only

Cronix's avatar

Not sure of your point on the session length. I've always just used the default 2 hours. I guess theoretically they could just keep the session alive by submitting something every 2 hours, 24 hours a day, but that's highly unlikely. I also disable logging in by cookie (remember me).

yagrasdemonde's avatar

@Cronix Yes you are right, I need just test if today >= licenceEnd.

In fact I have one user who is my client (with Client Role) and others can just use some forms after login with (Users Role). And the idea is the others users can use forms even the licence is expired, but only my client notified about his licence and on the login form, an error message showed if he tries to connect after the end of licence. (Because this user/client is the only one to validate datas sent by forms, and so if licence expired, he can't validate and he has to renew to keep use application).

So i'm trying to put my code in the LogAuthenticated Listener (with Illuminate\Auth\Events\Authenticated Event) but, error not showing...

public function handle(Authenticated $event)
    {
        $message = 'Expired licence';
        if(auth()->user()->hasRole('Client')){
            $licenceFin = Carbon::createFromFormat('d/m/Y', config('config_app.licenceEnd'));
            if(Carbon::now('Europe/Paris') == $licenceEnd->subDays(15)){
                $event->user->notify(new licence_soon_expired($message));
            }
            if(Carbon::now('Europe/Paris') == $licenceEnd->subMonth()){
                $event->user->notify(new licence_soon_expired($message));
            }
            if(Carbon::now('Europe/Paris') >= $licenceEnd){
                $errors = new MessageBag();
                $errors->add('licence_expired', $message);
                auth()->logout();
                return back()->withErrors($errors);
            }
        }
    }

What is my mistake ?

Please or to participate in this conversation.