Microsoft Entra ID (Azure AD) SSO authentication package for Laravel using OAuth2 + OpenID Connect.
- PHP 8.3, 8.4, or 8.5
- Laravel 13
- A Microsoft Entra app registration
composer require codebar-ag/laravel-microsoft-entra-ssoPublish config (optional, recommended):
php artisan vendor:publish --tag=microsoft-entra-sso-configPublish package translations (recommended if you want to customize text or add locales):
php artisan vendor:publish --tag=microsoft-entra-sso-translationsSet these environment variables:
MICROSOFT_ENTRA_SSO_TENANT_ID=your-tenant-id
MICROSOFT_ENTRA_SSO_CLIENT_ID=your-client-id
MICROSOFT_ENTRA_SSO_CLIENT_SECRET=your-client-secret
MICROSOFT_ENTRA_SSO_REDIRECT_URI=${APP_URL}/sso/microsoft/web/callbackConfigure guards in config/microsoft-entra-sso.php:
'guards' => [
'web' => [
'model' => App\Models\User::class,
'redirect_after_login' => '/dashboard',
],
],The configured model must implement CodebarAg\MicrosoftEntraSSO\Contracts\SSOAuthenticatable (typically via the HasMicrosoftSSO trait).
The package supports additional hardening options:
'stateless' => false,
'state_ttl_seconds' => 300,
'allowed_redirect_hosts' => ['example.com', 'localhost'],stateless: skips session-bound state validation (useful for API/mobile callback workflows).state_ttl_seconds: rejects stale OAuth state values.allowed_redirect_hosts: prevents redirect URI host misuse.
OAuth and Graph calls can be tuned:
'http' => [
'timeout' => 10,
'connect_timeout' => 5,
'retry_times' => 1,
'retry_sleep_ms' => 200,
],Use these values to set environment-specific resiliency for slow networks or transient upstream failures.
The package registers two routes under the configured prefix (sso/microsoft by default):
GET /sso/microsoft/{guard}/redirect->RedirectToMicrosoftController(invokable)GET /sso/microsoft/{guard}/callback->HandleMicrosoftCallbackController(invokable)
Named routes remain:
microsoft-entra-sso.redirectmicrosoft-entra-sso.callback
The facade resolves a manager/factory contract and supports driver resolution similar to Socialite:
use CodebarAg\MicrosoftEntraSSO\Facades\MicrosoftEntraSSO;
$provider = MicrosoftEntraSSO::driver('microsoft');Under the hood the provider offers:
getAuthorizationUrl($state, $codeVerifier)exchangeCodeForTokens($code, $codeVerifier)getUserFromToken($token)refreshAccessToken($refreshToken)
Resolve the OAuth provider via facade/manager:
use CodebarAg\MicrosoftEntraSSO\Facades\MicrosoftEntraSSO;
$provider = MicrosoftEntraSSO::driver('microsoft');Resolve services directly from the container:
use CodebarAg\MicrosoftEntraSSO\Services\MicrosoftOAuthService;
use CodebarAg\MicrosoftEntraSSO\Services\MicrosoftGraphService;
$oauth = app(MicrosoftOAuthService::class);
$graph = app(MicrosoftGraphService::class);stateless(bool $stateless = true): static- enable/disable session-less callback validation mode.getAuthorizationUrl(string $state, string $codeVerifier): string- build Microsoft authorize URL.exchangeCodeForTokens(string $code, string $codeVerifier): SSOToken- exchange callback code for tokens.getUserFromToken(string $accessToken): SSOUser- fetch current Microsoft user profile from Graph/me.refreshAccessToken(string $refreshToken): SSOToken- refresh an expired/expiring token.setRedirectUri(string $uri): static- override redirect URI at runtime.getRedirectUri(): ?string- inspect current redirect URI.
Static helpers on MicrosoftOAuthService:
generateState(): string- generate random OAuth state.generateCodeVerifier(): string- generate PKCE verifier.generateCodeChallenge(string $codeVerifier): string- derive PKCE S256 challenge.
getUserProfile(SSOAuthenticatable $user): array- extended profile fields from Microsoft Graph.getUserGroups(SSOAuthenticatable $user): Collection- all Azure AD groups for the user (handles pagination).getUserPhotoDataUri(SSOAuthenticatable $user): ?string- profile photo as data URI (nullwhen missing).isUserInGroup(SSOAuthenticatable $user, string $groupId): bool- efficient membership check (cache-aware).
findByMicrosoftId(string $microsoftId): ?staticfindOrCreateFromMicrosoft(array $microsoftUser): staticlinkMicrosoftAccount(array $microsoftUser): voidupdateMicrosoftTokens(array $microsoftUser): voidhasMicrosoftSSOLinked(): boolisMicrosoftTokenExpired(): boolunlinkMicrosoftAccount(): void
SSOToken helpers:
fromArray(array $payload): SSOTokentoArray(): array
SSOUser helpers:
fromGraphPayload(array $graphPayload): SSOUserwithToken(SSOToken $token): SSOUsertoArray(): array
Use the bundled button component in your login view:
<x-microsoft-entra-sso::sso-button guard="web" />You can override the label with a translation key:
<x-microsoft-entra-sso::sso-button
guard="web"
label="microsoft-entra-sso.button.sign_in"
/>The package ships with JSON translations for:
lang/en.jsonlang/de.json
After publishing (microsoft-entra-sso-translations), you can:
- edit existing keys in your application's
lang/en.jsonandlang/de.json - add additional locales by creating files like
lang/fr.jsonwith the same keys - set
APP_LOCALE(and optionallyAPP_FALLBACK_LOCALE) to control runtime language
This package does not require Flux or any frontend UI dependency.
If you use the provided Blade component styles, ensure Tailwind v4 scans the package classes. Add a source path in your app stylesheet:
@import "tailwindcss";
@source "../../packages/codebar-ag/laravel-microsoft-entra-sso/resources/views/**/*.blade.php";If your package is installed from vendor/, point @source at the vendor path instead:
@import "tailwindcss";
@source "../../vendor/codebar-ag/laravel-microsoft-entra-sso/resources/views/**/*.blade.php";Alternative: publish views and scan resources/views/vendor/microsoft-entra-sso/**/*.blade.php.
The package dispatches:
CodebarAg\MicrosoftEntraSSO\Events\SSOUserRegisteredCodebarAg\MicrosoftEntraSSO\Events\SSOUserAuthenticated
Both events are emitted during the callback flow after the package authenticates or registers a user.
You can listen to these events to add:
- custom provisioning
- role/group synchronization
- audit logging
microsoft_entra_sso_errorin session:- Check Entra app credentials and callback URL.
- Ensure guard exists in
config/microsoft-entra-sso.php. - Ensure your app has a
loginroute (or fallback redirect handling in your app). - If state errors occur, verify callback happens within
state_ttl_seconds.
- Button appears unstyled:
- Verify Tailwind v4
@sourceincludes package Blade view paths. - Rebuild frontend assets after changing Tailwind sources.
- Verify Tailwind v4
Run linting:
composer lintRun static analysis:
composer analysecomposer analyse runs PHPStan/Larastan using phpstan.neon.dist at level 9.
Run package tests:
composer testRun coverage with enforced minimum:
composer test-coverage