Files

93 lines
2.9 KiB
PHP

<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Http\Helpers\ApiResponse;
use App\Mail\TwoFactorOtp;
use App\Services\Auth\OtpService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
use OpenApi\Attributes as OA;
class OtpController extends Controller
{
public function __construct(protected OtpService $otpService) {}
#[OA\Post(
path: '/v1/otp/send',
operationId: 'otpSend',
tags: ['OTP'],
summary: 'Send a 6-digit OTP to the given email',
requestBody: new OA\RequestBody(
required: true,
content: new OA\JsonContent(
required: ['email'],
properties: [new OA\Property(property: 'email', type: 'string', format: 'email')]
)
),
responses: [
new OA\Response(response: 200, description: 'OTP sent'),
new OA\Response(response: 500, description: 'Mail delivery failed'),
]
)]
public function send(Request $request)
{
$request->validate([
'email' => 'required|email',
]);
$email = $request->email;
$code = $this->otpService->generate($email);
try {
Mail::to($email)->send(new TwoFactorOtp(
otp: $code,
ipAddress: $request->ip(),
userAgent: $request->userAgent(),
));
} catch (\Throwable $e) {
Log::error('OTP send failed', ['email' => $email, 'error' => $e->getMessage()]);
return ApiResponse::serverError('Failed to send OTP. Please try again later.');
}
return ApiResponse::success(null, 'OTP has been sent to your email');
}
#[OA\Post(
path: '/v1/otp/verify',
operationId: 'otpVerify',
tags: ['OTP'],
summary: 'Verify an OTP code',
requestBody: new OA\RequestBody(
required: true,
content: new OA\JsonContent(
required: ['email', 'code'],
properties: [
new OA\Property(property: 'email', type: 'string', format: 'email'),
new OA\Property(property: 'code', type: 'string', minLength: 6, maxLength: 6, example: '123456'),
]
)
),
responses: [
new OA\Response(response: 200, description: 'OTP verified'),
new OA\Response(response: 422, description: 'Invalid or expired OTP'),
]
)]
public function verify(Request $request)
{
$request->validate([
'email' => 'required|email',
'code' => 'required|string|size:6',
]);
if (! $this->otpService->verify($request->input('email'), $request->input('code'))) {
return ApiResponse::error('Invalid or expired OTP code', 422);
}
return ApiResponse::success(null, 'OTP verified successfully');
}
}