How to Use Microsoft OAuth2 with Laravel Socialite for User Authentication

Arlind Musliu cofounder at Lucky Media
Arlind Musliu

January 15, 2025 · 4 min read

How to Use Microsoft OAuth2 with Laravel Socialite for User Authentications

This article explains how to authenticate users using Microsoft if you’re building a web application with Laravel. You might notice that the official Laravel Socialite package doesn’t support Microsoft out of the box. There’s a simple way to make it work using a community package called socialiteproviders. In this guide, we’ll walk you through the steps to set up Microsoft OAuth2 in your Laravel application and we also have another guide for Google OAuth2 integration.

Besides the official Laravel Socialite package that supports Google, Facebook, X, LinkedIn, GitHub, GitLab, Bitbucket, and Slack, the community package also supports integrations like Apple, Steam, Instagram, Discord, Reddit, Snapchat, Telegram, Threads, TikTok, Yahoo, Dropbox, Twitch, Asana, Trello, Zoom, Spotify and many more.

We will also save the user’s last login method on that specific device to show it to them on their next login attempt. This will help prevent users from registering for multiple accounts with both Google and Microsoft.

microsoft google oauth login laravel socialite

Step 1: Register a Microsoft Application

To allow your app to use Microsoft OAuth2, you need to register it with Microsoft.

Create a Microsoft Azure Account

If you don’t already have one, sign up for a Microsoft Azure account and log in at portal.azure.com.

socialite microsoft azure signup laravel oath

Add a New App Registration

  • Go to "Manage Microsoft Entra ID".

  • Click on "+ Add" and select "App registration".

microsoft socialite entra id app registration laravel oath

Configure Your App

  • Choose a name for your app, like "socialite".

  • For supported account types, choose:

    • "Accounts in any organizational directory (Any Microsoft Entra ID tenant - Multitenant) and personal Microsoft accounts (e.g., Skype, Xbox)".

  • Set a Redirect URI:

socialite microsoft register an application laravel oath

Get Your Application Details

  • After creating your app, you’ll see an overview. Copy the Application (client) ID.

  • In your Laravel app, set this ID as the environment variable MICROSOFT_CLIENT_ID.

socialite microsoft oath overview laravel

Create a Client Secret

  • Click on "Add a certificate or secret" in the Client credentials section.

socialite microsoft add a secret laravel oath
  • Add a new client secret with a description like "SocialiteSecret".

  • Choose an expiration date (default or longer).

socialite microsoft add a client secret laravel oath
  • Copy the secret value (not the Secret ID) and set it as the environment variable MICROSOFT_CLIENT_SECRET in your Laravel app.

socialite microsoft copy client secret laravel oath

Step 2: Install Laravel SocialiteProviders

To enable OAuth2 authentication with providers like Microsoft in your Laravel application, you’ll need to install the Laravel community SocialiteProviders package. Follow these steps:

Install SocialiteProviders package

Use Composer to install the SocialiteProviders package:

composer require socialiteproviders/microsoft

Update Environment Variables

Add the necessary environment variables for Microsoft to your .env file. You’ll use the client IDs and secrets obtained from the project creation step above:

MICROSOFT_CLIENT_ID=your-microsoft-client-id
MICROSOFT_CLIENT_SECRET=your-microsoft-client-secret
MICROSOFT_REDIRECT_URI=http://localhost:8000/auth/microsoft/callback

Add provider event listener

With the release of Laravel 11, the standard EventServiceProvider has been removed. Now, you should register your listener by calling the listen method on the Event facade within the boot method found in your AppServiceProvider:

namespace App\Providers;

use Carbon\CarbonImmutable;
use Illuminate\Support\Facades\Date;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\ServiceProvider;
use SocialiteProviders\Manager\SocialiteWasCalled;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     */
    public function register(): void
    {
        //
    }

    /**
     * Bootstrap any application services.
     */
    public function boot(): void
    {
        Event::listen(SocialiteWasCalled::class, function (SocialiteWasCalled $event) {
            // $event->extendSocialite('google', \SocialiteProviders\Google\Provider::class);
            $event->extendSocialite('microsoft', \SocialiteProviders\Microsoft\Provider::class);
        });
    }
}

Note: We’ve commented out the code for integrating Google here. In order for this to work, you will need to have Google project credentials for your .env file as you’ll see in the next step below for Microsoft.

Step 3: Configure Laravel Backend

Update the services file

Add configurations for Microsoft OAuth services at the config/services.php file:

return [

    // Rest of the code

    'microsoft' => [
    'client_id' => env('MICROSOFT_CLIENT_ID'),
    'client_secret' => env('MICROSOFT_CLIENT_SECRET'),
    'redirect' => env('MICROSOFT_REDIRECT_URI'),
	],
];

Set Up Routing

Define routes for redirecting to Microsoft and handling the callbacks on the auth.php file:

use App\Http\Controllers\Auth\LoginUserViaSocialiteController;
use Illuminate\Support\Facades\Route;

// Rest of the code

Route::get('auth/{provider}/redirect', [LoginUserViaSocialiteController::class, 'create'])->where('provider', 'google|microsoft');
Route::get('auth/{provider}/callback', [LoginUserViaSocialiteController::class, 'store'])->where('provider', 'google|microsoft');

Create the Controller

Implement the LoginUserViaSocialiteController controller methods to handle OAuth redirection and callback:

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\Support\Facades\Auth;
use Laravel\Socialite\Facades\Socialite;

class LoginUserViaSocialiteController extends Controller
{
    public function create($provider)
    {
        // Redirect the user to the Google/Microsoft login page
        return Socialite::driver($provider)->redirect();
    }

    public function store($provider)
    {
        // Get the user from the Google/Microsoft callback
        $socialiteUser = Socialite::driver($provider)->user();

        // Check if the user exists
        $user = User::where('email', $socialiteUser->getEmail())->first();

        // If the user does not exist, do not log them in and redirect them to the login page
        if (!$user) {
            return redirect()->route('login');
        }

        // Update the user's socialite_id and socialite_token
        $user->update([
            'socialite_id' => $socialiteUser->getId(),
            'socialite_token' => $socialiteUser->token,
        ]);

        // Log the user in
        Auth::login($user);

        // Redirect the user to the dashboard
        return redirect(route('dashboard'));
    }
}

Step 4: Add Authentication Buttons in the Frontend

Create Login View

In your login view, add buttons for Microsoft login. Also, include logic to display the tooltip indicating the last used login method.

import Checkbox from '@/components/checkbox'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import InputError from '@/components/ui/input-error'
import InputLabel from '@/components/ui/input-label'
import {
  Tooltip,
  TooltipContent,
  TooltipProvider,
  TooltipTrigger,
} from '@/components/ui/tooltip'
import GuestLayout from '@/layouts/guest-layout'
import { Head, Link, useForm } from '@inertiajs/react'
import { FormEventHandler } from 'react'

import { useLocalStorage } from '@/hooks/useLocalStorage'
import SVG from 'react-inlinesvg'

export default function Login({
  status,
  canResetPassword,
}: {
  status?: string
  canResetPassword: boolean
}) {
  const { data, setData, post, processing, errors, reset } = useForm({
    email: '',
    password: '',
    remember: false,
  })

  const { setItem, getItem } = useLocalStorage('lastLoginMethod')

  const submit: FormEventHandler = (e) => {
    e.preventDefault()

    post(route('login'), {
      onFinish: () => {
        reset('password')
        setItem('Email')
      },
    })
  }

  const handleSocialLogin = (
    e: React.MouseEvent<HTMLSpanElement>,
    method: string,
    url: string
  ) => {
    e.preventDefault()

    setItem(method)
    window.location.href = url
  }

  return (
    <GuestLayout>
      <Head title="Log in" />

      {status && (
        <div className="mb-4 text-center font-medium text-green-600 text-sm">
          {status}
        </div>
      )}

      <div className="mx-auto flex w-full flex-col justify-center space-y-6 sm:w-[350px]">
        <div className="flex flex-col space-y-2 text-center">
          <h1 className="font-semibold text-2xl tracking-tight">
            Log in to your account
          </h1>
          <p className="text-muted-foreground text-sm">
            Enter your email below to create your account
          </p>
        </div>

        <div className="grid gap-6">
          <form onSubmit={submit}>
            <div className="grid gap-2">
              <InputLabel htmlFor="email" value="Email" className="sr-only" />
              <Input
                id="email"
                type="email"
                name="email"
                value={data.email}
                placeholder="name@example.com"
                className="mt-1 block w-full"
                autoCapitalize="none"
                autoComplete="email"
                autoCorrect="off"
                onChange={(e) => setData('email', e.target.value)}
              />
              <InputError message={errors.email} className="mt-2" />
            </div>

            <div className="mt-4">
              <InputLabel
                htmlFor="password"
                value="Password"
                className="sr-only"
              />
              <Input
                id="password"
                type="password"
                name="password"
                value={data.password}
                className="mt-1 block w-full"
                autoComplete="current-password"
                onChange={(e) => setData('password', e.target.value)}
              />
              <InputError message={errors.password} className="mt-2" />
            </div>

            <div className="mt-4 block">
              <label
                htmlFor="remember"
                className="flex items-center justify-between"
              >
                <div>
                  <Checkbox
                    name="remember"
                    checked={data.remember}
                    onChange={(e) => setData('remember', e.target.checked)}
                  />
                  <span className="ms-2 text-gray-600 text-sm">
                    Remember me
                  </span>
                </div>
                {canResetPassword && (
                  <Link
                    href={route('password.request')}
                    className="rounded-md text-gray-600 text-sm underline hover:text-gray-900 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
                  >
                    Forgot your password?
                  </Link>
                )}
              </label>
            </div>

            <LastLoginMethod defaultOpen={getItem() === 'Email'}>
              <Button className="mt-4 w-full" disabled={processing}>
                Sign In with Email
              </Button>
            </LastLoginMethod>
          </form>

          <div className="relative">
            <div className="absolute inset-0 flex items-center">
              <span className="w-full border-t" />
            </div>
            <div className="relative flex justify-center text-xs uppercase">
              <span className="bg-background px-2 text-muted-foreground">
                Or continue with
              </span>
            </div>
          </div>

          <div className="flex flex-col space-y-2">
            <LastLoginMethod defaultOpen={getItem() === 'Google'}>
              <Button
                asChild
                type="button"
                variant="outline"
                className="w-full"
                onClick={(e) =>
                  handleSocialLogin(e, 'Google', '/auth/google/redirect')
                }
              >
                <span className="hover:cursor-pointer">
                  <SVG src="/svg/google.svg" className="mr-2 size-5" />
                  Login with Google
                </span>
              </Button>
            </LastLoginMethod>

            <LastLoginMethod defaultOpen={getItem() === 'Microsoft'}>
              <Button
                asChild
                type="button"
                variant="outline"
                className="w-full"
                onClick={(e) =>
                  handleSocialLogin(e, 'Microsoft', '/auth/microsoft/redirect')
                }
              >
                <span className="hover:cursor-pointer">
                  <SVG src="/svg/microsoft.svg" className="mr-2 size-5" />
                  Login with Microsoft
                </span>
              </Button>
            </LastLoginMethod>

            {getItem() !== undefined ? (
              <p className="my-4 text-center font-medium text-gray-600 text-sm">
                Your last login method was with: {getItem()}
              </p>
            ) : null}
          </div>
        </div>
      </div>
    </GuestLayout>
  )
}

Store and Retrieve User’s Last Login Method:

  • When a user logs in via any method, store their choice (Google, Microsoft, or email) in the session or user profile.

  • Display this information as a tooltip or message in the login view.

This component uses a tooltip to provide feedback on the last used login method.

const LastLoginMethod = ({
  children,
  defaultOpen,
}: {
  children: React.ReactElement
  defaultOpen: boolean
}) => {
  return (
    <TooltipProvider>
      <Tooltip defaultOpen={defaultOpen}>
        <TooltipTrigger asChild>{children}</TooltipTrigger>
        <TooltipContent side="right">
          <p>Last used</p>
        </TooltipContent>
      </Tooltip>
    </TooltipProvider>
  )
}

Conclusion

By following these steps, you can successfully integrate Microsoft OAuth2 into your Laravel application using the community package SocialiteProviders, allowing users to log in with their Microsoft accounts. This setup not only makes the login process smoother but also enhances the security of your app.


Bring Your Ideas to Life 🚀

If you need help with a Laravel project let’s get in touch.

Lucky Media is proud to be recognized as a leading Laravel Development Agency

Technologies

Laravel
Arlind Musliu cofounder at Lucky Media
Arlind Musliu

Cofounder and CFO of Lucky Media

Stay up-to-date

Be updated with all news, products and tips we share!

Let’s chat

We partner with a limited number of brands each quarter to ensure senior-level attention on every project.

lokman and arlind headshots
Teamwork