Proje: Okul B2B App · Hub: Okul B2B App — Incidents
/customer/otp/users 403 — postPublic x-consumer-key göndermiyor
Semptom
OTP çoklu kullanıcı seçimi akışında, kod doğrulama adımı olan POST https://api.okul.work/customer/otp/users çağrısı 403 döndü:
[ERROR] API Error (Public): POST .../customer/otp/users [Error: 403]
[ERROR] Resolve OTP users error [ServerError: Server error: 403]
/auth/otp (send) aynı apiClient.postPublic() ile sorunsuz çalışıyordu — sadece resolve çağrısı patladı.
Root cause
okulcom-api route gruplarında middleware farklı:
routes/api/auth.php→['api'](sadece base middleware)routes/api/customer.php→['api', 'auth:sanctum', 'platform', 'user-group-type:...']customer/otp/usersroute’uwithoutMiddleware(['auth:sanctum', 'user-group-type:...'])ile auth’u kaldırmış amaplatform(VerifyConsumerToken) middleware’ini bırakmış.- Bu middleware
x-consumer-keyheader’ını şart koşar; yoksa 403.
apiClient.postPublic() ise defaultHeaders’ı bilinçli olarak göndermiyor (utils/ApiClient.ts:148):
// Use ONLY provided headers (no defaultHeaders for public endpoints)
const requestHeaders = headers;Sonuç: x-consumer-key gitmiyor → 403.
Çözüm
AuthService.resolveOtpUsers()’da postPublic yerine post kullan. apiClient.post() defaultHeaders’ı (x-consumer-key dahil) merge eder ama Authorization sadece setAuthToken() çağrılmışsa eklenir — yani auth gerektirmeyen ama platform doğrulaması isteyen endpoint’ler için doğru seçim:
// /customer/* group requires `x-consumer-key` (platform middleware) but NOT auth.
// post() (vs postPublic) merges defaultHeaders which includes x-consumer-key.
const response = await apiClient.post<any>('/customer/otp/users', { value, code });Commit: f90a9d6 (feat(auth): OTP login çoklu kullanıcı seçimi).
Çıkarım
postPublic = “hiçbir default header gitmesin” demek. Yani Authorization + x-cid + x-consumer-key + Accept-Language + X-App-Version hepsi düşer. Sadece tamamen public, hiçbir platform doğrulaması istemeyen endpoint’lerde (örn. /auth/otp, /auth/login) kullanılır.
Auth gerekmiyor ama platform doğrulaması/locale/version header’ı gerekiyorsa → post() kullan. Auth token zaten yoksa eklenmiyor.
Related
- api-client-header-yonetimi — header yaşam döngüsü, x-consumer-key
- api-client-pattern — postPublic vs post kullanımı
- 2026-05-06-otp-multi-user-selection — bu incident’in çıktığı feature