Skip to main content

Black Friday 2025! Only until December 1st: coupon FRIDAY25 for 40% off Yearly/Lifetime membership!

Read more here

Laravel Auth with SMS OTP (no email)

You may use the default Laravel login/registration logic using phone number instead of email, with SMS one-time passwords.

For this example, the authentication system uses phone numbers and SMS OTPs via Vonage.

The User Model is updated to store phone and OTP-related fields:

app/Models/User.php:

use Illuminate\Notifications\Notification;
 
class User extends Authenticatable
{
protected $fillable = [
'name',
'phone',
'password',
'verified_at',
'otp_code',
'otp_expires_at',
];
 
protected $hidden = [
'password',
'remember_token',
'otp_code',
];
 
protected function casts(): array
{
return [
'verified_at' => 'datetime',
'otp_expires_at' => 'datetime',
'password' => 'hashed',
];
}
 
public function routeNotificationForVonage(Notification $notification): string
{
return $this->phone;
}
}

Registration Flow

  • User submits name, phone, and password
  • Input is validated (using PhoneNumber rule)
  • User is created
  • OTP is generated and saved to otp_code and otp_expires_at
  • OTP is sent via Vonage SMS
  • User is logged in and redirected to phone verification page

app/Http/Controllers/Auth/RegisteredUserController.php:

use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;
use Illuminate\Support\Facades\URL;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Http\RedirectResponse;
use Illuminate\Validation\Rules\Password;
use App\Notifications\SendOtpNotification;
 
class RegisteredUserController extends Controller
{
// ...
 
public function store(Request $request): RedirectResponse
{
$request->validate([
'name' => ['required', 'string', 'max:255'],
'phone_full' => ['required', 'numeric', Rule::unique('users', 'phone')],
'password' => ['required', 'confirmed', Password::defaults()],
]);
 
$user = User::create([
'name' => $request->name,
'phone' => $request->phone_full,
'password' => Hash::make($request->password),
]);
 
$otp = rand(100000, 999999);
 
$user->update([
'otp_code' => $otp,
'otp_expires_at' => now()->addMinutes(10),
]);
 
$user->notify(new SendOtpNotification($otp));
 
Auth::login($user);
 
return redirect(URL::signedRoute('verification.notice'));
}
}

The notification class for...

Want to Get Access to GitHub Repository?

Unlock the complete README, installation instructions, code walkthrough, and direct access to clone the repository. Join our premium membership to access all project examples.

Full Source Code
Clone and customize
Documentation
Complete setup guides
All Examples
15 premium projects
Become a Premium Member for $129/year or $29/month