Laravel
Laravel

Introduction

Integrate Botbye bot protection into your Laravel application using middleware. This guide shows how to protect your Laravel routes with minimal configuration.

Installation

Install the SDK via Composer:

1
composer require botbye/botbye-php-sdk

Configuration

Register the Botbye client in your AppServiceProvider:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php

namespace App\Providers;

use Botbye\Client\BotbyeClient;
use Botbye\Client\BotbyeConfig;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        $this->app->singleton(BotbyeClient::class, function ($app) {
            $config = new BotbyeConfig(
                // Use your project server-key
                serverKey: '00000000-0000-0000-0000-000000000000'
            );

            return new BotbyeClient($config);
        });
    }

    public function boot(): void
    {
        //
    }
}

Usage

1. Create a middleware to validate requests:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<?php

namespace App\Http\Middleware;

use Botbye\Client\BotbyeClient;
use Botbye\Model\ConnectionDetails;
use Botbye\Model\Headers;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class BotbyeMiddleware
{
    public function __construct(
        private BotbyeClient $botbye
    ) {
    }

    public function handle(Request $request, Closure $next): Response
    {
        $connectionDetails = new ConnectionDetails(
            remoteAddr: $request->ip(),
            requestMethod: $request->method(),
            requestUri: $request->getRequestUri(),
            serverPort: $request->getPort(),
            serverName: $request->getHost()
        );

        $headers = Headers::fromArray($request->headers->all());

        // Get token from header or any place you store it.
        // For example in "x-botbye-token" header
        $token = $request->header('x-botbye-token')

        $response = $this->botbye->validateRequest(
            token: $token,
            connectionDetails: $connectionDetails,
            headers: $headers,
            customFields: [
                'user_id' => $request->user()?->id,
                'session_id' => $request->session()->getId(),
            ]
        );

        if ($response->result !== null && !$response->result->isAllowed) {
            abort(403, 'Access denied by Botbye protection');
        }

        return $next($request);
    }
}

2. Add the middleware to app/Http/Kernel.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php

namespace App\Http;

use Illuminate\Foundation\Http\Kernel as HttpKernel;

class Kernel extends HttpKernel
{
    protected $middlewareAliases = [
        // ... other middleware
        'botbye' => \App\Http\Middleware\BotbyeMiddleware::class,
    ];
}

3. Apply the middleware to specific routes:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php

use Illuminate\Support\Facades\Route;

// Protect a single route
Route::post('/api/checkout', [CheckoutController::class, 'process'])
    ->middleware('botbye');

// Protect a group of routes
Route::middleware(['botbye'])->group(function () {
    Route::post('/api/login', [AuthController::class, 'login']);
    Route::post('/api/register', [AuthController::class, 'register']);
    Route::post('/api/checkout', [CheckoutController::class, 'process']);
});

// Protect all API routes
Route::middleware(['api', 'botbye'])->prefix('api')->group(function () {
    // Your API routes
});

Advanced Configuration

Custom HTTP Client

Configure a custom HTTP client with Laravel's HTTP client:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php

namespace App\Providers;

use Botbye\Client\BotbyeClient;
use Botbye\Client\BotbyeConfig;
use Illuminate\Support\ServiceProvider;
use Symfony\Component\HttpClient\HttpClient;

class AppServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        $this->app->singleton(BotbyeClient::class, function ($app) {
            $config = new BotbyeConfig(
                serverKey: '00000000-0000-0000-0000-000000000000',
            );

            $httpClient = HttpClient::create([
                'timeout' => 1,
                'max_redirects' => 0,
            ]);

            return new BotbyeClient($config, $httpClient);
        });
    }
}

Logging Integration

Integrate with Laravel's logging system:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php

namespace App\Providers;

use Botbye\Client\BotbyeClient;
use Botbye\Client\BotbyeConfig;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Log;

class AppServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        $this->app->singleton(BotbyeClient::class, function ($app) {
            $config = new BotbyeConfig(
                serverKey: '00000000-0000-0000-0000-000000000000'
            );

            // Use Laravel's PSR-3 compatible logger
            return new BotbyeClient($config, null, Log::channel('botbye'));
        });
    }
}

Configure the log channel in config/logging.php:

1
2
3
4
5
6
7
8
9
10
'channels' => [
    // ... other channels

    'botbye' => [
        'driver' => 'daily',
        'path' => storage_path('logs/botbye.log'),
        'level' => 'warning',
        'days' => 14,
    ],
],

Best Practices

1. Selective Protection - Only apply middleware to routes that need protection

2. Custom Fields - You cab pass user context for better analysis

3. Logging - Monitor Botbye errors and blocked requests

Testing

Mock the Botbye client in your tests:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<?php

namespace Tests\Feature;

use Botbye\Client\BotbyeClient;
use Botbye\Model\BotbyeResponse;
use Botbye\Model\BotbyeResult;
use Tests\TestCase;

class ProtectedRouteTest extends TestCase
{
    public function test_allowed_request()
    {
        $mockClient = $this->mock(BotbyeClient::class);

        $mockClient->shouldReceive('validateRequest')
            ->once()
            ->andReturn(new BotbyeResponse(
                result: new BotbyeResult(isAllowed: true),
                error: null
            ));

        $response = $this->post('/api/checkout', [
            'item' => 'test',
        ]);

        $response->assertStatus(200);
    }

    public function test_blocked_request()
    {
        $mockClient = $this->mock(BotbyeClient::class);

        $mockClient->shouldReceive('validateRequest')
            ->once()
            ->andReturn(new BotbyeResponse(
                result: new BotbyeResult(isAllowed: false),
                error: null
            ));

        $response = $this->post('/api/checkout', [
            'item' => 'test',
        ]);

        $response->assertStatus(403);
    }
}

Examples of BotBye API responses

Bot detected:

1
2
3
4
5
6
7
{
  "reqId": "f77b2abd-c5d7-44f0-be4f-174b04876583",
  "result": {
    "isAllowed": false
  },
  "error": "Automation tool used"
}

Bot not detected:

1
2
3
4
5
6
7
{
  "reqId": "f77b2abd-c5d7-44f0-be4f-174b04876583",
  "result": {
    "isAllowed": true
  },
  "error": null
}

Request banned by custom rule:

1
2
3
4
5
6
7
8
9
{
  "reqId": "f77b2abd-c5d7-44f0-be4f-174b04876583",
  "result": {
    "isAllowed": false
  },
  "error": {
    "message": "Banned by rule: MY_CUSTOM_RULE"
  }
}

Invalid server-key:

1
2
3
4
5
6
7
{
  "reqId": "f77b2abd-c5d7-44f0-be4f-174b04876583",
  "result": null,
  "error": {
    "message": "[BotBye] Bad Request: Invalid Server Key"
  }
}