First Commit

This commit is contained in:
2026-05-31 10:17:09 +07:00
commit 17a9c69379
4547 changed files with 1170384 additions and 0 deletions
+322
View File
@@ -0,0 +1,322 @@
# JWT API Authentication for Odoo 19
Modul `grt_jwt_token` menyediakan autentikasi JWT untuk aplikasi eksternal yang ingin mengakses endpoint API Odoo dengan pola:
1. Aplikasi eksternal mengirim `client_id` dan `client_secret`.
2. Odoo memvalidasi API Client.
3. Odoo mengembalikan JWT access token.
4. Aplikasi eksternal memakai token tersebut sebagai `Authorization: Bearer <token>` untuk mengakses endpoint API yang dilindungi.
Modul ini cocok untuk integrasi API dan SSO berbasis token antar aplikasi. Untuk login otomatis ke UI web Odoo, masih diperlukan flow tambahan yang membuat Odoo session secara eksplisit.
## Fitur
- Menu aplikasi utama: **JWT Auth**.
- Model konfigurasi API Client.
- Generate `client_id` otomatis.
- Generate dan rotasi `client_secret`.
- Penyimpanan secret sebagai hash PBKDF2, bukan plaintext.
- Token JWT dengan claim `iss`, `aud`, `exp`, `iat`, `jti`, `sub`, dan `client_id`.
- Decorator `@check_jwt_auth` untuk melindungi controller custom.
- Contoh endpoint protected: `/api/ifc/projects`.
## Struktur Modul
```text
grt_jwt_token/
+-- __manifest__.py
+-- __init__.py
+-- README.md
+-- controllers/
| +-- __init__.py
| +-- main.py
+-- models/
| +-- __init__.py
| +-- api_client.py
+-- security/
| +-- ir.model.access.csv
+-- static/
| +-- description/
| | +-- icon.png
| | +-- icon_128.png
| +-- src/img/
| +-- jwt_auth_icon.png
+-- views/
+-- api_client_views.xml
```
## Konfigurasi Odoo
Tambahkan `jwt_secret` di file `odoo.conf`.
```ini
[options]
jwt_secret = ganti_dengan_secret_panjang_minimal_32_karakter
```
Ketentuan:
- Minimal 32 karakter.
- Jangan pakai secret contoh di production.
- Simpan secret hanya di server.
- Setelah mengubah `odoo.conf`, restart Odoo.
Contoh konfigurasi lokal:
```ini
db_name = odoo19
http_port = 8071
jwt_secret = W2V8bVN38YJZJQhcew8Fcgw6vG5Ab79hbRzD3SpjJvGQxNPvKcNFQ8syb6h9PqRr
```
## Instalasi
1. Pastikan folder `grt_jwt_token` berada di `addons_path`.
2. Restart Odoo.
3. Buka **Apps**.
4. Update Apps List jika modul belum muncul.
5. Install **JWT API Authentication**.
Atau lewat CLI:
```powershell
$env:PYTHONPATH='C:\odoo19\server'
.\.venv\Scripts\python.exe C:\odoo19\server\odoo-bin -c .\odoo.conf -d odoo19 -i grt_jwt_token --stop-after-init
```
Untuk update modul:
```powershell
$env:PYTHONPATH='C:\odoo19\server'
.\.venv\Scripts\python.exe C:\odoo19\server\odoo-bin -c .\odoo.conf -d odoo19 -u grt_jwt_token --stop-after-init
```
## Membuat API Client
1. Login sebagai Administrator.
2. Buka app **JWT Auth**.
3. Buat record baru.
4. Isi:
- **Application Name**: nama aplikasi eksternal.
- **Odoo User**: user Odoo yang akan dipakai ketika token digunakan.
- **Token Lifetime (seconds)**: masa berlaku token, default `7200`.
5. Simpan.
6. Salin `Client ID` dan `New Client Secret`.
Penting: `client_secret` hanya ditampilkan saat dibuat atau setelah tombol **Regenerate Secret** ditekan. Setelah halaman ditutup, secret tidak bisa dilihat lagi karena database hanya menyimpan hash.
## Endpoint Token
URL:
```text
POST /api/auth/token
```
Content-Type:
```text
application/json
```
Body:
```json
{
"client_id": "CLIENT_ID_ANDA",
"client_secret": "CLIENT_SECRET_ANDA"
}
```
`secret_key` juga diterima sebagai alias dari `client_secret` untuk kompatibilitas integrasi.
Response sukses:
```json
{
"access_token": "JWT_TOKEN",
"expires_in": 7200,
"token_type": "Bearer"
}
```
Response gagal:
```json
{
"error": "Invalid credentials."
}
```
## Contoh Request Token
PowerShell:
```powershell
$body = @{
client_id = "CLIENT_ID_ANDA"
client_secret = "CLIENT_SECRET_ANDA"
} | ConvertTo-Json
Invoke-RestMethod `
-Uri "http://localhost:8071/api/auth/token" `
-Method Post `
-Body $body `
-ContentType "application/json"
```
cURL:
```bash
curl -X POST http://localhost:8071/api/auth/token \
-H "Content-Type: application/json" \
-d '{"client_id":"CLIENT_ID_ANDA","client_secret":"CLIENT_SECRET_ANDA"}'
```
## Mengakses Endpoint Protected
Contoh endpoint:
```text
GET /api/ifc/projects
```
Header:
```text
Authorization: Bearer JWT_TOKEN
```
PowerShell:
```powershell
$headers = @{
Authorization = "Bearer JWT_TOKEN"
}
Invoke-RestMethod `
-Uri "http://localhost:8071/api/ifc/projects" `
-Method Get `
-Headers $headers
```
cURL:
```bash
curl http://localhost:8071/api/ifc/projects \
-H "Authorization: Bearer JWT_TOKEN"
```
Response contoh:
```json
{
"message": "JWT token is valid.",
"user_id": 2,
"user_name": "Administrator",
"client_id": "CLIENT_ID_ANDA",
"data": [
"Proyek_IFC_Gedung_A",
"Proyek_IFC_Infrastruktur_B"
]
}
```
## Melindungi Controller Custom
Import decorator dari controller modul:
```python
from odoo import http
from odoo.http import request
from odoo.addons.grt_jwt_token.controllers.main import check_jwt_auth, json_response
class MyApiController(http.Controller):
@http.route('/api/my/resource', type='http', auth='public', methods=['GET'], csrf=False)
@check_jwt_auth
def my_resource(self, **kwargs):
return json_response({
'user_id': request.env.user.id,
'user_name': request.env.user.name,
})
```
Saat token valid, decorator akan:
- Decode dan validasi JWT.
- Memastikan client masih aktif.
- Memastikan user Odoo masih aktif.
- Mengisi `request.jwt_payload`.
- Mengisi `request.jwt_client`.
- Mengisi `request.jwt_user_id`.
- Menjalankan `request.update_env(user=user_id)`.
## Claim JWT
Token berisi claim berikut:
| Claim | Isi |
| --- | --- |
| `iss` | Issuer, default `odoo` |
| `aud` | Audience, default `odoo-api` |
| `exp` | Waktu kedaluwarsa token |
| `iat` | Waktu token diterbitkan |
| `jti` | ID unik token |
| `sub` | ID user Odoo dalam format string |
| `client_id` | Client ID API Client |
## Keamanan
Rekomendasi production:
- Gunakan HTTPS.
- Gunakan `jwt_secret` yang panjang dan random.
- Jangan commit `jwt_secret` production ke repository.
- Buat satu API Client per aplikasi eksternal.
- Mapping API Client ke user Odoo dengan hak akses minimum.
- Rotasi secret secara berkala dengan tombol **Regenerate Secret**.
- Nonaktifkan API Client yang tidak digunakan.
- Batasi masa berlaku token sesuai kebutuhan.
- Tambahkan rate limiting di reverse proxy jika endpoint dibuka ke internet.
## Troubleshooting
### Error: JWT secret is not configured
Penyebab:
- `jwt_secret` belum ada di `odoo.conf`.
- Panjang `jwt_secret` kurang dari 32 karakter.
- Odoo belum direstart setelah config diubah.
Solusi:
1. Tambahkan `jwt_secret` yang valid.
2. Restart Odoo.
### Error: Invalid credentials
Penyebab:
- `client_id` salah.
- `client_secret` salah.
- API Client tidak aktif.
- User Odoo yang dipetakan tidak aktif.
### Error: Token has expired
Token melewati `Token Lifetime (seconds)`. Minta token baru melalui `/api/auth/token`.
### Menu JWT Auth belum muncul
Jika modul sudah ter-install tapi menu belum terlihat:
1. Logout.
2. Hapus local storage browser untuk `webclient_menus` dan `webclient_menus_version`.
3. Login ulang atau pakai private/incognito window.
## Catatan Batasan
Modul ini belum membuat session login web Odoo otomatis. Token JWT dipakai untuk akses endpoint API yang memakai `@check_jwt_auth`. Jika membutuhkan SSO penuh ke UI Odoo, perlu tambahan flow session seperti OAuth/OIDC callback atau endpoint login session yang divalidasi dengan signature.