Files
fitness/backend/AUTHENTICATION_API.md

3.8 KiB

مصادقة SportPath — API v1

هذه الواجهات تأسيس أولي لمصادقة رقم الهاتف. لا تشغّل إرسال OTP قبل إعداد مزود حقيقي ومراجعة عقده على بيئة sandbox. لا يخرج الرمز أو المفاتيح في response أو logs.

إعداد الخادم

ضع القيم في ملف البيئة الخاص خارج مجلد public/:

JWT_SIGNING_KEY=<random secret, at least 32 bytes>
JWT_ACCESS_TTL_SECONDS=900
JWT_REFRESH_TTL_DAYS=30
OTP_PROVIDER=generic_json
OTP_API_URL=https://provider.example/api/send
OTP_API_KEY=<server-only token>
OTP_SENDER_ID=<approved sender>
OTP_MESSAGE_TEMPLATE=رمز التحقق الخاص بك هو {code}
OTP_ENABLED=true
OTP_HASH_KEY=<independent random secret, at least 32 bytes>

المحول الحالي يرسل JSON بالشكل {"to":"+...","sender":"...","message":"..."} مع Authorization: Bearer ...، ويعد أي HTTP 2xx نجاحًا. هذا عقد عام مؤقت وليس افتراضًا عن أي مزود؛ عدّل ConfiguredHttpOtpProvider ليتوافق مع توثيق المزود الفعلي قبل تفعيل الإنتاج. يرفض endpoint العناوين غير HTTPS. في حال غياب الإعداد يبقى الطلب مغلقًا ويرجع 503.

المسارات

  • POST /api/v1/auth/request-otp.php: JSON { "phone_e164": "+962…", "purpose": "register|login", "device_uuid": "UUID" }. يرد challenge_id ومدة الصلاحية. حد الإرسال الحالي 5 لكل رقم/ساعة، 20 لكل IP/ساعة، و10 لكل device/ساعة؛ المحاولات لكل تحدٍ 5 خلال 5 دقائق.
  • POST /api/v1/auth/verify-otp.php: JSON { "challenge_id": "UUID", "code": "123456", "display_name": "…", "device_uuid": "UUID", "platform": "ios|android|web" }. يستهلك التحدي مرة واحدة ويصدر JWT وrefresh token عشوائيًا. يجب حفظ refresh token في مخزن آمن على الجهاز، وعدم تسجيل أي token.
  • POST /api/v1/auth/refresh.php: JSON { "refresh_token": "…" }. تدوير الرمز يصدر refresh جديدًا؛ إعادة استخدام رمز سبق تدويره تبطل عائلة الجلسة.
  • POST /api/v1/auth/logout.php: يتطلب Authorization: Bearer <access-token> ويبطل الجلسة الحالية.
  • /api/v1/admin/settings.php: يتطلب bearer token ودور owner أو content_manager؛ GET للقراءة وPATCH للتعديل مع audit trail.

كل Access Token قصير العمر ويرتبط بجلسة حية في MySQL. الدور وحالة الحساب يعاد التحقق منهما من قاعدة البيانات لكل طلب محمي. لا تُقبل معرفات عتادية ثابتة؛ device_uuid معرّف تثبيت عشوائي. ترقية أول مالك تتم يدويًا على قاعدة الخادم بعد التحقق من رقم الهاتف، ولا توجد واجهة bootstrap عامة لمنح دور owner.

ما لم يكتمل بعد

تطبيق Flutter مرتبط الآن بنقاط OTP والجلسات ويخزن الرموز في secure storage؛ مزامنة التمارين ترسل Bearer وتجدد الجلسة عند الحاجة. نقاط التتبع تقبل HMAC فقط إذا ضُبط LEGACY_HMAC_ENABLED=true صراحة لفترة ترحيل عميل قديم، وقيمته في المثال false. لم يُختبر اتصال MySQL الفعلي أو إرسال SMS؛ فحوص PHP/Dart حتى الآن ساكنة وتحليلية فقط. نفّذ migrations 001_phone_auth_and_sessions.sql و002_workout_idempotency.sql و003_training_content.sql على staging بعد backup، وتحقق من rate limits والتدوير والإبطال مع مزود OTP في sandbox قبل الإنتاج.