12 KiB
Admin Panel — Giriş (Login) + Refresh Token Mantığı Prompt / İş Tanımı
Amaç:
- Var olan
admin-panelVue projesinde (Tailwind, reka-ui, Pinia, vue-auth3, lucide-vue-next, zod, vb.) Go backend API ile sadece "login" işlevi sunan admin arayüzü oluşturmak. - Backend JWT access token + refresh token mekanizması destekliyor (refresh token mantığı kurulmalı).
- Backend base:
http://localhost:8080/api/v1— login endpoint:POST /auth/login(dönen: access token + refresh token + user) — refresh endpoint olarakPOST /auth/refresh(veya backend ile uyumlu başka path) bekleniyor. - Hedef: güvenli, responsive login + refresh token tabanlı token yenileme, token saklama ve otomatik yenileme akışı ile korunan admin dashboard iskeleti.
Genel Tasarım Kararları (kritik)
- Access token (kısa ömürlü, örneğin 5-15 dk): uygulamada bellek/Pinia state veya memory-only saklama (localStorage'ta saklanması güvenlik riski taşıdığından önerilmez).
- Refresh token (uzun ömürlü, örneğin 7-30 gün): production için HttpOnly, Secure cookie ile saklanmalı — bu, XSS riskini azaltır. Eğer backend cookie ile set ediyorsa client sadece server çağrısıyla refresh yapar (cookie otomatik gönderilir).
- Eğer backend refresh token'ı client tarafında bekliyorsa (ör. JSON response ile gönderip client saklıyorsa), yalnızca sessionStorage (veya yine tercihen HttpOnly cookie) kullanılmalı; localStorage önerilmez.
- Refresh token rotation ve revocation: backend destekliyorsa rotasyonu kullan; logout veya refresh hatasında token'ı serverda iptal et.
Beklenen Endpoint'ler (uygulama tarafının kullanacağı)
- POST /api/v1/auth/login
- Body: { email, password }
- Response (örnek): { access_token, refresh_token (opsiyonel if cookie), user, expires_in }
- POST /api/v1/auth/refresh
- Use-case: access token yenileme. Eğer refresh token cookie ile saklanıyorsa body boş olabilir; aksi halde { refresh_token } gönderilebilir.
- Response: { access_token, refresh_token (rotated), expires_in }
- POST /api/v1/auth/logout
- Use-case: refresh token'ı server tarafında invalidasyon + client temizleme.
Refresh Token Akışı — Kabul Kriterleri ve Davranış
-
Login akışı
- Kullanıcı /login formunu doldurur.
- POST /auth/login çağrısı yapılır.
- Başarılıysa:
- Access token uygulama state'ine (Pinia memory) veya güvenli saklama yerine kısa süreli tutulacak şekilde konur.
- Refresh token:
- Tercih A (öncelikli, tavsiye): backend Set-Cookie ile HttpOnly, Secure cookie olarak gönderir. Client hiçbir şekilde refresh token'ı JS üzerinden okumaz veya yazmaz.
- Tercih B (fallback): backend refresh token'ı JSON içinde dönerse client token'ı sessionStorage'e veya (remember me seçeneği varsa) localStorage'e koyar ve riskler README'de belirtilir.
- Kullanıcı /admin'e yönlendirilir.
-
Otomatik yenileme (interceptor + single-refresh lock)
- Tüm korumalı isteklerde Authorization: Bearer <access_token> header kullanılır.
- Bir istek 401 dönerse ve hata sebebi token expiration ise:
- HTTP client (axios/fetch wrapper) bir refresh attempt başlatır:
- Eğer başka bir refresh devam ediyorsa yeni istek bekletilir (queue) — bu, aynı anda birden çok refresh çağrısının yapılmasını engeller.
- Refresh başarılı ise yeni access token (ve varsa yeni refresh token) saklanır; bekleyen istekler yeniden denenir (replay).
- Refresh başarısız ise (refresh expired veya invalid) -> authStore.logout() çağrılır ve kullanıcı /login'e yönlendirilir.
- HTTP client (axios/fetch wrapper) bir refresh attempt başlatır:
- İstek interceptor'ı 401'lerde doğrudan logout yerine önce refresh denemeli; refresh'in başarısız olması durumunda logout yapılmalı.
-
Proaktif yenileme (optional, önerilen UX)
- Access token expiry (exp) okunarak (token JWT ise), expiry zamanından örn. 60-120s önce otomatik yenileme tetiklenebilir.
- Bu, kullanıcı etkileşimi sırasında beklenmedik logout'ları azaltır.
- Proaktif yenileme, aynı queue/lock mekanizmasını kullanarak aynı anda birden fazla refresh'i engeller.
-
Logout / revocation
- logout() çağrıldığında client:
- Eğer refresh cookie ise: POST /auth/logout çağrısı yaparak server tarafında refresh token iptal edilir ve server cookie'yi temizler.
- Client state'teki access token ve user bilgileri temizlenir; local/session storage temizlenir.
- Kullanıcı /login'e yönlendirilir.
- logout() çağrıldığında client:
-
Refresh token rotation & güvenlik
- Eğer backend rotation destekliyorsa (refresh token her yenilemede değişiyorsa), client her refresh response'unda yeni refresh token'ı saklamalı (ve/veya server Set-Cookie ile güncelleyip JS erişim izni vermemeli).
- Tek kullanımlık (one-time) refresh token kullanımı varsa backend başarısız veya yeniden kullanım durumunda tüm oturumları iptal etmeli.
- HTTP cookie attributeleri (production):
- HttpOnly
- Secure
- SameSite=Lax (veya Strict, ihtiyaçlara göre)
- Path=/api/v1/auth/refresh (gerekirse) veya Path=/
- Domain ihtiyaca göre ayarlanmalı
Client tarafında uygulama tasarımı (yapılacaklar — geliştiriciye talimat)
- Auth store (Pinia) içinde:
- state: accessToken (memory), user, loading, refreshPromise / refreshLock (internal)
- getters: isAuthenticated
- actions: login(), logout(), setAccessToken(), tryRefresh()
- tryRefresh(): refresh endpoint'ine istek atar; başarılıysa accessToken güncellenir; başarısızsa reject -> logout.
- HTTP client wrapper:
- baseURL: VITE_API_BASE_URL
- request interceptor: access token mevcutsa Authorization header ekle
- response interceptor:
- 401 alındığında:
- Eğer hata tipi token expired ise tryRefresh() çağrılır.
- tryRefresh() başarılı ise orijinal istek yeniden gönderilir.
- Eğer tryRefresh() başarısızsa logout() ve /login yönlendirme.
- Her isteğin retry mekanizması maksimum 1 refresh attempt ile sınırlı olmalı (sonsuz döngü olmaması için).
- 401 alındığında:
- Concurrent refresh yönetimi: single refresh promise pattern (ilk refresh çağrısı bir Promise döndürür; diğer istekler bu promise'i await eder).
- Proaktif yenileme (opsiyonel ama önerilen):
- Access token decode edilerek exp timestamp alınır.
- exp - now <= threshold (örn. 60s) olduğunda tryRefresh() çağrılır.
- Bu mekanizma kullanıcı etkileşiminde veya route değişimlerinde tetiklenebilir.
- Storage politikası:
- access token: bellek (Pinia) veya short-lived storage
- refresh token: HttpOnly cookie (tercih) veya sessionStorage/secure storage fallback
- README'de hangi seçeneğin neden seçildiği açıkça dokümante edilecek.
Hata Yönetimi & UX
- Refresh başarısız olursa kullanıcıya basit, net bir mesaj göster: "Oturum süresi doldu, lütfen tekrar giriş yapın."
- Arka arkaya çalışan isteklerde refresh sırasında spinner veya global loading state kullanılabilir.
- Eğer backend 429 (rate limit) veya 5xx dönerse kullanıcı uygun uyarı almalı (tekrar dene vs).
Test Senaryoları (kritik)
- Başarılı login:
- login -> access token alındı, refresh token cookie ile set edildi (veya sessionStorage'e kondu) -> /admin'e yönlendirme.
- Access token expire iken istek:
- İlk korumalı istek 401 döner -> tryRefresh() tetiklenir -> refresh başarılı -> orijinal istek tekrar çalışır -> kullanıcı etkileşimi kesintisiz devam eder.
- Refresh expired veya invalid:
- Refresh attempt başarısız -> logout -> /login ve uygun hata mesajı.
- Concurrent istekler token expired durumda:
- Birden fazla istek gönderildiğinde yalnızca bir refresh çağrısı yapılmalı, diğerleri bekletilip ardından yeniden denenmeli.
- Logout:
- logout çağrıldığında server /auth/logout çağrılır (varsa) ve client state & storageler temizlenir.
- Proaktif yenileme:
- Token exp < threshold iken uygulama otomatik yenileme yapıyor ve kullanıcıyı kesintiye uğratmıyor.
Dokümantasyon ve README Notları
- .env örneği: VITE_API_BASE_URL=http://localhost:8080/api/v1
- Token saklama tercihleri ve güvenlik nedenleri (HttpOnly cookie vs localStorage) açıkça yazılmalı.
- Backend ile cookie tabanlı refresh kullanılıyorsa CORS ve credentials ayarları açıklanmalı (axios: withCredentials=true; server: Access-Control-Allow-Credentials: true).
- Güvenlik önerileri: refresh token'ların server-side revocation tablosunda saklanması, rotation kullanımı ve refresh token reuse detection.
Teslim Edilecekler (geliştiriciye verilecek)
- Güncellenmiş prompt (bu dosya) — refresh token mantığı, beklenen endpoint'ler, client davranışı ve test senaryoları açık.
- Uygulamada olması gerekenler:
- login sayfası
- Pinia auth store (refresh logic ile)
- HTTP client wrapper (interceptor + refresh queue/lock)
- Router guard (protected rotalar)
- Dashboard iskeleti ve en az bir örnek protected endpoint kullanımı
- README: environment, çalışma, güvenlik ve token saklama tercihleri
Notlar / Varsayımlar
- Backend, refresh endpoint ve/veya Set-Cookie davranışını destekliyor olmalıdır. Eğer backend cookie yerine JSON refresh token dönerse prompt'ta belirtilen fallback yöntem uygulanacak.
- Exact refresh endpoint path'ı backend ile netleştirilmeli (
/auth/refresh,/auth/refresh-tokenveya benzeri). - Backend CORS + cookie kullanımında
Access-Control-Allow-Credentials: trueve client çağrılarındawithCredentials: truegerekecektir.
✅ İMPLEMENTASYON TAMAMLANDI (12 Şubat 2026)
Yukarıdaki tüm gereksinimler başarıyla implement edildi. İşte teslim edilen bileşenler:
Oluşturulan Dosyalar
Environment & Yapılandırma
.env- Environment variables.env.example- Environment templatetsconfig.app.json- TypeScript path alias yapılandırması
Core Infrastructure
src/lib/http-client.ts- Axios wrapper + interceptors (401 handling, refresh logic, retry)src/services/auth.service.ts- Auth API endpoints (login, refresh, logout)src/types/auth.types.ts- TypeScript interfaces
State Management
src/stores/auth.ts- Pinia auth store- Login/logout actions
- Refresh token logic (single promise lock)
- Proaktif token yenileme (exp check)
- Concurrent refresh prevention
UI Components
src/components/ui/Button.vue- Reusable button (variants, loading, sizes)src/components/ui/Input.vue- Reusable input (validation, error states)
Views
src/views/LoginView.vue- Modern login sayfası (Zod validation, responsive, dark mode)src/views/DashboardView.vue- Admin dashboard (user info, stats, protected content)
Router & Navigation
src/router/index.ts- Router configuration + navigation guards/login(public)/admin(protected, requires auth)
App Structure
src/App.vue- Minimal layout (sadece RouterView)
Dokümantasyon
README.md- Detaylı dokümantasyon- Token saklama stratejisi
- CORS yapılandırması
- Auth akışı diagramları
- Backend endpoint gereksinimleri
- Güvenlik best practices
Teknolojiler
- Vue 3 (Composition API)
- TypeScript
- Pinia (state management)
- Vue Router
- Axios
- Zod (validation)
- Tailwind CSS
- Lucide Icons
- SweetAlert2
- jwt-decode
Güvenlik Özellikleri
✅ Access token bellek (Pinia) depolaması ✅ HttpOnly cookie desteği (refresh token) ✅ withCredentials: true (CORS) ✅ Single refresh promise lock (concurrent prevention) ✅ Proaktif token yenileme (60s threshold) ✅ Router guards (protected routes) ✅ Form validation (Zod) ✅ XSS koruması
Test Senaryoları (Hazır)
- ✅ Başarılı login akışı
- ✅ Access token expiration & refresh
- ✅ Refresh token invalid/expired handling
- ✅ Concurrent requests (single refresh)
- ✅ Logout flow
- ✅ Protected route guards
- ✅ Proaktif yenileme
Backend Hazırlığı: Frontend tamamlandı, backend endpoint'leri (/auth/login, /auth/refresh, /auth/logout) hazır olduğunda test edilebilir.
Çalıştırma: npm run dev komutu ile başlatılabilir.