laravel-test-login maintained by branpolo
Laravel Test Login
Test authentication bypass for Laravel browser and API testing (Mink, Dusk, Behat, PHPUnit).
Why This Package?
When testing Laravel applications with external browser drivers (Behat/Mink, Panther, Chrome DevTools Protocol), you can't use Laravel's built-in `loginAs()` method because the test process and web server run in separate processes.
This package provides secure HTTP routes that allow external test frameworks to authenticate users, similar to how Laravel Dusk's `loginAs()` works internally.
Features
- Session-based login - For browser tests (Mink, Dusk, Panther)
- API token login - For API tests (requires Laravel Sanctum)
- Multi-guard support - Works with custom authentication guards
- Spatie Permissions integration - Auto-clears permission cache
- Environment-restricted - Routes only load in local/testing environments
Security Warning
These routes bypass normal authentication! They are designed ONLY for testing environments and should NEVER be available in production.
The package includes multiple safety measures:
- Routes only register in configured environments (default: `local`, `testing`)
- Environment check happens at boot time, not at request time
- Configuration allows customizing allowed environments
Installation
```bash composer require --dev branpolo/laravel-test-login ```
The package auto-registers via Laravel's package discovery.
Publish Configuration (Optional)
```bash php artisan vendor:publish --tag=test-login-config ```
Configuration
```php // config/test-login.php return [ // Environments where routes are active (SECURITY CRITICAL) 'environments' => ['local', 'testing'],
// Route prefix (default: /_test)
'prefix' => '_test',
// Middleware (default: web for session support)
'middleware' => ['web'],
// User model (null = auto-detect from auth config)
'user_model' => null,
// Enable API token routes (requires Sanctum)
'api_tokens' => true,
// Clear Spatie permission cache on login
'clear_permissions_cache' => true,
]; ```
Usage
Browser Tests (Behat/Mink)
```php // In your Behat context public function iAmLoggedInAsAdmin(): void { $user = User::factory()->create(); $user->assignRole('admin');
// Visit the login URL
\$this->visit('/_test/login/' . \$user->id);
// Verify login worked
\$response = json_decode(\$this->getSession()->getPage()->getText(), true);
if (\$response['message'] !== 'Logged in successfully') {
throw new \RuntimeException('Login failed');
}
} ```
Gherkin Example
```gherkin Feature: Admin Dashboard Scenario: Admin can access dashboard Given I am logged in as "admin" When I visit "/admin/dashboard" Then I should see "Welcome, Admin" ```
```php /**
-
@Given I am logged in as :role */ public function iAmLoggedInAs(string $role): void { $user = User::factory()->create(); $user->assignRole($role);
$this->visit('/_test/login/' . $user->id); } ```
API Tests
```php // Get an API token $response = Http::get(env('APP_URL') . '/_test/api-login/' . $user->id); $token = $response->json('token');
// Use token in subsequent requests $this->withHeader('Authorization', 'Bearer ' . $token) ->getJson('/api/users') ->assertOk(); ```
PHPUnit Browser Tests
```php public function test_admin_can_access_dashboard(): void { $user = User::factory()->admin()->create();
// Login via test route
\$this->get('/_test/login/' . \$user->id)
->assertOk()
->assertJson(['message' => 'Logged in successfully']);
// Now authenticated
\$this->get('/admin/dashboard')
->assertOk();
} ```
Available Routes
| Route | Method | Description |
|---|---|---|
| `/_test/login/{userId}/{guard?}` | GET | Session-based login |
| `/_test/api-login/{userId}` | GET | Get Sanctum API token |
| `/_test/user/{guard?}` | GET | Get current authenticated user |
| `/_test/logout/{guard?}` | GET | Logout current user |
| `/_test/clear-permissions-cache` | POST | Clear Spatie permission cache |
User Lookup
The `{userId}` parameter accepts:
- Numeric ID: `/_test/login/1`
- Email address: `/_test/login/admin@example.com`
Multiple Guards
Specify a custom guard as the second parameter:
```php // Login to 'admin' guard $this->get('/_test/login/' . $user->id . '/admin');
// Check user on 'api' guard $this->get('/_test/user/api'); ```
Laravel Sail with Local Chrome (Behat/Mink)
When using Laravel Sail for your web server but running Chrome locally on the host (not inside the Docker container), you need a specific architecture:
Architecture Overview
``` ┌─────────────────────────────────────────────────────────────────┐ │ HOST MACHINE │ │ │ │ ┌─────────────────┐ ┌─────────────────────────────┐ │ │ │ Chrome (CDP) │ │ Behat Test Runner │ │ │ │ Port 9222 │◄───────►│ (with environment vars) │ │ │ └─────────────────┘ └──────────────┬──────────────┘ │ │ │ │ │ ┌───────────────────────────────────┘ │ │ │ DB: 127.0.0.1:5432 │ │ │ APP: localhost:8080 │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ Docker (Sail) │ │ │ │ ┌─────────────────┐ ┌─────────────────────────┐ │ │ │ │ │ Laravel App │ │ PostgreSQL │ │ │ │ │ │ Port 8080 │ │ Port 5432 │ │ │ │ │ └─────────────────┘ └─────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────┘ ```
Why This Setup?
- Chrome is NOT installed in the standard Laravel Sail container
- Behat needs direct database access to create test users before browser navigation
- Session cookies must be shared between the test login route and subsequent page visits
Step 1: Start Sail
```bash ./vendor/bin/sail up -d ```
Step 2: Start Chrome on Host
```bash
Linux
chromium-browser --headless --disable-gpu --no-sandbox \ --remote-debugging-port=9222 --disable-dev-shm-usage &
macOS
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome \ --headless --disable-gpu --remote-debugging-port=9222 &
Verify Chrome is running
curl -s http://127.0.0.1:9222/json/version | head -2 ```
Step 3: Run Behat on Host (NOT via Sail)
```bash
Set environment variables to connect to Sail's services
APP_ENV=testing \ APP_URL=http://localhost:8080 \ DB_CONNECTION=pgsql \ DB_HOST=127.0.0.1 \ DB_PORT=5432 \ DB_DATABASE=laravel \ DB_USERNAME=sail \ DB_PASSWORD=password \ CACHE_STORE=array \ SESSION_DRIVER=array \ ./vendor/bin/behat --suite=mink-chrome ```
Helper Script
Create a helper script (`scripts/run-mink-tests.sh`):
```bash #!/bin/bash set -e
Check Sail is running
if ! ./vendor/bin/sail ps 2>/dev/null | grep -q "laravel.test"; then echo "Starting Sail..." ./vendor/bin/sail up -d sleep 5 fi
Start Chrome if not running
if ! curl -s http://127.0.0.1:9222/json/version > /dev/null 2>&1; then echo "Starting Chrome..." chromium-browser --headless --disable-gpu --no-sandbox \ --remote-debugging-port=9222 --disable-dev-shm-usage & sleep 3 fi
Run Behat with environment variables
APP_ENV=testing \ APP_URL=http://localhost:8080 \ DB_CONNECTION=pgsql \ DB_HOST=127.0.0.1 \ DB_PORT=5432 \ DB_DATABASE=laravel \ DB_USERNAME=sail \ DB_PASSWORD=password \ CACHE_STORE=array \ SESSION_DRIVER=array \ ./vendor/bin/behat --suite=mink-chrome "$@" ```
Behat Context Example
```php