Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Microsoft Teamservice Laravel Package

socialiteproviders/microsoft-teamservice

Laravel Socialite provider for Microsoft Team Service. Adds a Microsoft Teams OAuth2 driver so you can authenticate users, request scopes, and retrieve profile data through Socialite's familiar API with minimal configuration.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and register the driver in three steps.

  1. Pull the provider. It is a subtree split of the SocialiteProviders monorepo, so Composer is the only supported entry point:
composer require socialiteproviders/microsoft-teamservice
  1. Tell Socialite the driver exists. The package ships an ExtendSocialite listener that injects the driver into the shared Socialite manager. Register it once (Laravel ≤10 EventServiceProvider::listen; Laravel 11+ use Event::listen in AppServiceProvider::boot):
Event::listen(
    \SocialiteProviders\Manager\SocialiteWasCalled::class,
    \SocialiteProviders\MicrosoftTeamService\MicrosoftTeamServiceExtendSocialite::class.'@handle'
);

If the class name above does not exist, check vendor/socialiteproviders/microsoft-teamservice/src/ — the namespace and ExtendSocialite class name are the first thing to confirm, because a typo here surfaces as Driver [microsoft-teamservice] not supported, not as a missing class.

  1. Add credentials to config/services.php:
'microsoft-teamservice' => [
    'client_id'     => env('MICROSOFT_TEAMS_CLIENT_ID'),
    'client_secret' => env('MICROSOFT_TEAMS_CLIENT_SECRET'),
    'redirect'      => env('MICROSOFT_TEAMS_REDIRECT_URI'),
    'tenant'        => env('MICROSOFT_TEAMS_TENANT', 'organizations'),
],

Where to look first. Register the app in the Azure portal (Entra ID → App registrations), add a Web platform redirect URI that matches MICROSOFT_TEAMS_REDIRECT_URI byte-for-byte, and create a client secret. Grant Microsoft Graph delegated permissions (User.Read, plus offline_access if you want refresh tokens). Nothing in the package works until the Azure side is correct — most "provider is broken" reports are actually app-registration mismatches.

First use case. The 80% scenario is internal sign-in: gate a Laravel app to your organisation's Microsoft work/school accounts and pull the user's name, email, and immutable object ID from Graph. Two routes and one controller gets you there:

Route::get('/auth/teams', fn () => Socialite::driver('microsoft-teamservice')->redirect());
Route::get('/auth/teams/callback', function () {
    $ms = Socialite::driver('microsoft-teamservice')->user();
    // $ms->getId(), ->getName(), ->getEmail(), ->token, ->refreshToken
});

Implementation Patterns

Standard redirect/callback controller. Keep the driver name in a constant so it never drifts between routes, the listener, and tests:

class TeamsAuthController extends Controller
{
    private const DRIVER = 'microsoft-teamservice';

    public function redirect()
    {
        return Socialite::driver(self::DRIVER)
            ->scopes(['offline_access', 'User.Read'])
            ->redirect();
    }

    public function callback()
    {
        $msUser = Socialite::driver(self::DRIVER)->user();

        $user = User::updateOrCreate(
            ['microsoft_id' => $msUser->getId()],   // stable, never reuse email as the key
            [
                'name'  => $msUser->getName(),
                'email' => $msUser->getEmail(),
            ]
        );

        Auth::login($user, remember: true);

        return redirect()->intended('/dashboard');
    }
}

Tenant selection is your authorisation boundary. This is the single most valuable config knob and the one most teams get wrong:

tenant value Who can sign in
common Work/school and personal Microsoft accounts
organizations Work/school accounts only (any Entra tenant)
consumers Personal accounts only
A GUID or domain A single tenant — strongest isolation

For an internal Teams tool, use your tenant GUID or organizations. Using common silently allows any Microsoft consumer account to complete the OAuth dance, so you must then reject them in the callback.

Token use for Graph. The driver returns the raw access token; subsequent Graph calls are plain HTTP with that bearer token. Wrap it so expiry handling lives in one place:

$response = Http::withToken($msUser->token)
    ->get('https://graph.microsoft.com/v1.0/me/photo/$value');

Persist $msUser->refreshToken (requires offline_access) if the app needs Graph access after the initial session, and refresh on a 401 rather than on a timer.

Account linking for existing users. When you already have a user table, don't create duplicates. Match on a verified email once, then write microsoft_id and use it exclusively from then on:

$user = User::where('email', $msUser->getEmail())->first()
     ?? User::create([...]);
$user->forceFill(['microsoft_id' => $msUser->getId()])->save();

Testing. Fake at the Socialite boundary rather than mocking Graph:

Socialite::shouldReceive('driver->user')->andReturn(
    (new \Laravel\Socialite\Two\User)->map([
        'id' => 'aad-oid-123', 'name' => 'Ada Lovelace', 'email' => '[email protected]',
    ])
);

Optional profile enrichment. Socialite::driver(...)->user() returns Socialite's standard contract; if you need job title, department, or manager, fetch /v1.0/me and /v1.0/me/manager yourself in a small GraphProfile service. Keep that out of the auth controller — it's presentation data, not identity.

Gotchas and Tips

This package is effectively frozen. Last release 2020-12-01, zero stars, single-maintainer subtree split. It works if the Microsoft endpoints it targets still respond, but expect no fixes for Laravel 10/11's Socialite changes or for PHP 8.2+ deprecation noise. Pin the version in composer.json and budget a fork plan: the source is a few hundred lines and can be vendored into app/Socialite/ in an afternoon if it ever breaks.

Raise issues upstream, not here. The repository is [READ ONLY] — a split of SocialiteProviders/Providers. PRs and issues belong in the monorepo.

Driver [...] not supported is almost always listener registration. Either the SocialiteWasCalled listener isn't registered, it's registered with the wrong class name, or config is cached. Run php artisan config:clear and php artisan event:clear before debugging anything else.

Redirect URI mismatch is the most common Azure error. Trailing slashes, http vs https, and localhost vs 127.0.0.1 all count as different URIs. Register every environment — dev, staging, prod — as separate redirect URIs on the same app registration.

getEmail() can return null. Teams/Microsoft accounts without a mailbox expose userPrincipalName instead of mail. Never assume an email; if you need one for display, fall back to userPrincipalName and store the object ID as the true identity key. Do not key users on email — aliases change.

Consent and admin approval. Requesting offline_access or any Teams-related scope beyond User.Read may require tenant admin consent; users on locked-down tenants will see Need admin approval and never reach your callback. Get consent granted at the tenant level before launch, and keep the default scope set minimal.

Client secrets expire. Azure client secrets have a maximum lifetime (typically 24 months) and expire silently. Track the expiry date next to the credential in your secret manager, or move to certificate-based credentials if the package's config allows it.

Scopes are additive, not replacing. ->scopes([...]) merges with the driver's defaults; check the driver's getScopes() in the vendor source if a permission you didn't ask for shows up on the consent screen.

Debug the OAuth round-trip in two halves. If /redirect throws, the problem is Azure config or scopes. If the callback throws, the problem is usually an expired/invalid state, a reused authorization code, or a code issued for a different redirect URI. Enable Socialite's error detail in non-production (APP_DEBUG=true) — the underlying InvalidStateException / InvalidArgumentException messages from the OAuth client are the actual signal.

Stateless mode only when you must. ->stateless() removes CSRF protection on the callback. Useful for API-driven or mobile flows, risky for browser sessions. If you use it, add your own signed-state check.

Extension point. For anything the package doesn't map — Teams-specific claims, tid, oid, job title — extend the driver and override mapUserToObject() with your own class, registering it through your own SocialiteWasCalled listener. That keeps you off the unmaintained upstream path while still using its OAuth plumbing.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core