Ana içeriğe geç

Kimlik Doğrulama (Authentication)

JWT Token Yapısı

Access Token (30 dakika)

{"exp": 1234567890, "sub": "user-uuid", "tenant_id": "tenant-uuid", "type": "access"}

Refresh Token (7 gün)

{"exp": 1234567890, "sub": "user-uuid", "tenant_id": "tenant-uuid", "type": "refresh"}

Login Akışı

POST /api/auth/login
Body: {"email": "user@example.com", "password": "..."}
Response: {"access_token": "...", "refresh_token": "..."}

Token Yenileme

POST /api/auth/refresh
Body: {"refresh_token": "..."}
Response: {"access_token": "new-token"}

Password Hashing

  • Algoritma: pbkdf2_sha256 / bcrypt
  • passlib[bcrypt] kütüphanesi

Dependency Injection

async def get_current_user(token: str = Depends(HTTPBearer())):
payload = decode_token(token)
user = await db.get(User, payload["sub"])
permissions = load_permissions(user)
return CurrentUser(id=user.id, tenant_id=user.tenant_id, permissions=permissions)

Token İmzalama

ParametreDeğer
AlgoritmaHS256 (HMAC with SHA-256)
Secret KeySECRET_KEY environment değişkeni (minimum 32 karakter)
Kaynak Dosyabackend/app/core/security/auth.py

Token imzalama için kullanılan secret key, .env dosyasında SECRET_KEY olarak tanımlanır. Bu değerin kriptografik olarak güçlü ve en az 32 karakter uzunluğunda olması zorunludur. Secret key değiştiğinde mevcut tüm token'lar geçersiz hale gelir.


Token Yenileme ve İptal

Yenileme Akışı

  1. Access token süresi dolduğunda (30 dakika) client HTTP 401 alır
  2. Client, refresh token ile POST /api/auth/refresh endpoint'ine istek gönderir
  3. Backend refresh token'ı doğrular ve yeni access token döner
  4. Refresh token'ın da süresi dolduysa (7 gün) kullanıcının yeniden giriş yapması gerekir

Stateless JWT Yapısı

  • Refresh token'lar veritabanında saklanmaz (stateless JWT)
  • Token iptali için blacklist mekanizması yoktur
  • Bu nedenle token sürelerinin kısa tutulması kritiktir (access: 30dk, refresh: 7 gün)

Token Geçersiz Kılma

  • Şifre değişikliğinde mevcut token'lar doğal süreleri dolana kadar geçerli kalır
  • Acil durumda tüm token'ları geçersiz kılmak için SECRET_KEY rotasyonu yapılmalıdır
  • SECRET_KEY rotasyonu tüm kullanıcıların token'larını geçersiz kılar — dikkatli kullanılmalıdır

CORS Yapılandırması

FastAPI CORSMiddleware ile cross-origin istekler kontrol altına alınmıştır.

Backend Ayarları

app.add_middleware(
CORSMiddleware,
allow_origins=["https://enerji.kepmark.com"], # Frontend domain
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)

Next.js Proxy (Same-Origin)

Frontend'den API'ye yapılan istekler next.config.js içindeki rewrites ile proxy'lenir. Bu sayede tarayıcı tarafında same-origin politikası sağlanır:

// next.config.js
async rewrites() {
return [
{
source: '/api/:path*',
destination: 'http://backend:8000/api/:path*',
},
];
}

Bu yapılandırma sayesinde frontend /api/* isteklerini doğrudan kendi origin'inden yapar, CORS sorunları ortadan kalkar.


Rate Limiting

Kimlik doğrulama endpoint'leri Nginx katmanında rate limiting ile korunmaktadır.

EndpointLimitAçıklama
POST /api/auth/login5 istek/dakikaBrute-force saldırı koruması
POST /api/auth/refresh5 istek/dakikaToken yenileme kötüye kullanım koruması
/api/* (genel)30 istek/saniyeGenel API koruması

Aşım Davranışı

  • HTTP 429 Too Many Requests status kodu döner
  • Retry-After header'ı ile beklenmesi gereken süre belirtilir
  • Client tarafında exponential backoff stratejisi önerilir

Nginx Yapılandırma Örneği

limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
limit_req_zone $binary_remote_addr zone=api:10m rate=30r/s;

location /api/auth/login {
limit_req zone=login burst=3 nodelay;
proxy_pass http://backend;
}

location /api/ {
limit_req zone=api burst=50 nodelay;
proxy_pass http://backend;
}

Şifre Sıfırlama (Self-Service Password Reset)

Kullanıcılar şifrelerini unuttuklarında yönetici müdahalesi olmadan kendileri sıfırlayabilir. Bu akış her zaman açıktır — tenant signup özelliğinin (TENANT_SIGNUP_ENABLED) açık/kapalı olmasından bağımsız çalışır.

Ekran Akışı

  1. Giriş sayfası (/login): Parola alanının yanındaki "Parolamı Unuttum" bağlantısına tıklanır.
  2. Şifremi Unuttum (/forgot-password): E-posta adresi girilir ve "Sıfırlama Bağlantısı Gönder" butonuna basılır. Yanıt her durumda aynıdır: "E-posta adresiniz sistemde kayıtlıysa şifre sıfırlama bağlantısı gönderildi."
  3. E-posta: Gelen kutusuna tek kullanımlık sıfırlama bağlantısı düşer (/reset-password?token=...).
  4. Yeni Şifre Belirle (/reset-password): Yeni parola iki kez girilir ve güncellenir. Başarı ekranındaki "Yeni şifremle giriş yap" butonu giriş sayfasına yönlendirir.

Şifre Politikası

Yeni parola aşağıdaki kurallara uymak zorundadır (kayıt/signup ve kullanıcı daveti kabulü ile aynı politika — tek kaynak: app/core/security/password_policy.py):

  • En az 12, en fazla 128 karakter
  • En az bir harf (Türkçe karakterler dahil) ve bir rakam

Politikaya uymayan parola hem arayüzde anında, hem backend'de (422) reddedilir.

Güvenlik Özellikleri

ÖzellikDavranış
Tek aktif bağlantıYeni sıfırlama isteği, önceki aktif bağlantıları iptal eder — yalnız en son gönderilen bağlantı çalışır
Bağlantı ömrü (TTL)60 dakika (PASSWORD_RESET_TOKEN_TTL_MINUTES, varsayılan 60). Süresi dolan bağlantı için yeni istek yapılmalıdır
Tek kullanımlık tokenBağlantı bir kez kullanıldığında geçersizleşir
Enumeration korumasıİstek yanıtı e-postanın kayıtlı olup olmadığını açığa çıkarmaz — her iki durumda da aynı mesaj döner
Oracle korumasıGeçersiz / süresi dolmuş / kullanılmış bağlantı ayrımı yapılmadan tek bir genel hata gösterilir
Oturum etkisiBaşarılı sıfırlama sonrası eski refresh token'lar geçersizleşir; kullanıcı yeni parolayla tekrar giriş yapar (mevcut access token'lar exp süresine kadar geçerli kalır)
Rate limitE-posta başına 3 istek/saat + IP başına 10 istek/saat (aşımda 429 + bekleme süresi)

İlgili Endpoint'ler

EndpointAçıklama
POST /api/auth/password-reset/requestSıfırlama bağlantısı iste (public, her zaman 202)
POST /api/auth/password-reset/confirmToken'ı tüket + yeni parolayı kaydet (public, 200)

İlgili Sayfalar

Aynı güvenlik ilkeleri (tek kullanımlık bağlantı, bağlantı ömrü/TTL, oracle koruması, rate limit) hesap oluşturma akışlarında da geçerlidir:

  • Yeni Firma Kaydı — çevrimiçi firma başvurusu (telefon kodu + e-posta doğrulama bağlantısı)
  • Kullanıcı Davetleri — davet bağlantısı ile hesap kurulumu (7 gün TTL, tek aktif bağlantı)