To add "Sign in with Microsoft" to a Laravel 13 app, install laravel/socialite plus the community socialiteproviders/microsoft driver, register the driver in a service provider, add your Entra ID (Azure) app credentials to config/services.php, and create a redirect route and a callback route. The callback finds or creates a local user and logs them in. Below is the flow step by step.
Microsoft is not one of the built-in Socialite drivers. The official docs list Facebook, X, LinkedIn, Google, GitHub, GitLab, Bitbucket and Slack, and point to the community Socialite Providers project for everything else. That is why one extra package is needed.
How does the Microsoft login flow work?
Your app sends the browser to Microsoft with your client ID and redirect URI. The user signs in and approves. Microsoft redirects back to your callback route with a code. Socialite exchanges that code for the user profile, and your controller maps the profile to a row in the users table. Two routes and one controller are all the application code you need.
What do I need before I start?
- Laravel 13.x on PHP 8.3 or newer (Laravel 12 also works on PHP 8.2 or newer; the steps are the same).
- A working login setup and a
userstable. - A Microsoft Entra ID app registration with a client ID, a client secret and a redirect URI such as
https://your-app.test/auth/microsoft/callback. - Composer access to the project.
Step 1: How do I install the packages?
composer require laravel/socialite
composer require socialiteproviders/microsoftStep 2: How do I register the Microsoft driver?
Since Laravel 11 there is no default EventServiceProvider, so register the listener in the boot method of app/Providers/AppServiceProvider.php:
use Illuminate\Support\Facades\Event;
use SocialiteProviders\Manager\SocialiteWasCalled;
use SocialiteProviders\Microsoft\Provider;
public function boot(): void
{
Event::listen(function (SocialiteWasCalled $event) {
$event->extendSocialite('microsoft', Provider::class);
});
}Step 3: Where do the credentials go?
Add a microsoft entry to config/services.php. The tenant key decides who may sign in: common, organizations, consumers, or one specific tenant ID.
'microsoft' => [
'client_id' => env('MICROSOFT_CLIENT_ID'),
'client_secret' => env('MICROSOFT_CLIENT_SECRET'),
'redirect' => env('MICROSOFT_REDIRECT_URI'),
'tenant' => env('MICROSOFT_TENANT_ID', 'common'),
],Then set the values in .env. Never commit the secret.
MICROSOFT_CLIENT_ID=your-application-id
MICROSOFT_CLIENT_SECRET=your-client-secret-value
MICROSOFT_REDIRECT_URI=https://your-app.test/auth/microsoft/callback
MICROSOFT_TENANT_ID=commonStep 4: How do I store the Microsoft account?
Add a nullable, unique microsoft_id column to users and allow it in the model. I match on the provider ID, not on the email, because an email can change or be reused.
php artisan make:migration add_microsoft_id_to_users_table --table=users
// inside up():
$table->string('microsoft_id')->nullable()->unique();Add 'microsoft_id' to the $fillable array of the User model.
Step 5: What do the routes and controller look like?
use App\Http\Controllers\Auth\MicrosoftController;
Route::get('/auth/microsoft/redirect', [MicrosoftController::class, 'redirect']);
Route::get('/auth/microsoft/callback', [MicrosoftController::class, 'callback']);namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Str;
use Laravel\Socialite\Facades\Socialite;
class MicrosoftController extends Controller
{
public function redirect(): RedirectResponse
{
return Socialite::driver('microsoft')->redirect();
}
public function callback(): RedirectResponse
{
$remote = Socialite::driver('microsoft')->user();
$user = User::updateOrCreate(
['microsoft_id' => $remote->getId()],
[
'name' => $remote->getName() ?? $remote->getEmail(),
'email' => $remote->getEmail(),
'password' => Str::random(40),
]
);
Auth::login($user, remember: true);
return redirect()->intended('/dashboard');
}
}I ran php -l on this controller to confirm it has no syntax errors. I did not run a live Microsoft sign-in for this article, so test the full flow in your own tenant.
One caution: updateOrCreate as written overwrites the password on every login. In a real app, set the random password only when the user is first created, for example with firstOrNew, so an existing password is never touched.
How do I test the flow?
- Open
/auth/microsoft/redirectin a browser. You should land on the Microsoft sign-in page. - Sign in and approve. Microsoft sends you to your callback URL.
- Confirm a row exists in
userswith yourmicrosoft_id, and that you reach/dashboardlogged in. - Sign in a second time and confirm no duplicate row is created.
Recent Socialite versions also provide Socialite::fake() for feature tests, which lets you test your callback without calling the provider. Check the Socialite testing docs for the current syntax and confirm it works with a community driver before relying on it.
What should I check before going to production?
- Use an HTTPS redirect URI and register the production URI in Entra ID separately from your local one.
- Keep the client secret in environment variables or a secrets manager, and note its expiry date. Microsoft secrets expire, so plan a rotation.
- Decide what happens when a Microsoft account email already exists locally. Linking silently can be an account takeover risk, so ask the user to confirm first.
- Request only the scopes you need.
What are the common mistakes?
- Redirect URI mismatch. The URI in Entra ID, in
.envand in your route must match exactly, includinghttpsand the path. - Using the secret ID instead of the secret value. Entra ID shows the value only once, when you create it.
- Wrong tenant. A single-tenant app registration rejects
common. Use the matching tenant ID. - Forgetting the listener. Without it, Socialite reports that the driver is not supported.
- Matching users by email only. That can merge or hijack accounts. Prefer the provider ID.
- Stale config. Run
php artisan config:clearafter editing.envif config is cached.
FAQ
Is there a built-in Microsoft driver in Socialite?
No. Microsoft comes from the community Socialite Providers package, which plugs into Socialite through the event listener shown above.
Can I allow only my company accounts?
Yes. Set MICROSOFT_TENANT_ID to your tenant ID, or use organizations to allow any work or school account.
Does this work for APIs without sessions?
Socialite offers a stateless() method for stateless APIs. You then issue your own token, for example with Sanctum, after the user is resolved.



