آزمایشی · وب‌سرویس‌ها

وب‌سرویس‌های Auth Push آزمایشی

مرجع ساده و کامل درخواست‌های سروری Auth Push؛ ثبت دستگاه مورد اعتماد، ساخت درخواست ورود، بررسی نتیجه و حذف اعتماد دستگاه.

POST
https://pushfa.com/api/webservices/auth-push/*
دانلود کالکشن Postman

قبل از استفاده این نکات را بدانید

همه درخواست‌های این صفحه باید از سرور سایت شما فرستاده شوند. هر درخواست به کلید عمومی و کلید خصوصی همان سرویس نیاز دارد. شناسه واقعی کاربر را از دیتابیس یا نشست معتبر خودتان بردارید و هیچ‌وقت اجازه ندهید مرورگر آزادانه آن را تعیین کند.

این قابلیت هنوز آزمایشی است. کلید خصوصی را فقط در Secret Manager یا متغیر محیطی سرور نگه دارید و روش ورود پیامکی فعلی را به‌عنوان مسیر جایگزین حفظ کنید.
مسیربه زبان ساده چه کاری می‌کند؟
POST /auth-push/bind دستگاه فعلی را به‌عنوان دستگاه مورد اعتماد یک کاربر ثبت می‌کند.
POST /auth-push/unbind اعتماد دستگاه را برمی‌دارد و درخواست‌های باز آن را باطل می‌کند.
POST /auth-push/challenges یک درخواست کوتاه‌مدت برای تأیید مستقیم یا کد شش‌رقمی می‌سازد.
POST /auth-push/grants/consume مجوز یک‌بارمصرف را بررسی می‌کند تا سرور بتواند کاربر را وارد کند.

ترتیب معمول فراخوانی وب‌سرویس‌ها

ثبت دستگاه مورد اعتماد

بعد از ورود معتبر کاربر، سرور مسیر bind را صدا می‌زند.

ساخت درخواست ورود

در ورود بعدی، سرور با challenges یک درخواست کوتاه‌مدت می‌سازد.

انتظار برای پاسخ کاربر

مرورگر با SDK منتظر تأیید یا ورود کد می‌ماند.

بررسی نتیجه نهایی

سرور Grant را با grants/consume بررسی می‌کند و سپس نشست ورود را می‌سازد.

حذف اعتماد در زمان لازم

در خروج یا حذف دستگاه، سرور مسیر unbind را فراخوانی می‌کند.

۲. ثبت دستگاه به‌عنوان دستگاه مورد اعتماد

POST
https://pushfa.com/api/webservices/auth-push/bind
این درخواست را فقط بعد از ورود معتبر کاربر بفرستید. هنگام خروج از حساب، حذف دستگاه یا لغو نشست، اعتماد دستگاه را با unbind بردارید.
فیلدتوضیحالزام
api_public_key کلید عمومی سرویس بله
api_private_key کلید خصوصی سرویس؛ فقط Backend بله
subscriber_id شناسه پایدار دستگاهی که کاربر روی آن احراز هویت شده است بله
auth_identity شناسه داخلی و پایدار کاربر در سیستم شما؛ مانند user UUID بله
curl -X POST https://pushfa.com/api/webservices/auth-push/bind \
  -H "Content-Type: application/json" \
  -d '{
    "api_public_key": "YOUR_PUBLIC_KEY",
    "api_private_key": "YOUR_PRIVATE_KEY",
    "subscriber_id": "DEVICE_SUBSCRIBER_UUID",
    "auth_identity": "YOUR_USER_UUID"
  }'

نمونه اتصال دستگاه در Laravel

در این نمونه، UUID کاربر از نشست احراز هویت‌شده گرفته می‌شود و مرورگر اجازه تعیین هویت کاربر را ندارد.

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;

Route::post('/account/trusted-device', function (Request $request) {
    $data = $request->validate(['subscriber_id' => ['required', 'uuid']]);

    Http::asJson()->post('https://pushfa.com/api/webservices/auth-push/bind', [
        'api_public_key' => config('services.pushfa.public_key'),
        'api_private_key' => config('services.pushfa.private_key'),
        'subscriber_id' => $data['subscriber_id'],
        'auth_identity' => $request->user()->uuid,
    ])->throw();

    return response()->json(['trusted' => true]);
})->middleware('auth');

۳. ساخت درخواست کوتاه‌مدت ورود

POST
https://pushfa.com/api/webservices/auth-push/challenges

سرور سایت شناسه کاربر و شناسه دستگاهی را که منتظر ورود است برای پوشفا می‌فرستد. پوشفا به همان دستگاه اعلان نمی‌فرستد و حداکثر پنج دستگاه فعال دیگر کاربر را انتخاب می‌کند. روش درخواست می‌تواند تأیید مستقیم یا کد شش‌رقمی باشد.

پاسخ شامل شناسه درخواست، توکن کوتاه‌مدت Client، زمان پایان و تعداد دستگاه‌های مقصد است. اگر دستگاه مناسبی پیدا نشود، fallback_required=true برمی‌گردد تا سرور بتواند ورود با پیامک را آغاز کند.
فیلدتوضیحالزام
api_public_key / api_private_key کلیدهای سرویس بله
auth_identity همان شناسه داخلی استفاده‌شده هنگام bind بله
requester_subscriber_id Subscriber ID دستگاهی که منتظر ورود است بله
mode approval برای تأیید روی دستگاه دیگر یا otp برای نمایش کد روی دستگاه دیگر خیر؛ پیش‌فرض approval
expires_in زمان اعتبار بین ۶۰ تا ۳۰۰ ثانیه خیر؛ پیش‌فرض ۱۲۰
reference شناسه داخلی درخواست در Backend شما خیر
context[ip/device/location] اطلاعاتی که در صفحه تأیید به کاربر نمایش داده می‌شود خیر
curl -X POST https://pushfa.com/api/webservices/auth-push/challenges \
  -H "Content-Type: application/json" \
  -d '{
    "api_public_key": "YOUR_PUBLIC_KEY",
    "api_private_key": "YOUR_PRIVATE_KEY",
    "auth_identity": "YOUR_USER_UUID",
    "requester_subscriber_id": "REQUESTER_SUBSCRIBER_UUID",
    "mode": "approval",
    "expires_in": 120
  }'

نمونه Endpoint شروع ورود در Backend

Backend ابتدا کاربر را با شماره موبایل یا شناسه ورود پیدا می‌کند، auth_identity واقعی را از دیتابیس خودش برمی‌دارد و Challenge را می‌سازد. api_private_key هرگز در پاسخ مرورگر قرار نمی‌گیرد.

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;

Route::post('/auth/push/start', function (Request $request) {
    $data = $request->validate([
        'username' => ['required', 'string'],
        'subscriber_id' => ['required', 'uuid'],
        'mode' => ['nullable', 'in:approval,otp'],
    ]);

    $user = User::where('username', $data['username'])->firstOrFail();
    $response = Http::asJson()->post(
        'https://pushfa.com/api/webservices/auth-push/challenges',
        [
            'api_public_key' => config('services.pushfa.public_key'),
            'api_private_key' => config('services.pushfa.private_key'),
            'auth_identity' => $user->uuid,
            'requester_subscriber_id' => $data['subscriber_id'],
            'mode' => $data['mode'] ?? 'approval',
            'expires_in' => 120,
            'reference' => (string) $user->uuid,
            'context' => [
                'ip' => $request->ip(),
                'device' => $request->userAgent(),
            ],
        ]
    );

    if ($response->status() === 422) {
        return response()->json(['fallback_required' => true], 422);
    }

    return response()->json($response->throw()->json('data'));
})->middleware('throttle:5,1');

۶. بررسی مجوز یک‌بارمصرف و ورود کاربر

POST
https://pushfa.com/api/webservices/auth-push/grants/consume

بعد از تأیید، SDK یک Grant کوتاه‌عمر برمی‌گرداند. مرورگر آن را برای سرور سایت می‌فرستد. سرور با کلید خصوصی اعتبار Grant و کاربر مربوط به آن را بررسی می‌کند و فقط پس از دریافت verified=true نشست ورود را می‌سازد.

Grant فقط یک بار، پیش از پایان زمان و برای همان کاربر قابل استفاده است. Cookie یا Access Token را تنها پس از verified=true صادر کنید.
فیلدتوضیحالزام
api_public_key / api_private_key کلیدهای سرویس بله
challenge_id شناسه Challenge بله
grant Grant دریافتی فقط پس از تأیید بله
auth_identity شناسه داخلی کاربری که قرار است وارد شود بله
curl -X POST https://pushfa.com/api/webservices/auth-push/grants/consume \
  -H "Content-Type: application/json" \
  -d '{
    "api_public_key": "YOUR_PUBLIC_KEY",
    "api_private_key": "YOUR_PRIVATE_KEY",
    "challenge_id": "CHALLENGE_UUID",
    "grant": "ONE_TIME_GRANT",
    "auth_identity": "YOUR_USER_UUID"
  }'

نمونه تکمیل Login در Backend

Route::post('/auth/push/complete', function (Request $request) {
    $data = $request->validate([
        'challenge_id' => ['required', 'uuid'],
        'grant' => ['required', 'string', 'size:64'],
    ]);

    // نگاشت Challenge به کاربر باید در state امن Backend شما نگهداری شود.
    $user = resolveUserForChallenge($data['challenge_id']);
    $verified = Http::asJson()->post(
        'https://pushfa.com/api/webservices/auth-push/grants/consume',
        [
            'api_public_key' => config('services.pushfa.public_key'),
            'api_private_key' => config('services.pushfa.private_key'),
            'challenge_id' => $data['challenge_id'],
            'grant' => $data['grant'],
            'auth_identity' => $user->uuid,
        ]
    )->throw()->json('data.verified');

    abort_unless($verified === true, 401);
    auth()->login($user);
    $request->session()->regenerate();

    return response()->json(['redirect_to' => '/dashboard']);
});

حذف اعتماد دستگاه

POST
https://pushfa.com/api/webservices/auth-push/unbind

هنگام خروج از حساب، لغو نشست، تغییر مالک دستگاه یا حذف آن از فهرست دستگاه‌ها، سرور باید اعتماد آن دستگاه را بردارد. این کار درخواست‌های باز و مجوزهای استفاده‌نشده مرتبط را نیز باطل می‌کند.

curl -X POST https://pushfa.com/api/webservices/auth-push/unbind \
  -H "Content-Type: application/json" \
  -d '{
    "api_public_key": "YOUR_PUBLIC_KEY",
    "api_private_key": "YOUR_PRIVATE_KEY",
    "subscriber_id": "DEVICE_SUBSCRIBER_UUID"
  }'

چک‌لیست امنیتی Production

کنترلالزام
کلید خصوصی فقط در Secret Manager یا متغیر محیطی Backend نگهداری شود.
مالکیت هویت auth_identity فقط از دیتابیس و نشست معتبر Backend استخراج شود، نه از ورودی مرورگر.
نگاشت Challenge Challenge را در Backend به همان تلاش ورود و همان کاربر متصل کنید.
Session fixation پس از مصرف Grant، شناسه Session را regenerate کنید.
Rate limit روی endpointهای داخلی start و complete علاوه بر محدودیت پوشفا، محدودیت IP و حساب اعمال کنید.
نمایش درخواست IP، نوع دستگاه و موقعیت تقریبی را برای تشخیص درخواست ناشناس به کاربر نشان دهید.
Fallback fallback پیامک را فقط پس از لغو Challenge قبلی آغاز کنید.
Logout و revoke در خروج، حذف نشست و تغییر مالک دستگاه، unbind را فراموش نکنید.
ثبت رویداد نتیجه نهایی را بدون ذخیره OTP، client_token، Grant یا api_private_key در audit log ثبت کنید.

خطاها و رفتار مورد انتظار Backend

حالتتفسیراقدام
422 + fallback_required دستگاه واجد شرایط وجود ندارد یا ارسال امن ممکن نیست. Challenge را خطای سیستمی تلقی نکنید و fallback را آغاز کنید.
401/403 کلیدها، مالکیت سرویس یا دسترسی معتبر نیست. درخواست را متوقف و تنظیم Secret/Service را بررسی کنید.
expired/rejected/cancelled Challenge دیگر قابل تکمیل نیست. Grant یا client_token قبلی را استفاده نکنید.
consumed Grant قبلاً یک بار مصرف شده است. Session قبلی را بررسی و از مصرف دوباره جلوگیری کنید.
429 محدودیت نرخ اعمال شده است. Backoff و محدودیت داخلی IP/Account را رعایت کنید.
Ctrl+I