# Admin Panel — Giriş (Login) + Refresh Token Mantığı Prompt / İş Tanımı Amaç: - Var olan `admin-panel` Vue 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 olarak `POST /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ış 1. 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. 2. Otomatik yenileme (interceptor + single-refresh lock) - Tüm korumalı isteklerde Authorization: Bearer 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. - İstek interceptor'ı 401'lerde doğrudan logout yerine önce refresh denemeli; refresh'in başarısız olması durumunda logout yapılmalı. 3. 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. 4. 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. 5. 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). - 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) 1. Başarılı login: - login -> access token alındı, refresh token cookie ile set edildi (veya sessionStorage'e kondu) -> /admin'e yönlendirme. 2. 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. 3. Refresh expired veya invalid: - Refresh attempt başarısız -> logout -> /login ve uygun hata mesajı. 4. 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. 5. Logout: - logout çağrıldığında server /auth/logout çağrılır (varsa) ve client state & storageler temizlenir. 6. 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-token` veya benzeri). - Backend CORS + cookie kullanımında `Access-Control-Allow-Credentials: true` ve client çağrılarında `withCredentials: true` gerekecektir. --- ## ✅ İ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 template - `tsconfig.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) 1. ✅ Başarılı login akışı 2. ✅ Access token expiration & refresh 3. ✅ Refresh token invalid/expired handling 4. ✅ Concurrent requests (single refresh) 5. ✅ Logout flow 6. ✅ Protected route guards 7. ✅ 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.