Difference between revisions of "Mengamankan API dengan Tokenisasi"

From OnnoWiki
Jump to navigation Jump to search
 
(4 intermediate revisions by the same user not shown)
Line 1: Line 1:
# Modul 3.3: Mengamankan API dengan Tokenisasi
+
==Tujuan Pembelajaran==
 +
* Memahami konsep '''tokenisasi''' dalam keamanan API.
 +
* Membangun API sederhana menggunakan '''Flask'''.
 +
* Mengamankan endpoint dengan '''Token (Bearer Token / API Key)'''.
 +
* Mengakses API menggunakan tools seperti '''Postman''' atau `curl`.
  
## Pendahuluan
 
  
Dalam pengembangan aplikasi web, keamanan komunikasi antara klien dan server menjadi aspek krusial. Salah satu metode yang umum digunakan untuk mengamankan komunikasi tersebut adalah melalui **tokenisasi**, khususnya dengan implementasi **JSON Web Tokens (JWT)**. JWT memungkinkan autentikasi dan otorisasi yang aman tanpa perlu menyimpan status sesi di server, menjadikannya pilihan populer dalam pengembangan API modern.
+
==Persiapan Lingkungan==
  
## Apa Itu JSON Web Token (JWT)?
+
'''1. Instalasi Flask'''
  
**JSON Web Token (JWT)** adalah standar terbuka (RFC 7519) yang mendefinisikan cara aman untuk mentransmisikan informasi antara pihak-pihak sebagai objek JSON. Informasi ini dapat diverifikasi dan dipercaya karena ditandatangani secara digital. JWT terdiri dari tiga bagian utama:
+
pip install flask
  
1. **Header**: Berisi tipe token dan algoritma yang digunakan, seperti HMAC SHA256 atau RSA.
 
2. **Payload**: Berisi klaim atau pernyataan tentang entitas (biasanya pengguna) dan data tambahan lainnya.
 
3. **Signature**: Digunakan untuk memverifikasi bahwa pesan tidak diubah selama transmisi.
 
  
Struktur JWT secara umum adalah sebagai berikut:
+
==Bagian 1: API Tanpa Keamanan (Public)==
  
```
+
'''`app.py`'''
  
Header.Payload.Signature
+
from flask import Flask, jsonify, request
```
+
+
app = Flask(__name__)
 +
 +
@app.route('/public', methods=['GET'])
 +
def public_api():
 +
    return jsonify({"message": "Ini endpoint publik, semua orang bisa akses."})
 +
 +
if __name__ == '__main__':
 +
    app.run(debug=True)
  
Setiap bagian dienkode dalam Base64URL dan dipisahkan oleh titik.
+
'''Akses:'''
  
## Instalasi Flask dan Flask-JWT-Extended di Ubuntu 24.04
+
curl http://localhost:5000/public
  
Sebelum memulai implementasi, pastikan Anda telah menginstal Python 3 dan pip. Berikut langkah-langkah instalasi Flask dan Flask-JWT-Extended:
+
==Bagian 2: API dengan Tokenisasi (Private)==
 +
 
 +
'''Tambahkan Endpoint dengan Token:'''
 +
 
 +
API_TOKEN = "rahasiabanget123"  # Token disimpan secara hardcoded untuk contoh
 +
 +
@app.route('/private', methods=['GET'])
 +
def private_api():
 +
    token = request.headers.get('Authorization')
 +
 +
    if not token or token != f"Bearer {API_TOKEN}":
 +
        return jsonify({"error": "Unauthorized"}), 401
 +
 +
    return jsonify({"message": "Ini endpoint privat, hanya bisa diakses dengan token valid."})
 +
 
 +
> 💡 '''Header format''' yang digunakan adalah:
  
1. **Perbarui daftar paket dan instal dependensi yang diperlukan:**
+
Authorization: Bearer rahasiabanget123
  
  ```bash
+
'''Contoh Akses dengan `curl`:'''
  sudo apt update
 
  sudo apt install python3 python3-pip python3-venv -y
 
  ```
 
 
  
2. **Buat direktori proyek dan navigasikan ke dalamnya:**
+
curl -H "Authorization: Bearer rahasiabanget123" http://localhost:5000/private
  
  ```bash
 
  mkdir flask_jwt_api
 
  cd flask_jwt_api
 
  ```
 
 
  
3. **Buat dan aktifkan virtual environment:**
+
==Uji dengan Postman==
  
  ```bash
+
* Jalankan server `python app.py`.
  python3 -m venv venv
+
* Buka Postman:
  source venv/bin/activate
+
** Method: `GET`
  ```
+
** URL: `http://localhost:5000/private`
+
** Header:
 +
*** Key: `Authorization`
 +
*** Value: `Bearer rahasiabanget123`
 +
* Klik '''Send''' untuk melihat hasil.
  
4. **Instal Flask dan Flask-JWT-Extended:**
+
==Jika Token Salah / Tidak Ada:==
  
  ```bash
+
'''Output''' akan seperti ini:
  pip install Flask Flask-JWT-Extended
 
  ```
 
 
  
## Implementasi JSON Web Token (JWT) dalam Flask
+
json
 +
{
 +
  "error": "Unauthorized"
 +
}
  
Setelah instalasi, kita akan mengimplementasikan JWT untuk mengamankan API dalam aplikasi Flask.
+
==Kesimpulan==
  
1. **Konfigurasi Aplikasi Flask:**
+
* Tokenisasi adalah cara umum mengamankan API dari akses tidak sah.
 +
* Token bisa disimpan dalam:
 +
** Header (`Authorization: Bearer <token>`)
 +
** Parameter URL (kurang disarankan)
 +
* Untuk tingkat lanjut, bisa menggunakan '''JWT (JSON Web Token)''' atau '''OAuth2'''.
  
  Buat file `app.py` dan tambahkan kode berikut:
+
==Tugas Tambahan (Opsional)==
 +
* Buat form login sederhana yang memberikan token.
 +
* Simpan token dalam `session` atau `localStorage` di frontend.
 +
* Gunakan token tersebut untuk akses endpoint `/private`.
  
  ```python
 
  from flask import Flask, jsonify, request
 
  from flask_jwt_extended import JWTManager, create_access_token, jwt_required, get_jwt_identity
 
  
  app = Flask(__name__)
 
  
  # Konfigurasi kunci rahasia untuk JWT
 
  app.config['JWT_SECRET_KEY'] = 'kunci_rahasia_anda'
 
  jwt = JWTManager(app)
 
  
  if __name__ == '__main__':
 
      app.run(debug=True)
 
  ```
 
 
  
  Kode di atas menginisialisasi aplikasi Flask dan mengkonfigurasi kunci rahasia untuk JWT.
 
  
2. **Membuat Endpoint untuk Autentikasi Pengguna:**
 
  
  Tambahkan route untuk login yang menghasilkan token JWT:
+
=Orek2an Bahan Tambahan=
  
  ```python
 
  from werkzeug.security import check_password_hash
 
  
  # Data pengguna contoh
 
  users = {
 
      "user1": {
 
          "password": "hashed_password1"
 
      },
 
      "user2": {
 
          "password": "hashed_password2"
 
      }
 
  }
 
  
  @app.route('/login', methods=['POST'])
+
'''CATATAN:''' Materi ini harus di kembangkan lagi.
  def login():
 
      username = request.json.get('username', None)
 
      password = request.json.get('password', None)
 
  
      user = users.get(username, None)
+
Dalam pengembangan aplikasi web, keamanan komunikasi antara klien dan server menjadi aspek krusial. Salah satu metode yang umum digunakan untuk mengamankan komunikasi tersebut adalah melalui '''tokenisasi''', khususnya dengan implementasi '''JSON Web Tokens (JWT)'''. JWT memungkinkan autentikasi dan otorisasi yang aman tanpa perlu menyimpan status sesi di server, menjadikannya pilihan populer dalam pengembangan API modern.
      if user and check_password_hash(user['password'], password):
 
          access_token = create_access_token(identity=username)
 
          return jsonify(access_token=access_token), 200
 
      else:
 
          return jsonify({"msg": "Username atau password salah"}), 401
 
  ```
 
 
  
  Dalam contoh ini, `users` adalah kamus yang menyimpan data pengguna dengan password yang telah di-hash. Fungsi `check_password_hash` digunakan untuk memverifikasi password yang dimasukkan dengan hash yang tersimpan.
+
==Apa Itu JSON Web Token (JWT)?==
  
3. **Membuat Endpoint yang Dilindungi:**
+
'''JSON Web Token (JWT)''' adalah standar terbuka (RFC 7519) yang mendefinisikan cara aman untuk mentransmisikan informasi antara pihak-pihak sebagai objek JSON. Informasi ini dapat diverifikasi dan dipercaya karena ditandatangani secara digital. JWT terdiri dari tiga bagian utama:
  
  Tambahkan route yang hanya dapat diakses dengan token JWT yang valid:
+
* '''Header''': Berisi tipe token dan algoritma yang digunakan, seperti HMAC SHA256 atau RSA.
 +
* '''Payload''': Berisi klaim atau pernyataan tentang entitas (biasanya pengguna) dan data tambahan lainnya.
 +
* '''Signature''': Digunakan untuk memverifikasi bahwa pesan tidak diubah selama transmisi.
  
  ```python
+
Struktur JWT secara umum adalah sebagai berikut:
  @app.route('/protected', methods=['GET'])
 
  @jwt_required()
 
  def protected():
 
      current_user = get_jwt_identity()
 
      return jsonify(logged_in_as=current_user), 200
 
  ```
 
 
  
  Dekorator `@jwt_required()` memastikan bahwa endpoint ini hanya dapat diakses jika permintaan menyertakan token JWT yang valid.
+
Header.Payload.Signature
  
4. **Menjalankan Aplikasi:**
+
Setiap bagian dienkode dalam Base64URL dan dipisahkan oleh titik.
  
  Jalankan aplikasi Flask dengan perintah:
+
==Instalasi Flask dan Flask-JWT-Extended di Ubuntu 24.04==
  
  ```bash
+
Sebelum memulai implementasi, pastikan Anda telah menginstal Python 3 dan pip. Berikut langkah-langkah instalasi Flask dan Flask-JWT-Extended:
  python app.py
 
  ```
 
 
  
  Aplikasi akan berjalan di `http://127.0.0.1:5000/`.
+
1. '''Perbarui daftar paket dan instal dependensi yang diperlukan:'''
  
## Pengujian API dengan cURL
+
sudo apt update
 +
sudo apt install python3 python3-pip python3-venv -y
  
Untuk menguji endpoint yang telah dibuat, Anda dapat menggunakan cURL:
+
2. '''Buat direktori proyek dan navigasikan ke dalamnya:'''
  
1. **Melakukan Login untuk Mendapatkan Token:**
+
mkdir flask_jwt_api
 +
cd flask_jwt_api
  
  ```bash
+
3. '''Buat dan aktifkan virtual environment:'''
  curl -X POST http://127.0.0.1:5000/login \
 
  -H "Content-Type: application/json" \
 
  -d '{"username": "user1", "password": "password1"}'
 
  ```
 
 
  
  Jika berhasil, Anda akan menerima respons dengan token akses.
+
python3 -m venv venv
 +
source venv/bin/activate
  
2. **Mengakses Endpoint yang Dilindungi:**
+
4. '''Instal Flask dan Flask-JWT-Extended:'''
  
  Gantilah `your_access_token` dengan token yang diperoleh dari langkah sebelumnya.
+
pip install Flask Flask-JWT-Extended
  
  ```bash
+
==Implementasi JSON Web Token (JWT) dalam Flask==
  curl -X GET http://127.0.0.1:5000/protected \
 
  -H "Authorization: Bearer your_access_token"
 
  ```
 
 
  
  Jika token valid, Anda akan menerima respons
+
Setelah instalasi, kita akan mengimplementasikan JWT untuk mengamankan API dalam aplikasi Flask.
  
 +
1. '''Konfigurasi Aplikasi Flask:'''
  
 +
Buat file `app.py` dan tambahkan kode berikut:
  
 +
from flask import Flask, jsonify, request
 +
from flask_jwt_extended import JWTManager, create_access_token, jwt_required, get_jwt_identity
 +
 +
app = Flask(__name__)
 +
 +
# Konfigurasi kunci rahasia untuk JWT
 +
app.config['JWT_SECRET_KEY'] = 'kunci_rahasia_anda'
 +
jwt = JWTManager(app)
 +
 +
if __name__ == '__main__':
 +
    app.run(debug=True)
  
 +
Kode di atas menginisialisasi aplikasi Flask dan mengkonfigurasi kunci rahasia untuk JWT.
  
Melanjutkan pembahasan sebelumnya mengenai pengamanan API dengan JSON Web Token (JWT) dalam aplikasi Flask, kita akan membahas lebih lanjut tentang pengelolaan token, penanganan kesalahan, dan praktik terbaik dalam implementasi JWT.
+
2. '''Membuat Endpoint untuk Autentikasi Pengguna:'''
  
## 1. Penggunaan Refresh Token
+
Tambahkan route untuk login yang menghasilkan token JWT:
  
Selain **access token**, JWT juga mendukung penggunaan **refresh token**. Access token biasanya memiliki masa berlaku yang singkat untuk mengurangi risiko jika token tersebut dicuri. Setelah access token kedaluwarsa, refresh token digunakan untuk mendapatkan access token baru tanpa perlu meminta pengguna untuk login kembali.
+
from werkzeug.security import check_password_hash
 +
 +
# Data pengguna contoh
 +
users = {
 +
    "user1": {
 +
        "password": "hashed_password1"
 +
    },
 +
    "user2": {
 +
        "password": "hashed_password2"
 +
    }
 +
}
 +
 +
@app.route('/login', methods=['POST'])
 +
def login():
 +
    username = request.json.get('username', None)
 +
    password = request.json.get('password', None)
 +
 +
    user = users.get(username, None)
 +
    if user and check_password_hash(user['password'], password):
 +
        access_token = create_access_token(identity=username)
 +
        return jsonify(access_token=access_token), 200
 +
    else:
 +
        return jsonify({"msg": "Username atau password salah"}), 401
  
**Implementasi Refresh Token dalam Flask:**
+
Dalam contoh ini, `users` adalah kamus yang menyimpan data pengguna dengan password yang telah di-hash. Fungsi `check_password_hash` digunakan untuk memverifikasi password yang dimasukkan dengan hash yang tersimpan.
  
Tambahkan konfigurasi berikut pada aplikasi Flask Anda:
+
3. '''Membuat Endpoint yang Dilindungi:'''
  
 +
Tambahkan route yang hanya dapat diakses dengan token JWT yang valid:
  
```python
+
@app.route('/protected', methods=['GET'])
from flask_jwt_extended import create_refresh_token, jwt_refresh_token_required
+
@jwt_required()
 +
def protected():
 +
    current_user = get_jwt_identity()
 +
    return jsonify(logged_in_as=current_user), 200
  
# Endpoint untuk login yang menghasilkan access dan refresh token
+
Dekorator `@jwt_required()` memastikan bahwa endpoint ini hanya dapat diakses jika permintaan menyertakan token JWT yang valid.
@app.route('/login', methods=['POST'])
 
def login():
 
    username = request.json.get('username')
 
    password = request.json.get('password')
 
    user = users.get(username)
 
    if user and check_password_hash(user['password'], password):
 
        access_token = create_access_token(identity=username)
 
        refresh_token = create_refresh_token(identity=username)
 
        return jsonify(access_token=access_token, refresh_token=refresh_token), 200
 
    return jsonify({"msg": "Username atau password salah"}), 401
 
  
# Endpoint untuk mendapatkan access token baru menggunakan refresh token
+
4. '''Menjalankan Aplikasi:'''
@app.route('/refresh', methods=['POST'])
 
@jwt_refresh_token_required
 
def refresh():
 
    current_user = get_jwt_identity()
 
    new_access_token = create_access_token(identity=current_user)
 
    return jsonify(access_token=new_access_token), 200
 
```
 
 
  
Dalam implementasi di atas, saat pengguna berhasil login, sistem akan memberikan **access token** dan **refresh token**. Ketika access token kedaluwarsa, klien dapat menggunakan refresh token untuk mendapatkan access token baru tanpa perlu login ulang.
+
Jalankan aplikasi Flask dengan perintah:
  
## 2. Penanganan Kesalahan (Error Handling)
+
python app.py
  
Penanganan kesalahan yang tepat penting untuk memberikan informasi yang jelas kepada klien dan meningkatkan keamanan aplikasi. Flask-JWT-Extended menyediakan dekorator untuk menangani berbagai jenis kesalahan terkait JWT.
+
Aplikasi akan berjalan di `http://127.0.0.1:5000/`.
  
**Contoh Penanganan Kesalahan:**
+
==Pengujian API dengan cURL==
  
 +
Untuk menguji endpoint yang telah dibuat, Anda dapat menggunakan cURL:
  
```python
+
1. '''Melakukan Login untuk Mendapatkan Token:'''
from flask_jwt_extended import JWTManager
 
  
app.config['JWT_SECRET_KEY'] = 'kunci_rahasia_anda'
+
curl -X POST http://127.0.0.1:5000/login \
jwt = JWTManager(app)
+
-H "Content-Type: application/json" \
 +
-d '{"username": "user1", "password": "password1"}'
  
@jwt.expired_token_loader
+
Jika berhasil, Anda akan menerima respons dengan token akses.
def expired_token_callback(jwt_header, jwt_payload):
 
    return jsonify({"msg": "Token telah kedaluwarsa"}), 401
 
  
@jwt.invalid_token_loader
+
2. '''Mengakses Endpoint yang Dilindungi:'''
def invalid_token_callback(error):
 
    return jsonify({"msg": "Token tidak valid"}), 422
 
  
@jwt.unauthorized_loader
+
Gantilah `your_access_token` dengan token yang diperoleh dari langkah sebelumnya.
def missing_token_callback(error):
 
    return jsonify({"msg": "Token otorisasi diperlukan"}), 401
 
```
 
 
  
Dengan penanganan kesalahan seperti di atas, aplikasi dapat memberikan respons yang sesuai saat terjadi kesalahan terkait JWT, seperti token kedaluwarsa, tidak valid, atau tidak disertakan dalam permintaan.
+
curl -X GET http://127.0.0.1:5000/protected \
 +
-H "Authorization: Bearer your_access_token"
  
## 3. Praktik Terbaik dalam Penggunaan JWT
+
Jika token valid, Anda akan menerima respons
  
- **Keamanan Kunci Rahasia:** Pastikan kunci rahasia (`JWT_SECRET_KEY`) disimpan dengan aman dan tidak dibagikan. Gunakan variabel lingkungan atau manajer konfigurasi untuk mengelola kunci rahasia.
+
Melanjutkan pembahasan sebelumnya mengenai pengamanan API dengan JSON Web Token (JWT) dalam aplikasi Flask, kita akan membahas lebih lanjut tentang pengelolaan token, penanganan kesalahan, dan praktik terbaik dalam implementasi JWT.
  
- **Masa Berlaku Token:** Tetapkan masa berlaku yang sesuai untuk access token dan refresh token. Access token dengan masa berlaku singkat mengurangi risiko jika token dicuri.
+
==1. Penggunaan Refresh Token==
  
- **Penggunaan HTTPS:** Selalu gunakan HTTPS untuk mengenkripsi komunikasi antara klien dan server, sehingga mencegah penyadapan token oleh pihak ketiga.
+
Selain '''access token''', JWT juga mendukung penggunaan '''refresh token'''. Access token biasanya memiliki masa berlaku yang singkat untuk mengurangi risiko jika token tersebut dicuri. Setelah access token kedaluwarsa, refresh token digunakan untuk mendapatkan access token baru tanpa perlu meminta pengguna untuk login kembali.
  
- **Penyimpanan Token di Klien:** Simpan token dengan aman di sisi klien. Hindari menyimpan token di `localStorage` atau `sessionStorage` karena rentan terhadap serangan XSS. Sebagai alternatif, pertimbangkan untuk menyimpan token di cookie dengan atribut `HttpOnly` dan `Secure`.
+
'''Implementasi Refresh Token dalam Flask:'''
  
- **Penanganan Logout:** Implementasikan mekanisme logout yang efektif dengan mencabut (revoke) token yang telah dikeluarkan. Salah satu caranya adalah dengan menyimpan daftar token yang dicabut di basis data dan memeriksa validitas token pada setiap permintaan.
+
Tambahkan konfigurasi berikut pada aplikasi Flask Anda:
  
**Contoh Implementasi Logout dengan Revokasi Token:**
+
from flask_jwt_extended import create_refresh_token, jwt_refresh_token_required
 +
 +
# Endpoint untuk login yang menghasilkan access dan refresh token
 +
@app.route('/login', methods=['POST'])
 +
def login():
 +
    username = request.json.get('username')
 +
    password = request.json.get('password')
 +
    user = users.get(username)
 +
    if user and check_password_hash(user['password'], password):
 +
        access_token = create_access_token(identity=username)
 +
        refresh_token = create_refresh_token(identity=username)
 +
        return jsonify(access_token=access_token, refresh_token=refresh_token), 200
 +
    return jsonify({"msg": "Username atau password salah"}), 401
 +
 +
# Endpoint untuk mendapatkan access token baru menggunakan refresh token
 +
@app.route('/refresh', methods=['POST'])
 +
@jwt_refresh_token_required
 +
def refresh():
 +
    current_user = get_jwt_identity()
 +
    new_access_token = create_access_token(identity=current_user)
 +
    return jsonify(access_token=new_access_token), 200
  
 +
Dalam implementasi di atas, saat pengguna berhasil login, sistem akan memberikan '''access token''' dan '''refresh token'''. Ketika access token kedaluwarsa, klien dapat menggunakan refresh token untuk mendapatkan access token baru tanpa perlu login ulang.
  
```python
+
==2. Penanganan Kesalahan (Error Handling)==
from flask_jwt_extended import get_jwt
 
  
# Simpan daftar token yang dicabut
+
Penanganan kesalahan yang tepat penting untuk memberikan informasi yang jelas kepada klien dan meningkatkan keamanan aplikasi. Flask-JWT-Extended menyediakan dekorator untuk menangani berbagai jenis kesalahan terkait JWT.
revoked_tokens = set()
 
  
@app.route('/logout', methods=['DELETE'])
+
'''Contoh Penanganan Kesalahan:'''
@jwt_required()
 
def logout():
 
    jti = get_jwt()['jti']
 
    revoked_tokens.add(jti)
 
    return jsonify({"msg": "Logout berhasil"}), 200
 
  
@jwt.token_in_blocklist_loader
+
from flask_jwt_extended import JWTManager
def check_if_token_revoked(jwt_header, jwt_payload):
+
    jti = jwt_payload['jti']
+
app.config['JWT_SECRET_KEY'] = 'kunci_rahasia_anda'
    return jti in revoked_tokens
+
jwt = JWTManager(app)
```
+
+
@jwt.expired_token_loader
 +
def expired_token_callback(jwt_header, jwt_payload):
 +
    return jsonify({"msg": "Token telah kedaluwarsa"}), 401
 +
 +
@jwt.invalid_token_loader
 +
def invalid_token_callback(error):
 +
    return jsonify({"msg": "Token tidak valid"}), 422
 +
 +
@jwt.unauthorized_loader
 +
def missing_token_callback(error):
 +
    return jsonify({"msg": "Token otorisasi diperlukan"}), 401
  
Dalam contoh di atas, setiap token memiliki **JWT ID (jti)** yang unik. Saat pengguna logout, jti token ditambahkan ke daftar `revoked_tokens`. Pada setiap permintaan yang memerlukan autentikasi, aplikasi memeriksa apakah jti token ada dalam daftar token yang dicabut.
+
Dengan penanganan kesalahan seperti di atas, aplikasi dapat memberikan respons yang sesuai saat terjadi kesalahan terkait JWT, seperti token kedaluwarsa, tidak valid, atau tidak disertakan dalam permintaan.
  
Dengan menerapkan praktik-praktik terbaik di atas, Anda dapat meningkatkan keamanan API yang menggunakan JWT untuk autentikasi dan otorisasi.
+
==3. Praktik Terbaik dalam Penggunaan JWT==
  
## 4. Pengujian API dengan Postman
+
* '''Keamanan Kunci Rahasia:''' Pastikan kunci rahasia (`JWT_SECRET_KEY`) disimpan dengan aman dan tidak dibagikan. Gunakan variabel lingkungan atau manajer konfigurasi untuk mengelola kunci rahasia.
 +
* '''Masa Berlaku Token:''' Tetapkan masa berlaku yang sesuai untuk access token dan refresh token. Access token dengan masa berlaku singkat mengurangi risiko jika token dicuri.
 +
* '''Penggunaan HTTPS:''' Selalu gunakan HTTPS untuk mengenkripsi komunikasi antara klien dan server, sehingga mencegah penyadapan token oleh pihak ketiga.
 +
* '''Penyimpanan Token di Klien:''' Simpan token dengan aman di sisi klien. Hindari menyimpan token di `localStorage` atau `sessionStorage` karena rentan terhadap serangan XSS. Sebagai alternatif, pertimbangkan untuk menyimpan token di cookie dengan atribut `HttpOnly` dan `Secure`.
 +
* '''Penanganan Logout:''' Implementasikan mekanisme logout yang efektif dengan mencabut (revoke) token yang telah dikeluarkan. Salah satu caranya adalah dengan menyimpan daftar token yang dicabut di basis data dan memeriksa validitas token pada setiap permintaan.
  
Selain menggunakan cURL, Anda dapat menggunakan **Postman** untuk menguji endpoint yang telah dibuat. Berikut langkah-langkahnya:
+
'''Contoh Implementasi Logout dengan Revokasi Token:'''
  
1. **Login untuk Mendapatkan Token:**
+
from flask_jwt_extended import get_jwt
  - Buka Postman dan buat permintaan **POST** ke `http://127.0.0.1:5000/login`.
+
  - Pada tab **Body**, pilih **raw** dan atur tipe menjadi **JSON**.
+
# Simpan daftar token yang dicabut
  - Masukkan data berikut:
+
revoked_tokens = set()
 +
 +
@app.route('/logout', methods=['DELETE'])
 +
@jwt_required()
 +
def logout():
 +
    jti = get_jwt()['jti']
 +
    revoked_tokens.add(jti)
 +
    return jsonify({"msg": "Logout berhasil"}), 200
 +
 +
@jwt.token_in_blocklist_loader
 +
def check_if_token_revoked(jwt_header, jwt_payload):
 +
    jti = jwt_payload['jti']
 +
    return jti in revoked_tokens
  
    ```json
+
Dalam contoh di atas, setiap token memiliki '''JWT ID (jti)''' yang unik. Saat pengguna logout, jti token ditambahkan ke daftar `revoked_tokens`. Pada setiap permintaan yang memerlukan autentikasi, aplikasi memeriksa apakah jti token ada dalam daftar token yang dicabut.
    {
 
      "username": "user1",
 
      "password": "password1"
 
    }
 
    ```
 
  
  - Klik **Send**. Jika berhasil, Anda akan menerima respons dengan access token dan refresh token.
+
Dengan menerapkan praktik-praktik terbaik di atas, Anda dapat meningkatkan keamanan API yang menggunakan JWT untuk autentikasi dan otorisasi.
  
2. **Mengakses Endpoint yang Dilindungi:**
+
==4. Pengujian API dengan Postman==
  - Buat permintaan **GET** ke `http://127.0.0.1:5000/protected`.
 
  - Pada tab **Headers**, tambahkan kunci `Authorization` dengan nilai `Bearer <access_token>`, ganti `<access
 
  
 +
Selain menggunakan cURL, Anda dapat menggunakan '''Postman''' untuk menguji endpoint yang telah dibuat. Berikut langkah-langkahnya:
  
 +
1. '''Login untuk Mendapatkan Token:'''
  
 +
* Buka Postman dan buat permintaan '''POST''' ke `http://127.0.0.1:5000/login`.
 +
* Pada tab '''Body''', pilih '''raw''' dan atur tipe menjadi '''JSON'''.
 +
* Masukkan data berikut:
  
 +
json
 +
{
 +
  "username": "user1",
 +
  "password": "password1"
 +
}
  
 +
* Klik '''Send'''. Jika berhasil, Anda akan menerima respons dengan access token dan refresh token.
  
Melanjutkan pembahasan sebelumnya mengenai pengamanan API dengan JSON Web Token (JWT) dalam aplikasi Flask, kita akan membahas lebih lanjut tentang **implementasi refresh token**, **penanganan logout dengan revokasi token**, dan **praktik terbaik dalam penggunaan JWT**.
+
2. '''Mengakses Endpoint yang Dilindungi:'''
  
## 1. Implementasi Refresh Token dalam Flask
+
* Buat permintaan '''GET''' ke `http://127.0.0.1:5000/protected`.
 +
* Pada tab '''Headers''', tambahkan kunci `Authorization` dengan nilai `Bearer <access_token>`, ganti `<access
  
**Refresh token** memungkinkan pengguna untuk mendapatkan access token baru tanpa perlu login kembali setelah access token sebelumnya kedaluwarsa. Hal ini meningkatkan keamanan dan kenyamanan pengguna.
 
  
**Langkah-langkah Implementasi:**
+
Melanjutkan pembahasan sebelumnya mengenai pengamanan API dengan JSON Web Token (JWT) dalam aplikasi Flask, kita akan membahas lebih lanjut tentang '''implementasi refresh token''', '''penanganan logout dengan revokasi token''', dan '''praktik terbaik dalam penggunaan JWT'''.
  
1. **Konfigurasi Masa Berlaku Token:**
+
==1. Implementasi Refresh Token dalam Flask==
  
  Tentukan masa berlaku untuk access token dan refresh token dalam konfigurasi aplikasi Flask:
+
'''Refresh token''' memungkinkan pengguna untuk mendapatkan access token baru tanpa perlu login kembali setelah access token sebelumnya kedaluwarsa. Hal ini meningkatkan keamanan dan kenyamanan pengguna.
  
  ```python
+
'''Langkah-langkah Implementasi:'''
  from datetime import timedelta
 
  
  app.config['JWT_ACCESS_TOKEN_EXPIRES'] = timedelta(minutes=15)  # Access token berlaku selama 15 menit
+
1. '''Konfigurasi Masa Berlaku Token:'''
  app.config['JWT_REFRESH_TOKEN_EXPIRES'] = timedelta(days=30)    # Refresh token berlaku selama 30 hari
 
  ```
 
 
  
  Dengan konfigurasi ini, access token memiliki masa berlaku yang singkat, sementara refresh token memiliki masa berlaku yang lebih panjang.
+
Tentukan masa berlaku untuk access token dan refresh token dalam konfigurasi aplikasi Flask:
  
2. **Membuat Endpoint untuk Mendapatkan Refresh Token:**
+
from datetime import timedelta
 +
 +
app.config['JWT_ACCESS_TOKEN_EXPIRES'] = timedelta(minutes=15)  # Access token berlaku selama 15 menit
 +
app.config['JWT_REFRESH_TOKEN_EXPIRES'] = timedelta(days=30)    # Refresh token berlaku selama 30 hari
 +
 
 +
Dengan konfigurasi ini, access token memiliki masa berlaku yang singkat, sementara refresh token memiliki masa berlaku yang lebih panjang.
  
  Saat pengguna berhasil login, selain memberikan access token, kita juga memberikan refresh token:
+
2. '''Membuat Endpoint untuk Mendapatkan Refresh Token:'''
  
  ```python
+
Saat pengguna berhasil login, selain memberikan access token, kita juga memberikan refresh token:
  from flask_jwt_extended import create_refresh_token
 
  
  @app.route('/login', methods=['POST'])
+
from flask_jwt_extended import create_refresh_token
  def login():
+
      username = request.json.get('username')
+
@app.route('/login', methods=['POST'])
      password = request.json.get('password')
+
def login():
      user = users.get(username)
+
    username = request.json.get('username')
      if user and check_password_hash(user['password'], password):
+
    password = request.json.get('password')
          access_token = create_access_token(identity=username, fresh=True)
+
    user = users.get(username)
          refresh_token = create_refresh_token(identity=username)
+
    if user and check_password_hash(user['password'], password):
          return jsonify(access_token=access_token, refresh_token=refresh_token), 200
+
        access_token = create_access_token(identity=username, fresh=True)
      return jsonify({"msg": "Username atau password salah"}), 401
+
        refresh_token = create_refresh_token(identity=username)
  ```
+
        return jsonify(access_token=access_token, refresh_token=refresh_token), 200
+
    return jsonify({"msg": "Username atau password salah"}), 401
  
  Dalam kode di atas, `create_refresh_token` digunakan untuk membuat refresh token yang dikirimkan bersama dengan access token setelah proses login berhasil.
+
Dalam kode di atas, `create_refresh_token` digunakan untuk membuat refresh token yang dikirimkan bersama dengan access token setelah proses login berhasil.
  
3. **Membuat Endpoint untuk Meregenerasi Access Token Menggunakan Refresh Token:**
+
3. '''Membuat Endpoint untuk Meregenerasi Access Token Menggunakan Refresh Token:'''
  
 
   Buat endpoint yang memungkinkan klien untuk mendapatkan access token baru menggunakan refresh token:
 
   Buat endpoint yang memungkinkan klien untuk mendapatkan access token baru menggunakan refresh token:
  
   ```python
+
   python
 
   from flask_jwt_extended import jwt_required, get_jwt_identity
 
   from flask_jwt_extended import jwt_required, get_jwt_identity
  
Line 363: Line 398:
 
       new_access_token = create_access_token(identity=current_user, fresh=False)
 
       new_access_token = create_access_token(identity=current_user, fresh=False)
 
       return jsonify(access_token=new_access_token), 200
 
       return jsonify(access_token=new_access_token), 200
   ```
+
    
+
Dekorator `@jwt_required(refresh=True)` memastikan bahwa hanya permintaan dengan refresh token yang valid yang dapat mengakses endpoint ini.
 
 
  Dekorator `@jwt_required(refresh=True)` memastikan bahwa hanya permintaan dengan refresh token yang valid yang dapat mengakses endpoint ini.
 
 
 
## 2. Penanganan Logout dengan Revokasi Token
 
  
Untuk meningkatkan keamanan, penting untuk memiliki mekanisme logout yang efektif dengan **revokasi token**. Ini memastikan bahwa setelah pengguna logout, token yang sebelumnya diberikan tidak dapat digunakan kembali.
+
==2. Penanganan Logout dengan Revokasi Token==
  
**Langkah-langkah Implementasi:**
+
Untuk meningkatkan keamanan, penting untuk memiliki mekanisme logout yang efektif dengan '''revokasi token'''. Ini memastikan bahwa setelah pengguna logout, token yang sebelumnya diberikan tidak dapat digunakan kembali.
  
1. **Menyimpan Token yang Dicabut:**
+
'''Langkah-langkah Implementasi:'''
  
  Buat struktur data (misalnya, himpunan atau tabel basis data) untuk menyimpan daftar token yang telah dicabut (diblacklist):
+
1. '''Menyimpan Token yang Dicabut:'''
  
  ```python
+
Buat struktur data (misalnya, himpunan atau tabel basis data) untuk menyimpan daftar token yang telah dicabut (diblacklist):
  from flask_jwt_extended import JWTManager
 
  
  app.config['JWT_SECRET_KEY'] = 'kunci_rahasia_anda'
+
from flask_jwt_extended import JWTManager
  app.config['JWT_BLACKLIST_ENABLED'] = True
+
  app.config['JWT_BLACKLIST_TOKEN_CHECKS'] = ['access', 'refresh']
+
app.config['JWT_SECRET_KEY'] = 'kunci_rahasia_anda'
  jwt = JWTManager(app)
+
app.config['JWT_BLACKLIST_ENABLED'] = True
 +
app.config['JWT_BLACKLIST_TOKEN_CHECKS'] = ['access', 'refresh']
 +
jwt = JWTManager(app)
 +
 +
blacklist = set()
  
  blacklist = set()
+
Konfigurasi `JWT_BLACKLIST_ENABLED` dan `JWT_BLACKLIST_TOKEN_CHECKS` memastikan bahwa aplikasi memeriksa daftar blacklist untuk access token dan refresh token.
  ```
 
 
  
  Konfigurasi `JWT_BLACKLIST_ENABLED` dan `JWT_BLACKLIST_TOKEN_CHECKS` memastikan bahwa aplikasi memeriksa daftar blacklist untuk access token dan refresh token.
+
2. '''Menambahkan Token ke Daftar Blacklist saat Logout:'''
  
2. **Menambahkan Token ke Daftar Blacklist saat Logout:**
+
Buat endpoint logout yang menambahkan token pengguna ke daftar blacklist:
  
  Buat endpoint logout yang menambahkan token pengguna ke daftar blacklist:
+
from flask_jwt_extended import get_jwt
 +
 +
@app.route('/logout', methods=['DELETE'])
 +
@jwt_required()
 +
def logout():
 +
    jti = get_jwt()['jti']
 +
    blacklist.add(jti)
 +
    return jsonify({"msg": "Logout berhasil"}), 200
  
  ```python
+
Di sini, `get_jwt()['jti']` mengambil JWT ID (jti) dari token saat ini dan menambahkannya ke daftar blacklist.
  from flask_jwt_extended import get_jwt
 
  
  @app.route('/logout', methods=['DELETE'])
+
3. '''Memeriksa Apakah Token Telah Dicabut:'''
  @jwt_required()
 
  def logout():
 
      jti = get_jwt()['jti']
 
      blacklist.add(jti)
 
      return jsonify({"msg": "Logout berhasil"}), 200
 
  ```
 
 
  
  Di sini, `get_jwt()['jti']` mengambil JWT ID (jti) dari token saat ini dan menambahkannya ke daftar blacklist.
+
Tambahkan fungsi callback untuk memeriksa apakah token termasuk dalam daftar blacklist:
  
3. **Memeriksa Apakah Token Telah Dicabut:**
+
@jwt.token_in_blocklist_loader
 +
def check_if_token_revoked(jwt_header, jwt_payload):
 +
    jti = jwt_payload['jti']
 +
    return jti in blacklist
  
  Tambahkan fungsi callback untuk memeriksa apakah token termasuk dalam daftar blacklist:
+
Dengan implementasi ini, setiap permintaan yang membawa token akan diperiksa apakah token tersebut telah dicabut atau belum.
  
  ```python
+
==3. Praktik Terbaik dalam Penggunaan JWT
  @jwt.token_in_blocklist_loader
 
  def check_if_token_revoked(jwt_header, jwt_payload):
 
      jti = jwt_payload['jti']
 
      return jti in blacklist
 
  ```
 
 
  
  Dengan implementasi ini, setiap permintaan yang membawa token akan diperiksa apakah token tersebut telah dicabut atau belum.
+
* '''Keamanan Penyimpanan Token di Klien:'''
  
## 3. Praktik Terbaik dalam Penggunaan JWT
+
Simpan token dengan aman di sisi klien. Hindari menyimpan token di `localStorage` atau `sessionStorage` karena rentan terhadap serangan XSS. Sebagai alternatif, pertimbangkan untuk menyimpan token di cookie dengan atribut `HttpOnly` dan `Secure`.
  
- **Keamanan Penyimpanan Token di Klien:**
+
'''Contoh Implementasi:'''
  
  Simpan token dengan aman di sisi klien. Hindari menyimpan token di `localStorage` atau `sessionStorage` karena rentan terhadap serangan XSS. Sebagai alternatif, pertimbangkan untuk menyimpan token di cookie dengan atribut `HttpOnly` dan `Secure`.
+
from flask import make_response
 +
 +
@app.route('/login', methods=['POST'])
 +
def login():
 +
    # Proses autentikasi
 +
    response = make_response(jsonify({"msg": "Login berhasil"}), 200)
 +
    set_access_cookies(response, access_token)
 +
    set_refresh_cookies(response, refresh_token)
 +
    return response
  
  **Contoh Implementasi:**
+
Dalam contoh di atas, `set_access_cookies` dan `set_refresh_cookies` digunakan untuk menyimpan token dalam cookie yang aman.
  
 
+
* '''Penggunaan HTTPS:'''
```python
 
  from flask import make_response
 
  
  @app.route('/login', methods=['POST'])
+
Selalu gunakan HTTPS untuk mengenkripsi komunikasi antara klien dan server, sehingga mencegah penyadapan token oleh pihak ketiga.
  def login():
 
      # Proses autentikasi
 
      response = make_response(jsonify({"msg": "Login berhasil"}), 200)
 
      set_access_cookies(response, access_token)
 
      set_refresh_cookies(response, refresh_token)
 
      return response
 
  ```
 
 
  
  Dalam contoh di atas, `set_access_cookies` dan `set_refresh_cookies` digunakan untuk menyimpan token dalam cookie yang aman.
+
* '''Pembaruan Token secara Proaktif:'''
  
- **Penggunaan HTTPS:**
+
Perbarui access token sebelum kedaluwarsa untuk memastikan pengalaman pengguna yang lancar.
  
  Selalu gunakan HTTPS untuk mengenkripsi komunikasi antara klien dan server, sehingga mencegah penyadapan token oleh pihak ketiga.
 
  
- **Pembaruan Token secara Proaktif:**
 
  
  Perbarui access token sebelum kedaluwarsa untuk memastikan pengalaman pengguna yang lancar. Misalnya, klien
 
  
 +
==Pranala Menarik==
  
  - **3.3. Mengamankan API dengan Tokenisasi**
+
* [[Web Programming]]
    - Menggunakan token untuk mengamankan komunikasi antara klien dan server.
 
    - Contoh: Implementasi JSON Web Tokens (JWT) dalam Flask.
 
    - Referensi: [Membuat REST API dengan Flask](https://www.digitalocean.com/community/tutorials/create-a-rest-api-using-flask-on-ubuntu)
 

Latest revision as of 18:59, 7 April 2025

Tujuan Pembelajaran

  • Memahami konsep tokenisasi dalam keamanan API.
  • Membangun API sederhana menggunakan Flask.
  • Mengamankan endpoint dengan Token (Bearer Token / API Key).
  • Mengakses API menggunakan tools seperti Postman atau `curl`.


Persiapan Lingkungan

1. Instalasi Flask

pip install flask


Bagian 1: API Tanpa Keamanan (Public)

`app.py`

from flask import Flask, jsonify, request

app = Flask(__name__)

@app.route('/public', methods=['GET'])
def public_api():
    return jsonify({"message": "Ini endpoint publik, semua orang bisa akses."}) 

if __name__ == '__main__':
    app.run(debug=True)

Akses:

curl http://localhost:5000/public

Bagian 2: API dengan Tokenisasi (Private)

Tambahkan Endpoint dengan Token:

API_TOKEN = "rahasiabanget123"  # Token disimpan secara hardcoded untuk contoh

@app.route('/private', methods=['GET'])
def private_api():
    token = request.headers.get('Authorization')

    if not token or token != f"Bearer {API_TOKEN}":
        return jsonify({"error": "Unauthorized"}), 401 

    return jsonify({"message": "Ini endpoint privat, hanya bisa diakses dengan token valid."})

> 💡 Header format yang digunakan adalah:

Authorization: Bearer rahasiabanget123

Contoh Akses dengan `curl`:

curl -H "Authorization: Bearer rahasiabanget123" http://localhost:5000/private


Uji dengan Postman

  • Jalankan server `python app.py`.
  • Buka Postman:
  • Klik Send untuk melihat hasil.

Jika Token Salah / Tidak Ada:

Output akan seperti ini:

json
{
  "error": "Unauthorized"
}

Kesimpulan

  • Tokenisasi adalah cara umum mengamankan API dari akses tidak sah.
  • Token bisa disimpan dalam:
    • Header (`Authorization: Bearer <token>`)
    • Parameter URL (kurang disarankan)
  • Untuk tingkat lanjut, bisa menggunakan JWT (JSON Web Token) atau OAuth2.

Tugas Tambahan (Opsional)

  • Buat form login sederhana yang memberikan token.
  • Simpan token dalam `session` atau `localStorage` di frontend.
  • Gunakan token tersebut untuk akses endpoint `/private`.




Orek2an Bahan Tambahan

CATATAN: Materi ini harus di kembangkan lagi.

Dalam pengembangan aplikasi web, keamanan komunikasi antara klien dan server menjadi aspek krusial. Salah satu metode yang umum digunakan untuk mengamankan komunikasi tersebut adalah melalui tokenisasi, khususnya dengan implementasi JSON Web Tokens (JWT). JWT memungkinkan autentikasi dan otorisasi yang aman tanpa perlu menyimpan status sesi di server, menjadikannya pilihan populer dalam pengembangan API modern.

Apa Itu JSON Web Token (JWT)?

JSON Web Token (JWT) adalah standar terbuka (RFC 7519) yang mendefinisikan cara aman untuk mentransmisikan informasi antara pihak-pihak sebagai objek JSON. Informasi ini dapat diverifikasi dan dipercaya karena ditandatangani secara digital. JWT terdiri dari tiga bagian utama:

  • Header: Berisi tipe token dan algoritma yang digunakan, seperti HMAC SHA256 atau RSA.
  • Payload: Berisi klaim atau pernyataan tentang entitas (biasanya pengguna) dan data tambahan lainnya.
  • Signature: Digunakan untuk memverifikasi bahwa pesan tidak diubah selama transmisi.

Struktur JWT secara umum adalah sebagai berikut:

Header.Payload.Signature

Setiap bagian dienkode dalam Base64URL dan dipisahkan oleh titik.

Instalasi Flask dan Flask-JWT-Extended di Ubuntu 24.04

Sebelum memulai implementasi, pastikan Anda telah menginstal Python 3 dan pip. Berikut langkah-langkah instalasi Flask dan Flask-JWT-Extended:

1. Perbarui daftar paket dan instal dependensi yang diperlukan:

sudo apt update
sudo apt install python3 python3-pip python3-venv -y

2. Buat direktori proyek dan navigasikan ke dalamnya:

mkdir flask_jwt_api
cd flask_jwt_api

3. Buat dan aktifkan virtual environment:

python3 -m venv venv
source venv/bin/activate

4. Instal Flask dan Flask-JWT-Extended:

pip install Flask Flask-JWT-Extended

Implementasi JSON Web Token (JWT) dalam Flask

Setelah instalasi, kita akan mengimplementasikan JWT untuk mengamankan API dalam aplikasi Flask.

1. Konfigurasi Aplikasi Flask:

Buat file `app.py` dan tambahkan kode berikut:

from flask import Flask, jsonify, request
from flask_jwt_extended import JWTManager, create_access_token, jwt_required, get_jwt_identity

app = Flask(__name__)

# Konfigurasi kunci rahasia untuk JWT
app.config['JWT_SECRET_KEY'] = 'kunci_rahasia_anda'
jwt = JWTManager(app)

if __name__ == '__main__':
    app.run(debug=True)

Kode di atas menginisialisasi aplikasi Flask dan mengkonfigurasi kunci rahasia untuk JWT.

2. Membuat Endpoint untuk Autentikasi Pengguna:

Tambahkan route untuk login yang menghasilkan token JWT:

from werkzeug.security import check_password_hash

# Data pengguna contoh
users = {
    "user1": {
        "password": "hashed_password1"
    },
    "user2": {
        "password": "hashed_password2"
    }
}

@app.route('/login', methods=['POST'])
def login():
    username = request.json.get('username', None)
    password = request.json.get('password', None)

    user = users.get(username, None)
    if user and check_password_hash(user['password'], password):
        access_token = create_access_token(identity=username)
        return jsonify(access_token=access_token), 200
    else:
        return jsonify({"msg": "Username atau password salah"}), 401
Dalam contoh ini, `users` adalah kamus yang menyimpan data pengguna dengan password yang telah di-hash. Fungsi `check_password_hash` digunakan untuk memverifikasi password yang dimasukkan dengan hash yang tersimpan.

3. Membuat Endpoint yang Dilindungi:

Tambahkan route yang hanya dapat diakses dengan token JWT yang valid:

@app.route('/protected', methods=['GET'])
@jwt_required()
def protected():
    current_user = get_jwt_identity()
    return jsonify(logged_in_as=current_user), 200

Dekorator `@jwt_required()` memastikan bahwa endpoint ini hanya dapat diakses jika permintaan menyertakan token JWT yang valid.

4. Menjalankan Aplikasi:

Jalankan aplikasi Flask dengan perintah:

python app.py

Aplikasi akan berjalan di `http://127.0.0.1:5000/`.

Pengujian API dengan cURL

Untuk menguji endpoint yang telah dibuat, Anda dapat menggunakan cURL:

1. Melakukan Login untuk Mendapatkan Token:

curl -X POST http://127.0.0.1:5000/login \
-H "Content-Type: application/json" \
-d '{"username": "user1", "password": "password1"}'

Jika berhasil, Anda akan menerima respons dengan token akses.

2. Mengakses Endpoint yang Dilindungi:

Gantilah `your_access_token` dengan token yang diperoleh dari langkah sebelumnya.

curl -X GET http://127.0.0.1:5000/protected \
-H "Authorization: Bearer your_access_token"

Jika token valid, Anda akan menerima respons

Melanjutkan pembahasan sebelumnya mengenai pengamanan API dengan JSON Web Token (JWT) dalam aplikasi Flask, kita akan membahas lebih lanjut tentang pengelolaan token, penanganan kesalahan, dan praktik terbaik dalam implementasi JWT.

1. Penggunaan Refresh Token

Selain access token, JWT juga mendukung penggunaan refresh token. Access token biasanya memiliki masa berlaku yang singkat untuk mengurangi risiko jika token tersebut dicuri. Setelah access token kedaluwarsa, refresh token digunakan untuk mendapatkan access token baru tanpa perlu meminta pengguna untuk login kembali.

Implementasi Refresh Token dalam Flask:

Tambahkan konfigurasi berikut pada aplikasi Flask Anda:

from flask_jwt_extended import create_refresh_token, jwt_refresh_token_required

# Endpoint untuk login yang menghasilkan access dan refresh token
@app.route('/login', methods=['POST'])
def login():
    username = request.json.get('username')
    password = request.json.get('password')
    user = users.get(username)
    if user and check_password_hash(user['password'], password):
        access_token = create_access_token(identity=username)
        refresh_token = create_refresh_token(identity=username)
        return jsonify(access_token=access_token, refresh_token=refresh_token), 200
    return jsonify({"msg": "Username atau password salah"}), 401

# Endpoint untuk mendapatkan access token baru menggunakan refresh token
@app.route('/refresh', methods=['POST'])
@jwt_refresh_token_required
def refresh():
    current_user = get_jwt_identity()
    new_access_token = create_access_token(identity=current_user)
    return jsonify(access_token=new_access_token), 200

Dalam implementasi di atas, saat pengguna berhasil login, sistem akan memberikan access token dan refresh token. Ketika access token kedaluwarsa, klien dapat menggunakan refresh token untuk mendapatkan access token baru tanpa perlu login ulang.

2. Penanganan Kesalahan (Error Handling)

Penanganan kesalahan yang tepat penting untuk memberikan informasi yang jelas kepada klien dan meningkatkan keamanan aplikasi. Flask-JWT-Extended menyediakan dekorator untuk menangani berbagai jenis kesalahan terkait JWT.

Contoh Penanganan Kesalahan:

from flask_jwt_extended import JWTManager

app.config['JWT_SECRET_KEY'] = 'kunci_rahasia_anda'
jwt = JWTManager(app)

@jwt.expired_token_loader
def expired_token_callback(jwt_header, jwt_payload):
    return jsonify({"msg": "Token telah kedaluwarsa"}), 401

@jwt.invalid_token_loader
def invalid_token_callback(error):
    return jsonify({"msg": "Token tidak valid"}), 422

@jwt.unauthorized_loader
def missing_token_callback(error):
    return jsonify({"msg": "Token otorisasi diperlukan"}), 401

Dengan penanganan kesalahan seperti di atas, aplikasi dapat memberikan respons yang sesuai saat terjadi kesalahan terkait JWT, seperti token kedaluwarsa, tidak valid, atau tidak disertakan dalam permintaan.

3. Praktik Terbaik dalam Penggunaan JWT

  • Keamanan Kunci Rahasia: Pastikan kunci rahasia (`JWT_SECRET_KEY`) disimpan dengan aman dan tidak dibagikan. Gunakan variabel lingkungan atau manajer konfigurasi untuk mengelola kunci rahasia.
  • Masa Berlaku Token: Tetapkan masa berlaku yang sesuai untuk access token dan refresh token. Access token dengan masa berlaku singkat mengurangi risiko jika token dicuri.
  • Penggunaan HTTPS: Selalu gunakan HTTPS untuk mengenkripsi komunikasi antara klien dan server, sehingga mencegah penyadapan token oleh pihak ketiga.
  • Penyimpanan Token di Klien: Simpan token dengan aman di sisi klien. Hindari menyimpan token di `localStorage` atau `sessionStorage` karena rentan terhadap serangan XSS. Sebagai alternatif, pertimbangkan untuk menyimpan token di cookie dengan atribut `HttpOnly` dan `Secure`.
  • Penanganan Logout: Implementasikan mekanisme logout yang efektif dengan mencabut (revoke) token yang telah dikeluarkan. Salah satu caranya adalah dengan menyimpan daftar token yang dicabut di basis data dan memeriksa validitas token pada setiap permintaan.

Contoh Implementasi Logout dengan Revokasi Token:

from flask_jwt_extended import get_jwt

# Simpan daftar token yang dicabut
revoked_tokens = set()

@app.route('/logout', methods=['DELETE'])
@jwt_required()
def logout():
    jti = get_jwt()['jti']
    revoked_tokens.add(jti)
    return jsonify({"msg": "Logout berhasil"}), 200

@jwt.token_in_blocklist_loader
def check_if_token_revoked(jwt_header, jwt_payload):
    jti = jwt_payload['jti']
    return jti in revoked_tokens

Dalam contoh di atas, setiap token memiliki JWT ID (jti) yang unik. Saat pengguna logout, jti token ditambahkan ke daftar `revoked_tokens`. Pada setiap permintaan yang memerlukan autentikasi, aplikasi memeriksa apakah jti token ada dalam daftar token yang dicabut.

Dengan menerapkan praktik-praktik terbaik di atas, Anda dapat meningkatkan keamanan API yang menggunakan JWT untuk autentikasi dan otorisasi.

4. Pengujian API dengan Postman

Selain menggunakan cURL, Anda dapat menggunakan Postman untuk menguji endpoint yang telah dibuat. Berikut langkah-langkahnya:

1. Login untuk Mendapatkan Token:

  • Buka Postman dan buat permintaan POST ke `http://127.0.0.1:5000/login`.
  • Pada tab Body, pilih raw dan atur tipe menjadi JSON.
  • Masukkan data berikut:
json
{
  "username": "user1",
  "password": "password1"
}
  • Klik Send. Jika berhasil, Anda akan menerima respons dengan access token dan refresh token.

2. Mengakses Endpoint yang Dilindungi:

  • Buat permintaan GET ke `http://127.0.0.1:5000/protected`.
  • Pada tab Headers, tambahkan kunci `Authorization` dengan nilai `Bearer <access_token>`, ganti `<access


Melanjutkan pembahasan sebelumnya mengenai pengamanan API dengan JSON Web Token (JWT) dalam aplikasi Flask, kita akan membahas lebih lanjut tentang implementasi refresh token, penanganan logout dengan revokasi token, dan praktik terbaik dalam penggunaan JWT.

1. Implementasi Refresh Token dalam Flask

Refresh token memungkinkan pengguna untuk mendapatkan access token baru tanpa perlu login kembali setelah access token sebelumnya kedaluwarsa. Hal ini meningkatkan keamanan dan kenyamanan pengguna.

Langkah-langkah Implementasi:

1. Konfigurasi Masa Berlaku Token:

Tentukan masa berlaku untuk access token dan refresh token dalam konfigurasi aplikasi Flask:

from datetime import timedelta

app.config['JWT_ACCESS_TOKEN_EXPIRES'] = timedelta(minutes=15)  # Access token berlaku selama 15 menit
app.config['JWT_REFRESH_TOKEN_EXPIRES'] = timedelta(days=30)    # Refresh token berlaku selama 30 hari
  

Dengan konfigurasi ini, access token memiliki masa berlaku yang singkat, sementara refresh token memiliki masa berlaku yang lebih panjang.

2. Membuat Endpoint untuk Mendapatkan Refresh Token:

Saat pengguna berhasil login, selain memberikan access token, kita juga memberikan refresh token:

from flask_jwt_extended import create_refresh_token

@app.route('/login', methods=['POST'])
def login():
    username = request.json.get('username')
    password = request.json.get('password')
    user = users.get(username)
    if user and check_password_hash(user['password'], password):
        access_token = create_access_token(identity=username, fresh=True)
        refresh_token = create_refresh_token(identity=username)
        return jsonify(access_token=access_token, refresh_token=refresh_token), 200
    return jsonify({"msg": "Username atau password salah"}), 401

Dalam kode di atas, `create_refresh_token` digunakan untuk membuat refresh token yang dikirimkan bersama dengan access token setelah proses login berhasil.

3. Membuat Endpoint untuk Meregenerasi Access Token Menggunakan Refresh Token:

  Buat endpoint yang memungkinkan klien untuk mendapatkan access token baru menggunakan refresh token:
  python
  from flask_jwt_extended import jwt_required, get_jwt_identity
  @app.route('/refresh', methods=['POST'])
  @jwt_required(refresh=True)
  def refresh():
      current_user = get_jwt_identity()
      new_access_token = create_access_token(identity=current_user, fresh=False)
      return jsonify(access_token=new_access_token), 200
  

Dekorator `@jwt_required(refresh=True)` memastikan bahwa hanya permintaan dengan refresh token yang valid yang dapat mengakses endpoint ini.

2. Penanganan Logout dengan Revokasi Token

Untuk meningkatkan keamanan, penting untuk memiliki mekanisme logout yang efektif dengan revokasi token. Ini memastikan bahwa setelah pengguna logout, token yang sebelumnya diberikan tidak dapat digunakan kembali.

Langkah-langkah Implementasi:

1. Menyimpan Token yang Dicabut:

Buat struktur data (misalnya, himpunan atau tabel basis data) untuk menyimpan daftar token yang telah dicabut (diblacklist):

from flask_jwt_extended import JWTManager

app.config['JWT_SECRET_KEY'] = 'kunci_rahasia_anda'
app.config['JWT_BLACKLIST_ENABLED'] = True
app.config['JWT_BLACKLIST_TOKEN_CHECKS'] = ['access', 'refresh']
jwt = JWTManager(app)

blacklist = set()

Konfigurasi `JWT_BLACKLIST_ENABLED` dan `JWT_BLACKLIST_TOKEN_CHECKS` memastikan bahwa aplikasi memeriksa daftar blacklist untuk access token dan refresh token.

2. Menambahkan Token ke Daftar Blacklist saat Logout:

Buat endpoint logout yang menambahkan token pengguna ke daftar blacklist:

from flask_jwt_extended import get_jwt

@app.route('/logout', methods=['DELETE'])
@jwt_required()
def logout():
    jti = get_jwt()['jti']
    blacklist.add(jti)
    return jsonify({"msg": "Logout berhasil"}), 200

Di sini, `get_jwt()['jti']` mengambil JWT ID (jti) dari token saat ini dan menambahkannya ke daftar blacklist.

3. Memeriksa Apakah Token Telah Dicabut:

Tambahkan fungsi callback untuk memeriksa apakah token termasuk dalam daftar blacklist:

@jwt.token_in_blocklist_loader
def check_if_token_revoked(jwt_header, jwt_payload):
    jti = jwt_payload['jti']
    return jti in blacklist

Dengan implementasi ini, setiap permintaan yang membawa token akan diperiksa apakah token tersebut telah dicabut atau belum.

==3. Praktik Terbaik dalam Penggunaan JWT

  • Keamanan Penyimpanan Token di Klien:

Simpan token dengan aman di sisi klien. Hindari menyimpan token di `localStorage` atau `sessionStorage` karena rentan terhadap serangan XSS. Sebagai alternatif, pertimbangkan untuk menyimpan token di cookie dengan atribut `HttpOnly` dan `Secure`.

Contoh Implementasi:

from flask import make_response

@app.route('/login', methods=['POST'])
def login():
    # Proses autentikasi
    response = make_response(jsonify({"msg": "Login berhasil"}), 200)
    set_access_cookies(response, access_token)
    set_refresh_cookies(response, refresh_token)
    return response

Dalam contoh di atas, `set_access_cookies` dan `set_refresh_cookies` digunakan untuk menyimpan token dalam cookie yang aman.

  • Penggunaan HTTPS:

Selalu gunakan HTTPS untuk mengenkripsi komunikasi antara klien dan server, sehingga mencegah penyadapan token oleh pihak ketiga.

  • Pembaruan Token secara Proaktif:

Perbarui access token sebelum kedaluwarsa untuk memastikan pengalaman pengguna yang lancar.



Pranala Menarik