A fully functional Laravel 12-based microservices architecture with JWT authentication, API Gateway, and role-based access control. All CRUD operations and authentication endpoints are working perfectly!
- ✅ Authentication: Register, login, JWT tokens, introspection working
- ✅ CRUD Operations: All user and order operations working
- ✅ API Gateway: Properly routing requests with JWT validation
- ✅ JSON API: Full REST API functionality
- ✅ Form-Data Support: Both JSON and form-data work through gateway
- ✅ JWT Authentication: Complete JWT implementation with bypass for development
- ✅ Role-Based Access: Admin/Moderator/User roles properly enforced
- ✅ Test Suite: Complete end-to-end testing with
test.phpscript - ✅ Clean Architecture: Professional MVC/OOP structure implemented
- ✅ Middleware Chain: All middleware properly configured and working
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Gateway │ │ Users │ │ Orders │
│ Service │ │ Service │ │ Service │
│ Port: 8000 │ │ Port: 8001 │ │ Port: 8002 │
│ │ │ │ │ │
│ • JWT Auth │ │ • Registration │ │ • Order CRUD │
│ • Request Route │ │ • Login │ │ • User Scoped │
│ • Role Control │ │ • JWT Introspect│ │ • Status Mgmt │
│ • Health Check │ │ • User Profile │ │ • Admin Access │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │ │
└───────────────────────┼───────────────────────┘
│
┌─────────────────┐
│ Client │
│ Application │
│ (Frontend) │
└─────────────────┘
- Purpose: API Gateway with JWT validation and request routing
- Features:
- JWT token validation and introspection
- Request routing to microservices
- Role-based access control with
RequireRolemiddleware - Health check monitoring for all services
- Security headers and XSS protection
- User context injection via headers (
X-User-Id,X-User-Email,X-User-Role)
- Purpose: User management and JWT authentication
- Features:
- User registration and login
- JWT token generation and refresh
- JWT token introspection for gateway validation
- User profile management
- Role-based user management (Admin only)
- Password hashing and validation
- TrustGateway middleware for gateway integration
- Purpose: Order management with user-specific access
- Features:
- Order CRUD operations with proper validation
- User-specific order filtering via
X-User-Idheader - Order status management
- Role-based access (Moderator/Admin can manage all orders)
- TrustGateway middleware for gateway integration
- Professional service/repository architecture
- user: Basic user with access to own orders
- moderator: Can manage order statuses and view all orders
- admin: Full access to user and order management
- superadmin: Highest level access (same as admin for now)
- PHP 8.2+
- Composer
- SQLite (or MySQL/PostgreSQL)
- Firebase JWT library (automatically installed)
# Navigate to each service directory and install dependencies
cd gateway-service
composer install
composer require firebase/php-jwt
cd ../users-service
composer install
composer require firebase/php-jwt
cd ../orders-service
composer install
composer require firebase/php-jwtEach service needs its own .env file. The services use local_env files for configuration:
# For each service - copy local_env to .env
cp local_env .env
php artisan key:generateRequired Environment Variables:
Gateway Service (.env):
JWT_SECRET=your-secret-key-change-this-in-production
AUTH_SERVICE_URL=http://127.0.0.1:8001
# Gateway Configuration
GATEWAY_MODE=bypass
GATEWAY_BYPASS_ROLE=adminUsers Service (.env):
JWT_SECRET=your-secret-key-change-this-in-productionOrders Service (.env):
JWT_SECRET=your-secret-key-change-this-in-productionNote: All services must use the same JWT_SECRET for proper token validation.
# For users-service
cd users-service
php artisan migrate
# For orders-service
cd ../orders-service
php artisan migrateSet the same JWT secret in all services' .env files:
JWT_SECRET=your-super-secret-jwt-key-change-this-in-production# Start all services at once
start-all.batOpen three terminal windows and run each service:
# Terminal 1 - Gateway Service
cd gateway-service
php artisan serve --port=8000
# Terminal 2 - Users Service
cd users-service
php artisan serve --port=8001
# Terminal 3 - Orders Service
cd orders-service
php artisan serve --port=8002POST /api/auth/register
Content-Type: application/json
{
"name": "John Doe",
"email": "[email protected]",
"password": "password123",
"password_confirmation": "password123",
"role": "user"
}Alternative: Form-Data (Also Supported)
POST /api/auth/register
Content-Type: multipart/form-data
name: John Doe
email: [email protected]
password: password123
password_confirmation: password123
role: userPOST /api/auth/login
Content-Type: application/json
{
"email": "[email protected]",
"password": "password123"
}Alternative: Form-Data (Also Supported)
POST /api/auth/login
Content-Type: multipart/form-data
email: [email protected]
password: password123POST /api/auth/refresh
Authorization: Bearer <token>POST /api/auth/logout
Authorization: Bearer <token>GET /api/users/profile
Authorization: Bearer <token>PUT /api/users/profile
Authorization: Bearer <token>
Content-Type: application/json
{
"name": "John Updated",
"current_password": "password123",
"password": "newpassword123",
"password_confirmation": "newpassword123"
}GET /api/users
Authorization: Bearer <admin_token>PUT /api/users/{id}
Authorization: Bearer <admin_token>
Content-Type: application/json
{
"name": "Updated Name",
"role": "moderator",
"is_active": true
}GET /api/orders
Authorization: Bearer <token>POST /api/orders
Authorization: Bearer <token>
Content-Type: application/json
{
"total_amount": 99.99,
"currency": "USD",
"shipping_address": {
"name": "John Doe",
"street": "123 Main St",
"city": "New York",
"state": "NY",
"postal_code": "10001",
"country": "USA"
},
"notes": "Please deliver after 5 PM"
}GET /api/orders/{id}
Authorization: Bearer <token>PUT /api/orders/{id}
Authorization: Bearer <token>
Content-Type: application/json
{
"status": "processing",
"notes": "Updated notes"
}DELETE /api/orders/{id}
Authorization: Bearer <token>PUT /api/orders/{id}/status
Authorization: Bearer <moderator_token>
Content-Type: application/json
{
"status": "shipped"
}GET /api/orders/admin/all
Authorization: Bearer <moderator_token>GET /api/health- Secure token-based authentication
- Token expiration and refresh mechanism
- Role-based access control
- Comprehensive request validation
- SQL injection prevention through Eloquent ORM
- XSS protection through input sanitization
- X-Content-Type-Options: nosniff
- X-Frame-Options: DENY
- X-XSS-Protection: 1; mode=block
- Referrer-Policy: strict-origin-when-cross-origin
- Content-Security-Policy: default-src 'self'
- User roles: user, moderator, admin, superadmin
- Endpoint-level permission checks
- Resource ownership validation
- JWT Library Missing: Installed
firebase/php-jwtin all services - Middleware User Resolution: Fixed
TrustGatewaymiddleware to properly set user objects using$request->setUserResolver() - Controller User Access: Updated controllers to use
$request->user()instead of$request->user - Gateway Data Forwarding: Fixed gateway to properly forward both JSON and form-data
- Password Hashing: Removed double-hashing in AuthController (Laravel 11's
hashedcast handles it) - User Model Fields: Added
is_activefield to the orders-service User model - Form-Data Support: Gateway now properly forwards form-data by converting it to JSON
- Missing Middleware: Created and registered
RequireRolemiddleware in gateway service - Missing Introspect Endpoint: Added
/api/introspectendpoint to users service for gateway JWT validation - Environment Variables: Added missing
AUTH_SERVICE_URLandJWT_SECRETto gateway and users services - Middleware Cleanup: Removed unused middleware files (
DevJwtBypass,JwtMiddleware,SecurityMiddleware,JwtControl) - Route Configuration: Updated all services to use correct middleware aliases (
gateway.auth,trust.gateway,require.role) - User Resolution Fix: Fixed
TrustGatewaymiddleware to fetch actual User model from database instead of mock object - Test Script Updates: Updated test script to use correct endpoints (
/api/users/profileinstead of/api/users) - Gateway Bypass Mode: Implemented proper bypass mode with
GATEWAY_MODE=bypassconfiguration - Bypass User Creation: Fixed "User not found" error by implementing automatic user creation in bypass mode
- Middleware Registration: Fixed missing
require.rolemiddleware registration in gateway service - Environment File Setup: Created proper
.envfile configuration for all services
- Authentication: Register, login, JWT tokens, refresh, logout, introspect
- User Management: Profile management, admin user operations
- Order Management: Full CRUD operations, status updates, admin operations
- API Gateway: Proper request routing and data forwarding with JWT validation
- Multiple Formats: Both JSON and form-data supported
- Gateway Bypass Mode: Development mode with automatic user creation and admin privileges
- Production Mode: Full JWT authentication with role-based access control
- Test Suite: Complete end-to-end testing with
test.phpscript - Clean Architecture: Professional MVC/OOP structure with service and repository layers
- Middleware Chain: Complete middleware implementation with proper user resolution
The system includes a powerful bypass mode for local development that eliminates the need for JWT authentication while maintaining full functionality.
Add these variables to your gateway-service/.env file:
# Gateway Configuration
GATEWAY_MODE=bypass
GATEWAY_BYPASS_ROLE=adminThe system automatically detects the mode. You can verify it by running:
php test.phpLook for: Gateway mode: bypass or Gateway mode: introspect
- Gateway Level: When
GATEWAY_MODE=bypass, the gateway skips JWT validation - User Creation: The system automatically creates/finds a bypass user (
[email protected]) - Role Assignment: Uses the role specified in
GATEWAY_BYPASS_ROLE(default:admin) - Seamless Operation: All CRUD operations work without authentication tokens
| Feature | Bypass Mode | Normal Mode |
|---|---|---|
| Authentication | ❌ Not Required | ✅ JWT Required |
| User Creation | 🔄 Auto-created | 👤 Real users |
| Role Access | 🔓 Admin by default | 🔐 Based on JWT claims |
| Development | 🚀 Perfect for testing | 🏭 Production ready |
Run the repository root script to verify auth + CRUD via the gateway. It adapts to bypass vs introspect automatically.
php test.phpExpected Output (Bypass Mode):
Gateway mode: bypass
=== Health ===
[OK] gateway /api/health (200)
[OK] users-service /up (200)
[OK] orders-service /up (200)
=== Register ===
[OK] users-service register (201)
=== Login ===
[OK] users-service login (200)
=== Current user via gateway ===
[OK] GET /api/users/profile (200)
=== User profile update via gateway ===
[OK] PUT /api/users/profile (200)
=== Orders CRUD via gateway ===
[OK] POST /api/orders (201)
[OK] GET /api/orders (200)
[OK] GET /api/orders/{id} (200)
[OK] PUT /api/orders/{id} (200)
[OK] DELETE /api/orders/{id} (200)
=== Logout (optional) ===
All checks passed ✅
Expected Output (Normal Mode):
Gateway mode: introspect
=== Health ===
[OK] gateway /api/health (200)
[OK] users-service /up (200)
[OK] orders-service /up (200)
=== Register ===
[OK] users-service register (201)
=== Login ===
[OK] users-service login (200)
=== Current user via gateway ===
[OK] GET /api/users/profile (200)
=== User profile update via gateway ===
[OK] PUT /api/users/profile (200)
=== Orders CRUD via gateway ===
[OK] POST /api/orders (201)
[OK] GET /api/orders (200)
[OK] GET /api/orders/{id} (200)
[OK] PUT /api/orders/{id} (200)
[OK] DELETE /api/orders/{id} (200)
=== Logout (optional) ===
All checks passed ✅
What it does:
- Health checks for all services
- Registers a user and logs in (if not bypass)
- Through the gateway: current user profile; user profile update; full orders CRUD
- Attempts logout (ignored if not present)
# Get user profile (no token required in bypass mode)
curl http://localhost:8000/api/users/profile
# Create an order (no token required in bypass mode)
curl -X POST http://localhost:8000/api/orders \
-H "Content-Type: application/json" \
-d '{
"total_amount": 99.99,
"shipping_address": {
"name": "Dev User",
"street": "123 Dev St",
"city": "Dev City",
"state": "DV",
"postal_code": "12345",
"country": "USA"
}
}'
# Access admin endpoints (no token required in bypass mode)
curl http://localhost:8000/api/users
curl http://localhost:8000/api/orders/admin/all# These will return 401 Unauthorized without valid JWT token
curl http://localhost:8000/api/users/profile # Returns 401
curl http://localhost:8000/api/orders # Returns 401
# With valid JWT token (after login)
curl -H "Authorization: Bearer YOUR_JWT_TOKEN" http://localhost:8000/api/users/profilecurl -X POST http://localhost:8000/api/auth/register \
-H "Content-Type: application/json" \
-d '{
"name": "Test User",
"email": "[email protected]",
"password": "password123",
"password_confirmation": "password123"
}'curl -X POST http://localhost:8000/api/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected]",
"password": "password123"
}'curl -X POST http://localhost:8000/api/orders \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_TOKEN_HERE" \
-d '{
"total_amount": 99.99,
"shipping_address": {
"name": "Test User",
"street": "123 Test St",
"city": "Test City",
"state": "TS",
"postal_code": "12345",
"country": "USA"
}
}'curl http://localhost:8000/api/health- Method: POST
- URL:
http://localhost:8000/api/auth/register - Headers:
Content-Type: application/jsonAccept: application/json
- Body: Select "raw" → "JSON"
- JSON Body:
{
"name": "Test User",
"email": "[email protected]",
"password": "password123",
"password_confirmation": "password123"
}- Method: POST
- URL:
http://localhost:8000/api/auth/register - Headers:
Accept: application/json
- Body: Select "form-data"
- Form Fields:
name: Test Useremail: [email protected]password: password123password_confirmation: password123
The gateway bypass mode is controlled by the GATEWAY_MODE environment variable in the gateway service:
-
Gateway Level:
- When
GATEWAY_MODE=bypass, theGatewayAuthmiddleware skips JWT validation - Sets
X-Bypass-Mode: trueheader for downstream services - Sets
X-User-EmailandX-User-Roleheaders
- When
-
Users Service:
TrustGatewaymiddleware detects bypass mode- Automatically creates/finds user by email (
[email protected]) - Sets proper user object for
$request->user()
-
Orders Service:
TrustGatewaymiddleware detects bypass mode- Creates mock user object with admin privileges
- Allows all CRUD operations without authentication
# Gateway Service (.env)
GATEWAY_MODE=bypass # Enable bypass mode
GATEWAY_BYPASS_ROLE=admin # Role for bypass user (admin, user, moderator)- Enable Bypass: Set
GATEWAY_MODE=bypassin gateway service - Disable Bypass: Set
GATEWAY_MODE=introspectin gateway service - Restart Required: Restart gateway service after changing mode
- Users service uses SQLite for user management
- Orders service uses SQLite for order storage
- Each service maintains its own database
- Services communicate through HTTP requests
- Gateway service routes requests to appropriate microservices
- JWT tokens are validated at the gateway level (unless bypassed in dev mode)
- Comprehensive error responses with appropriate HTTP status codes
- Detailed validation error messages
- Logging for debugging and monitoring
-
Security:
- Change default JWT secrets
- Use HTTPS in production
- Implement rate limiting
- Add request logging and monitoring
-
Database:
- Use production-grade databases (MySQL/PostgreSQL)
- Implement database backups
- Add database connection pooling
-
Deployment:
- Use containerization (Docker)
- Implement load balancing
- Add health checks and monitoring
- Use environment-specific configurations
-
Performance:
- Implement caching (Redis)
- Add database indexing
- Optimize database queries
- Implement API response caching
Your microservices system supports multiple ways to control JWT authentication between development and production modes. This guide explains all the methods available.
# Run the interactive control script
jwt-control.batOptions:
- Development Mode - Enables JWT bypass with admin mock user
- Production Mode - Requires full JWT authentication
- Custom Mock User - Configure custom mock user settings
- Check Settings - View current configuration
# In each service's .env file
APP_ENV=local
APP_DEBUG=true
JWT_BYPASS=true
JWT_MOCK_USER_ROLE=admin# In each service's .env file
APP_ENV=production
APP_DEBUG=false
JWT_BYPASS=false# Custom mock user configuration
JWT_MOCK_USER_ID=1
JWT_MOCK_USER_NAME=Test User
JWT_MOCK_USER_EMAIL=[email protected]
JWT_MOCK_USER_ROLE=moderatorThe system checks JWT bypass in this order:
-
Environment-based (current system)
if (config('app.env') === 'local' && config('app.debug') === true)
-
Explicit bypass setting
if (config('jwt.bypass_enabled', false))
-
Force bypass via environment
if (env('JWT_BYPASS', false))
# Option 1: Use control script
jwt-control.bat
# Option 2: Manual .env update
echo APP_ENV=local > .env
echo APP_DEBUG=true >> .env
echo JWT_BYPASS=true >> .env# Option 1: Use control script
jwt-control.bat
# Option 2: Manual .env update
echo APP_ENV=production > .env
echo APP_DEBUG=false >> .env
echo JWT_BYPASS=false >> .envreturn [
'secret' => env('JWT_SECRET', 'your-secret-key'),
'algo' => 'HS256',
'expire' => 3600,
'refresh_expire' => 86400,
// JWT Bypass Control
'bypass_enabled' => env('JWT_BYPASS', false),
// Mock User Configuration
'mock_user' => [
'id' => env('JWT_MOCK_USER_ID', 1),
'name' => env('JWT_MOCK_USER_NAME', 'Dev User'),
'email' => env('JWT_MOCK_USER_EMAIL', '[email protected]'),
'role' => env('JWT_MOCK_USER_ROLE', 'admin'),
],
];| Variable | Description | Default | Example |
|---|---|---|---|
APP_ENV |
Application environment | local |
local, production |
APP_DEBUG |
Debug mode | true |
true, false |
JWT_BYPASS |
Force JWT bypass | false |
true, false |
JWT_MOCK_USER_ID |
Mock user ID | 1 |
1, 2, 3 |
JWT_MOCK_USER_NAME |
Mock user name | Dev User |
Test User |
JWT_MOCK_USER_EMAIL |
Mock user email | [email protected] |
[email protected] |
JWT_MOCK_USER_ROLE |
Mock user role | admin |
user, moderator, admin, superadmin |
# These should work without authentication
curl http://localhost:8000/api/users/profile
curl http://localhost:8000/api/orders
curl http://localhost:8000/api/users # Admin endpoint# These should require authentication
curl http://localhost:8000/api/users/profile # Returns 401
curl http://localhost:8000/api/orders # Returns 401
# With valid token
curl -H "Authorization: Bearer YOUR_TOKEN" http://localhost:8000/api/users/profile- Run
jwt-control.bat - Choose option 1 (Development Mode)
- Run
jwt-control.bat - Choose option 2 (Production Mode)
- Run
jwt-control.bat - Choose option 3 (Custom Mock User)
- Configure your test user
- ✅ JWT bypass enabled
- ✅ Mock user with admin privileges
- ✅ No authentication required
- ⚠� Only use in local development
- ✅ Full JWT authentication required
- ✅ All security measures active
- ✅ Role-based access control enforced
- ✅ No bypass available
-
Check environment variables:
jwt-control.bat # Choose option 4 -
Verify .env files:
# Should contain: APP_ENV=local APP_DEBUG=true JWT_BYPASS=true -
Restart services after changes
- Ensure JWT_BYPASS=false
- Check APP_ENV=production
- Verify JWT_SECRET is set
- Test with valid JWT token
- Check mock user configuration
- Verify role permissions
- Development: Always use JWT bypass for local development
- Testing: Use custom mock users for specific test scenarios
- Production: Never enable JWT bypass in production
- Security: Regularly rotate JWT secrets
- Monitoring: Log authentication attempts and failures
| Mode | APP_ENV | APP_DEBUG | JWT_BYPASS | Authentication |
|---|---|---|---|---|
| Development | local |
true |
true |
Bypassed |
| Production | production |
false |
false |
Required |
| Custom | local |
true |
true |
Bypassed (custom user) |
jwt-control.bat- Interactive control scriptconfig/jwt.php- JWT configurationapp/Http/Middleware/DevJwtBypass.php- Bypass middlewareapp/Http/Middleware/JwtControl.php- Advanced control middleware