323 lines
7.3 KiB
Markdown
323 lines
7.3 KiB
Markdown
# 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.
|