This document explains how to properly set up Laravel Passport in this project and resolve migration conflicts that occur during Docker builds.
When installing Laravel Passport, the following migration conflict occurs:
SQLSTATE[HY000]: General error: 1 table "oauth_auth_codes" already exists
This happens because:
- Existing Migrations: The project already contains Passport migration files (dated 2025-07-28)
- Duplicate Publishing: When
php artisan passport:installruns, it publishes new migration files with newer timestamps - Table Conflict: The new migrations try to create tables that already exist from the previous migrations
We've implemented a custom approach to handle Passport migrations:
- Existing Migrations: Keep the current migration files (2025_07_28_100934 to 2025_07_28_100938)
- Prevent Duplicates: Use scripts to detect and prevent duplicate migration publishing
- Smart Setup: Use conditional logic to only run migrations when tables don't exist
This script handles the complete Passport setup:
# Run the setup script
./scripts/setup-passport.shWhat it does:
- ✅ Creates necessary storage directories
- ✅ Checks for existing migrations before publishing
- ✅ Runs migrations only if tables don't exist
- ✅ Generates encryption keys safely
- ✅ Creates OAuth clients with error handling
- ✅ Works both inside Docker and on host system
This script specifically handles migration conflicts:
# Fix migration conflicts
./scripts/fix-passport-migrations.shWhat it does:
- 🔧 Removes duplicate migration files
- 📁 Preserves existing migrations
- 🔐 Sets up oauth-keys directory
- 💡 Provides next steps guidance
The AppServiceProvider is configured to:
public function boot(): void
{
// Configure Passport to use custom key storage location
Passport::loadKeysFrom(storage_path('oauth-keys'));
// Set custom token expiration times
Passport::tokensExpireIn(now()->addDays(15));
Passport::refreshTokensExpireIn(now()->addDays(30));
Passport::personalAccessTokensExpireIn(now()->addMonths(6));
}The following entries have been added to .gitignore:
# OAuth Keys
/storage/oauth-keys/
oauth-*.key
This prevents committing sensitive encryption keys to version control.
The Passport setup is now integrated into the project's build process:
# For development environment (includes Passport setup)
make setup
# For production environment (includes Passport setup)
make setup-prod
#### Manual Passport setup only
make passport-setupThe setup script is automatically used in:
- GitHub Actions CI: Replaces
php artisan passport:install --force - Development Setup: Integrated into
make setup - Production Deployment: Integrated into
make setup-prod
This ensures consistent, conflict-free Passport installation across all environments.
-
Build containers (if not already built):
docker-compose -f compose.dev.yaml up -d
-
Run the setup script:
docker-compose -f compose.dev.yaml exec workspace ./scripts/setup-passport.sh -
Verify setup:
docker-compose -f compose.dev.yaml exec workspace php artisan passport:client --list
-
Run the setup script:
./scripts/setup-passport.sh
-
Verify setup:
php artisan passport:client --list
Symptoms:
table "oauth_auth_codes" already existserror- Docker build fails during migration step
Solution:
# Clean up and restart
docker-compose -f compose.dev.yaml down -v
./scripts/fix-passport-migrations.sh
docker-compose -f compose.dev.yaml up -d
./scripts/setup-passport.shSymptoms:
- "Encryption key not found" errors
- OAuth endpoints return 500 errors
Solution:
# Regenerate keys
docker-compose -f compose.dev.yaml exec workspace php artisan passport:keys --forceSymptoms:
- "Client not found" errors
- Unable to generate tokens
Solution:
# Create clients manually
docker-compose -f compose.dev.yaml exec workspace php artisan passport:client --personal
docker-compose -f compose.dev.yaml exec workspace php artisan passport:client --password- Never commit encryption keys - They're automatically ignored by
.gitignore - Use the setup scripts - They handle edge cases and conflicts
- Test OAuth endpoints - Verify setup with actual API calls
- Monitor token expiration - Adjust expiration times in
AppServiceProvideras needed - Backup client secrets - Store OAuth client secrets securely
After successful setup, the following OAuth endpoints will be available:
POST /oauth/token- Get access tokenGET /oauth/authorize- Authorization endpointPOST /oauth/token/refresh- Refresh tokenDELETE /oauth/tokens/{token-id}- Revoke token
For SPA applications, consider using Laravel Sanctum instead of Passport for simpler token-based authentication. Passport is ideal for:
- Third-party API access
- OAuth2 server implementation
- Complex authentication flows
- Mobile app authentication
Note: This setup ensures that Passport works reliably in both development and production environments without migration conflicts.