How to use Laravel Passport with a custom username column
Stefan Bogdanescu
Founder & Senior Architect · 2026-06-29
# How to Use Laravel Passport with a Custom Username Column
When building robust authentication systems in Laravel, flexibility is key. While the default setup often relies on the `email` field for user identification, many applications benefit from using a custom field, such as a unique `username`, for public-facing login. This approach enhances the user experience while keeping the core Passport and authentication mechanisms intact.
This guide will walk you through how to adapt your existing authentication flow, specifically when integrating with Laravel Passport, to successfully use a custom username column instead of the default email address for logging in.
## The Challenge with Default Authentication
As you noted in your initial query, standard Laravel authentication methods, including those leveraged by Passport's password grant flow, are heavily optimized around established conventions (like using `email` as the unique identifier). When you use `Auth::attempt($request->only(['id', 'password']))`, the system implicitly tries to match provided credentials against the fields defined in your `users` table. If you want to log in with a username, you must explicitly tell Laravel and Passport which field to use for the lookup.
The fundamental solution involves overriding or customizing the Eloquent query that precedes the password verification step.
## Step-by-Step Implementation
To successfully authenticate using a custom `username`, you need to modify how you retrieve the user from the database before attempting the password validation.
### 1. Ensure Your Model is Ready
First, ensure your `User` model correctly reflects your database structure. If you have a `username` column:
```php
// app/Models/User.php
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
use Notifiable;
protected $fillable = [
'username', // Ensure this is included
'password',
// ... other fields
];
// ... rest of the model
}
```
### 2. Customizing the Login Attempt Logic
Instead of relying solely on the default `Auth::attempt()`, which expects an email or primary key, we will manually query the user based on the provided username and then verify the password. This gives us full control over the identifier used.
In your controller or service layer where you handle the login request:
```php
use Illuminate\Support\Facades\Auth;
use Illuminate\Http\Request;
class AuthController extends Controller
{
public function login(Request $request)
{
$request->validate([
'username' => 'required|string',
'password' => 'required',
]);
// 1. Find the user by the custom username
$user = \App\Models\User::where('username', $request->input('username'))->first();
if (!$user) {
return response()->json(['message' => 'Invalid credentials'], 401);
}
// 2. Verify the password against the found user
if (Auth::attempt([
'username' => $user->username, // Use the custom field here
'password' => $request->input('password')
], $request->filled('remember'))) {
// Authentication successful! Passport tokens will be issued accordingly.
$user = Auth::user();
// Generate token or return response for Passport grant flow
return response()->json([
'message' => 'Login successful',
'token' => $this->generateToken($user) // Placeholder for actual token generation
]);
}
return response()->json(['message' => 'Invalid credentials'], 401);
}
// Helper function (you would integrate actual Passport token logic here)
protected function generateToken($user) {
// Logic to create and return a Laravel Passport token
return 'some_unique_token';
}
}
```
## Integrating with Laravel Passport
When using the password grant flow defined in documentation like [Laravel Documentation on Passport](https://laravel.com/docs/5.3/passport#password-grant-tokens), the successful authentication step is what triggers the token issuance. By successfully calling `Auth::attempt()` after manually finding the user by their custom username, you are ensuring that the authenticated session correctly maps to your application's identity structure before Passport handles the token creation.
This approach keeps the core security mechanisms provided by Laravel Passport sound while allowing your application layer to use any identifier it deems most appropriate for front-end interaction. For deeper context on service integration within Laravel, exploring services like those offered by [laravelcompany.com](https://laravelcompany.com) can provide excellent architectural guidance.
## Conclusion
Switching from email-based authentication to username-based authentication requires moving beyond the simple default `Auth::attempt()` syntax. By manually performing the Eloquent lookup based on your custom field (like `username`) and then passing that resolved user identity into the attempt function, you gain explicit control over your login process. This method is highly flexible, secure, and ensures seamless integration with Laravel Passport by correctly establishing the authenticated user context before token generation.