Multi-tenant Laravel application dengan API key-based tenant identification. Setiap tenant memiliki database terpisah untuk isolasi data yang sempurna.
- β Database Isolation - Setiap tenant memiliki database terpisah
- β
API Key Authentication - Identifikasi tenant via
X-Tenant-API-Keyheader - β Dynamic Database Configuration - Konfigurasi database per-tenant (host, port, username, password)
- β Encrypted Credentials - Password database dienkripsi menggunakan Laravel encryption
- β Laravel Sanctum - Token-based authentication untuk API
- β Role-Based Access Control - Support role admin/user
- β Tenant Token Validation - Mencegah cross-tenant token usage
- β Custom Error Messages - Pesan error yang informatif
- β Automated Backup - Scheduled daily & weekly backup
- β Manual Backup - Via Artisan command atau REST API
- β Compression Support - Gzip compression untuk menghemat storage
- β Auto Cleanup - Hapus backup lama otomatis
- β Restore Capability - Restore database dari backup
- β Tenant Management API - CRUD tenant via REST API
- β Health Check - Monitor koneksi database tenant
- β Backup Statistics - Monitor status backup semua tenant
βββββββββββββββββββββββ
β Central Database β
β β
β - tenants β
β - domains β
βββββββββββββββββββββββ€
β β
β Tenant Metadata & β
β API Keys Storage β
βββββββββββββββββββββββ
β
β Manages
βΌ
ββββββββββββββββββββββββββββββββββββββββ
β Tenant Databases β
βββββββββββββββ¬ββββββββββββββ¬βββββββββββ€
β Tenant A β Tenant B β Tenant C β
β β β β
β - users β - users β - users β
β - products β - products β - productsβ
β - orders β - orders β - orders β
β - tokens β - tokens β - tokens β
βββββββββββββββ΄ββββββββββββββ΄βββββββββββ
ββββββββββββββββ
β Client β
ββββββββ¬ββββββββ
β X-Tenant-API-Key: tk_abc123...
β Authorization: Bearer token...
βΌ
ββββββββββββββββββββββββββββββββββββββββ
β Middleware: InitializeTenancyByApiKeyβ
β 1. Validasi API Key β
β 2. Find Tenant β
β 3. Initialize Tenancy β
β 4. Set Database Connection β
ββββββββ¬ββββββββββββββββββββββββββββββββ
β
βΌ
ββββββββββββββββββββββββββββββββββββββββ
β Middleware: auth:sanctum β
β 1. Verify Bearer Token β
β 2. Load User dari Tenant Database β
ββββββββ¬ββββββββββββββββββββββββββββββββ
β
βΌ
ββββββββββββββββββββββββββββββββββββββββ
β Middleware: ValidateTenantToken β
β 1. Pastikan token dari tenant yang β
β sama dengan API key β
ββββββββ¬ββββββββββββββββββββββββββββββββ
β
βΌ
ββββββββββββββββββββββββββββββββββββββββ
β Controller Action β
β Data dari Tenant Database β
βββββββββββββββββββββββββββββββββββββββββ
- PHP 8.4+
- Composer
- MySQL 8.0+
- Laravel Herd (atau PHP development server lainnya)
-
Clone Repository
git clone https://github.com/JunedSetiawan/laravel-multi-tenant-try.git cd laravel-multi-tenant-try -
Install Dependencies
composer install
-
Environment Configuration
cp .env.example .env php artisan key:generate
-
Database Configuration (
.env)# Central Database DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=central_db DB_USERNAME=root DB_PASSWORD=root # Tenant Database Template TENANT_DB_HOST=127.0.0.1 TENANT_DB_PORT=3306 TENANT_DB_USERNAME=root TENANT_DB_PASSWORD=root # Master API Key untuk Management MASTER_API_KEY=your-super-secret-master-key # Backup Email Alert (optional) BACKUP_ALERT_EMAIL=admin@example.com
-
Run Migrations
# Migrate central database php artisan migrate # Seed super admin (optional) php artisan db:seed --class=SuperAdminSeeder
-
Start Development Server
# Jika menggunakan Laravel Herd herd link # Atau gunakan artisan serve php artisan serve
Endpoint: POST /api/central/tenants
Headers:
X-Master-API-Key: your-master-key
Accept: application/json
Body:
{
"name": "Warung Makan Bu Joko",
"db_name": "kasir_waroenk",
"db_host": "localhost",
"db_port": 3306,
"db_username": "root",
"db_password": "root"
}Response:
{
"message": "Tenant created successfully",
"data": {
"tenant_id": "warung-makan-bu-joko-abc123",
"name": "Warung Makan Bu Joko",
"api_key": "tk_0123456789abcdef...",
"database": "kasir_waroenk"
},
"warning": "Save the API Key securely! It cannot be retrieved again."
}api_key dengan aman! API key ini digunakan untuk akses tenant.
Base URL: http://localhost/api/central
Required Header: X-Master-API-Key: your-master-key
| Method | Endpoint | Deskripsi |
|---|---|---|
| POST | /tenants |
Create tenant baru |
| GET | /tenants |
List semua tenant |
| GET | /tenants/{id} |
Detail tenant |
| PUT | /tenants/{id} |
Update tenant |
| DELETE | /tenants/{id} |
Delete tenant |
| POST | /tenants/{id}/regenerate-key |
Regenerate API key |
| GET | /tenants/{id}/health |
Health check |
| POST | /tenants/{id}/backup |
Backup database |
| GET | /tenants/{id}/backups |
List backups |
| POST | /tenants/{id}/restore |
Restore database |
Base URL: http://localhost/api
Required Headers:
X-Tenant-API-Key: tk_your_tenant_key
Accept: application/json
| Method | Endpoint | Deskripsi |
|---|---|---|
| POST | /register |
Register user baru |
| POST | /login |
Login user |
| GET | /info |
Info tenant saat ini |
Register Example:
POST /api/register
Headers:
X-Tenant-API-Key: tk_abc123...
Accept: application/json
Body:
{
"name": "John Doe",
"email": "john@example.com",
"username": "johndoe",
"password": "password123",
"password_confirmation": "password123",
"role": "user"
}Login Example:
POST /api/login
Headers:
X-Tenant-API-Key: tk_abc123...
Accept: application/json
Body:
{
"email": "john@example.com",
"password": "password123"
}
Response:
{
"message": "Login successful",
"user": { ... },
"token": "11|abc123xyz..."
}Additional Header: Authorization: Bearer {token}
| Method | Endpoint | Deskripsi |
|---|---|---|
| GET | /me |
Get user profile |
| POST | /logout |
Logout user |
| GET | /products |
List products |
| POST | /products |
Create product |
| GET | /products/{id} |
Show product |
| PUT | /products/{id} |
Update product |
| DELETE | /products/{id} |
Delete product |
| GET | /users |
List users (admin only) |
Example Request:
GET /api/me
Headers:
X-Tenant-API-Key: tk_abc123...
Authorization: Bearer 11|abc123xyz...
Accept: application/jsonβββββββββββ
β Admin β
ββββββ¬βββββ
β
β POST /api/central/tenants
β (name, db_name, db_host, db_username, db_password)
βΌ
ββββββββββββββββββββββββββββββββββββββββ
β Create Tenant in Central DB β
β β
β 1. Save tenant metadata β
β 2. Encrypt db_password β
β 3. Generate & hash API Key β
β 4. Store db config (host, port, β
β username, encrypted password) β
ββββββββββββ¬ββββββββββββββββββββββββββββ
β
β Database tenant (db_name) HARUS SUDAH ADA
β dengan migrations yang sudah di-run
β
β Response: tenant_id, api_key (plaintext)
βΌ
ββββββββββββββββββββββββββββββββββββββββ
β Admin receives API Key β
β β οΈ SAVE API KEY - shown only once! β
β β
β Admin gives API Key to Tenant Owner β
ββββββββββββββββββββββββββββββββββββββββ
β
β Tenant Owner can now use API Key
β to access their database
βΌ
ββββββββββββββββββββββββββββββββββββββββ
β Tenant users can register/login β
β using X-Tenant-API-Key header β
ββββββββββββββββββββββββββββββββββββββββ
- Database dengan nama
db_nameHARUS SUDAH DIBUAT sebelumnya - Migrations HARUS SUDAH DI-RUN di database tenant tersebut
- Sistem TIDAK otomatis membuat database atau run migrations
- Sistem hanya menyimpan konfigurasi koneksi ke database yang sudah ada
ββββββββββββ
β User β
ββββββ¬ββββββ
β
β POST /api/register
β Headers: X-Tenant-API-Key
β Body: name, email, password
βΌ
ββββββββββββββββββββββββ
β Register Process β
β β
β 1. Validate Tenant β
β 2. Create User in β
β Tenant Database β
ββββββββββββ¬ββββββββββββ
β
β Success Response
βΌ
ββββββββββββββββββββββββ
β POST /api/login β
β Body: email, pass β
ββββββββββββ¬ββββββββββββ
β
βΌ
ββββββββββββββββββββββββ
β Login Process β
β β
β 1. Find User β
β 2. Verify Password β
β 3. Generate Token β
β 4. Save to Tenant DBβ
ββββββββββββ¬ββββββββββββ
β
β Response: user, token
βΌ
ββββββββββββββββββββββββ
β User can now access β
β protected resources β
ββββββββββββββββββββββββ
ββββββββββββββββββ
β User Request β
β with Headers β
βββββββββ¬βββββββββ
β
βΌ
βββββββββββββββββββββββ
β Has X-Tenant-API- β NO
β Key header? ββββββΊ Error: API Key Required
βββββββββββ¬ββββββββββββ
β YES
βΌ
βββββββββββββββββββββββ
β Find Tenant by β NO
β API Key ββββββΊ Error: Invalid API Key
βββββββββββ¬ββββββββββββ
β YES
βΌ
βββββββββββββββββββββββ
β Initialize Tenancy β
β - Set DB Connection β
β - Load Tenant Data β
βββββββββββ¬ββββββββββββ
β
βΌ
βββββββββββββββββββββββ
β Has Authorization β NO
β Bearer header? ββββββΊ Error: Unauthenticated
βββββββββββ¬ββββββββββββ
β YES
βΌ
βββββββββββββββββββββββ
β Find Token in β NO
β Tenant Database ββββββΊ Error: Invalid Token
βββββββββββ¬ββββββββββββ
β YES
βΌ
βββββββββββββββββββββββ
β Validate Token β NO
β belongs to Tenant ββββββΊ Error: Token Mismatch
βββββββββββ¬ββββββββββββ
β YES
βΌ
βββββββββββββββββββββββ
β Check Role/ β NO
β Permissions ββββββΊ Error: Forbidden
βββββββββββ¬ββββββββββββ
β YES
βΌ
βββββββββββββββββββββββ
β β
Access Granted β
β Execute Controller β
β Return Response β
βββββββββββββββββββββββ
- Layer 1: Tenant API Key - Identifikasi tenant
- Layer 2: Bearer Token - Autentikasi user
- Layer 3: Token Validation - Validasi token belongs to tenant
- Layer 4: Role-Based Access - Authorization based on role
- Setiap tenant memiliki database terpisah
- Tidak ada data sharing antar tenant
- Token dari Tenant A tidak bisa akses Tenant B
- Password database tenant dienkripsi dengan Laravel encryption
- API key di-hash dengan SHA-256
- User password di-hash dengan bcrypt
Sistem memberikan pesan error yang jelas:
{
"error": "Invalid Tenant API Key",
"message": "The provided API key does not match any tenant...",
"hint": "Make sure you are using the correct API key...",
"provided_key": "tk_abc123..."
}# Backup semua tenant
php artisan tenant:backup --compress
# Backup tenant tertentu
php artisan tenant:backup tenant-id-123 --compress
# Custom retention
php artisan tenant:backup --keep-days=60Backup otomatis sudah dikonfigurasi di app/Console/Kernel.php:
- Daily Backup: Setiap hari jam 02:00 WIB (retention 30 hari)
- Weekly Backup: Setiap Minggu jam 03:00 WIB (retention 90 hari)
Tambahkan cron job:
* * * * * cd /path-to-project && php artisan schedule:run >> /dev/null 2>&1# List semua backups
php artisan tenant:backups
# List backup tenant tertentu
php artisan tenant:backups tenant-id-123# Restore dari backup terbaru
php artisan tenant:restore tenant-id-123
# Restore dari file tertentu
php artisan tenant:restore tenant-id-123 backups/tenant-id/2025/10/backup.sql.gz# Create backup
POST /api/central/tenants/{id}/backup
Headers: X-Master-API-Key: your-key
Body: { "compress": true }
# List backups
GET /api/central/tenants/{id}/backups
# Download backup
GET /api/central/tenants/{id}/backups/download?file=backup.sql.gz
# Restore
POST /api/central/tenants/{id}/restore
Body: { "file": "backup.sql.gz" }# Create tenant
curl -X POST http://localhost/api/central/tenants \
-H "X-Master-API-Key: your-master-key" \
-H "Accept: application/json" \
-d '{"name":"Test Tenant","db_name":"test_db"}'# Register
curl -X POST http://localhost/api/register \
-H "X-Tenant-API-Key: tk_abc123..." \
-H "Accept: application/json" \
-d '{"name":"John","email":"john@test.com","password":"secret"}'
# Login
curl -X POST http://localhost/api/login \
-H "X-Tenant-API-Key: tk_abc123..." \
-H "Accept: application/json" \
-d '{"email":"john@test.com","password":"secret"}'
# Access protected route
curl -X GET http://localhost/api/me \
-H "X-Tenant-API-Key: tk_abc123..." \
-H "Authorization: Bearer 11|token..." \
-H "Accept: application/json"- Simpan tenant API key dengan aman
- Jangan share API key antar tenant
- Regenerate API key jika terjadi kebocoran
- Gunakan database terpisah untuk setiap tenant
- Backup rutin (automated + manual)
- Monitor disk space untuk backup
- Gunakan HTTPS di production
- Rate limiting untuk prevent abuse
- Monitor suspicious activities
- Update dependencies secara berkala
- Health check rutin untuk semua tenant
- Monitor backup status
- Log analysis untuk debug
Contributions are welcome! Please feel free to submit a Pull Request.
This project is open-sourced software licensed under the MIT license.
Juned Setiawan
- GitHub: @JunedSetiawan
Jika ada pertanyaan atau issue, silakan buat GitHub Issue.
Built with β€οΈ using Laravel & Stancl Tenancy