DEV Community

Cover image for Elegant Ways to Distribute Commercial Laravel Source Code Without Sacrificing Developer Experience
Alfiansa
Alfiansa

Posted on • Originally published at blog.fiandev.com

Elegant Ways to Distribute Commercial Laravel Source Code Without Sacrificing Developer Experience

Many development teams struggle with the challenges of software distribution architecture.

When we build a commercial product and intend to distribute it with a licensing system, the first instinct is usually to lock down and encrypt the entire codebase.

We feel the need to protect intellectual property strictly so it cannot be pirated or redistributed illegally.

However, field experience shows that blindly encrypting the entire project repository is a fatal mistake.

This paranoid approach makes it difficult for clients to perform fundamental configurations.

For example, adjusting routing, adding custom middleware, or simply modifying the UI to match their brand identity.

In addition to destroying flexibility, full encryption also burdens the server and drastically decreases application performance.

The execution of fully encrypted code requires significantly higher computing resources.

Therefore, we need a smarter and more structured enterprise-level approach.

We must find a balance: exclusive business logic remains secure, while the application framework remains open for exploration and modification by the client.

Separating Core Logic into Private Packages

The key to an elegant distribution architecture is modular separation between the main framework and secret business logic.

Never ship a full Laravel project in an encrypted state.

Instead, extract all crucial "secret sauce" features into their own modules.

Features such as billing systems, core algorithms, and license validation mechanisms should be completely separated from the main application.

Encapsulate all such sensitive logic into a custom Composer package.

For instance, we could name it acme/core-module as an internal naming standard.

By isolating code into a separate package, the main Laravel application directory held by the client remains clean, transparent, and easy to develop.

Once the core logic is isolated, only then do we apply code protection processes.

Encryption and compilation using tools like IonCube or AST (Abstract Syntax Tree) manipulation techniques via yakpro-php are only applied to that acme/core-module package.

The rest of the application outside that package remains readable, standard PHP code.

This approach ensures that only the "brain" of the application is tightly protected, while the other "limbs" are free to move and adapt.

To distribute the compiled package, use a closed distribution ecosystem.

We can utilize Private Packagist or build our own Satis server.

From the client's side, the installation experience remains natural and familiar.

They simply run a standard composer require in the server terminal, include a valid authentication token, and the secret package will be automatically downloaded in an obfuscated format.

Building a Robust License Validation Architecture

Encrypted code alone is not enough without a gateway system that validates access rights.

We need a centralized license server tasked with issuing, managing, and validating every license key.

On the client application side, design a specific Service Provider or Middleware that is always ready to perform HTTP communication with the license server to ensure installation validity.

Ideal license key validation should not just match a string of random characters.

The data payload during verification must bind the license key to the identity of the client's server environment.

Include unique parameters such as the domain name, server IP address, or even the MAC address.

Binding the license to physical and network parameters is important to prevent a single pirated license key from being used across dozens of different installations.

In a client-server implementation, avoid a fatal error: forcing the client application to contact the license server on every page request.

Such an architectural design is terrible for performance.

It is mandatory to implement a solid caching mechanism.

Store license verification results and feature scope status in fast memory like Redis or the local file system.

Set the cache expiration time between 12 to 24 hours.

Besides performance, this cache acts as a safety net during network failures.

The license server might experience downtime, or the client server might suddenly lose internet connection.

In a worst-case scenario, the commercial application should not immediately crash or lock up.

Provide a grace period of several days so the client has time to fix the connection before the system fully deactivates paid features.

Securing Payload Communication with Cryptography

Data security principles from blockchain technology can be adapted to maintain message integrity between servers.

Client developers often have high technical skills, and some might try to bypass the system by rerouting network traffic.

They could create a fake server to mimic our verification responses.

If you rely only on a standard JSON response with a success status, spoofing will be easy to perform.

To counter man-in-the-middle manipulation attacks, implement asymmetric cryptography using the RSA algorithm.

The central license server must hold a strictly secret Private Key.

This private key is used exclusively to sign every data response sent to the client.

This signature is mathematical proof that cannot be forged, confirming the message truly originated from our official server.

On the other hand, the client application hidden inside the encrypted package will store the corresponding Public Key.

When the application receives a response from the server, the first thing it does is verify the digital signature using the public key.

If even a single byte of the response data is manipulated by the client or a third party, the signature verification process will immediately fail mathematically.

The application then automatically blocks overall access.

Integrating License Status with Filament Panels

Once all layers of security architecture and communication logic are running smoothly behind the scenes, the final stage is connecting it to the user interface.

In the modern Laravel ecosystem, Filament is a solid choice for building elegant and interactive administration panels.

We can implement feature flagging concepts directly in the Filament panel provider configuration based on the validated license level.

Retrieve the license scope data previously stored securely in the cache.

Based on regular or premium license status, we can register plugins, render navigation menus, or display pages dynamically.

This conditional logic ensures clients only see and access the interface corresponding to their rights.

public function panel(Panel $panel): Panel
{
    $licenseScope = Cache::get('app_license_scope', 'unlicensed');

    return $panel
        ->default()
        ->id('admin')
        ->path('admin')
        ->plugins([
            $licenseScope === 'premium' ? new \App\Filament\Plugins\AdvancedReportingPlugin() : null,
        ])
        ->navigation(function (NavigationBuilder $builder) use ($licenseScope): NavigationBuilder {
            $navigation = [
                NavigationItem::make('Dashboard')->url(fn (): string => Dashboard::getUrl()),
                NavigationGroup::make('Basic Features')->items([...]),
            ];

            if (in_array($licenseScope, ['premium', 'pro'])) {
                $navigation[] = NavigationGroup::make('Premium Features')->items([...]);
            }

            return $builder->groups(array_filter($navigation));
        });
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)