Microsoft 365 and Azure AD authentication provider for Winter.SSO.
Allow your backend users to sign in using their Microsoft accounts, including:
- Microsoft 365 (formerly Office 365) work or school accounts
- Azure Active Directory (Azure AD / Entra ID) accounts
- Personal Microsoft accounts (@outlook.com, @live.com, @hotmail.com)
- Multi-tenant support: Allow users from any Microsoft 365 organization
- Single-tenant support: Restrict to your specific Azure AD tenant
- Flexible account types: Work/school accounts, personal accounts, or both
- Tenant information: Optionally retrieve tenant details for verification
- User roles/groups: Access Microsoft 365 group memberships via
.getRoles() - Profile photos: Automatically fetch user avatars
- Refresh tokens: Support for
offline_accessscope
composer require winter/wn-ssoprovidermicrosoft-plugin- Winter CMS v1.2+
- PHP 8.0.2+
- Winter.SSO plugin
- Azure AD application (or Microsoft 365 tenant)
- Go to Azure Portal
- Navigate to Azure Active Directory → App registrations
- Click New registration
- Configure:
- Name: Your Application Name
- Supported account types:
- Multi-tenant (public): "Accounts in any organizational directory and personal Microsoft accounts"
- Single-tenant (private): "Accounts in this organizational directory only"
- Redirect URI:
https://example.com/backend/winter/sso/handle/callback/microsoft
- Click Register
- Copy the Application (client) ID
- Go to Certificates & secrets → New client secret
- Create and copy the secret Value (not the Secret ID)
See Detailed Setup Guide for screenshots and step-by-step instructions.
Add to your .env file:
MICROSOFT_CLIENT_ID=your_application_client_id
MICROSOFT_CLIENT_SECRET=your_client_secret_value
# Tenant configuration (default: 'common')
# 'common' = any Microsoft account (multi-tenant)
# 'organizations' = work/school accounts only
# 'consumers' = personal Microsoft accounts only
# Or use your specific tenant ID for single-tenant
MICROSOFT_TENANT=commonCreate or edit config/winter/sso/config.php:
<?php
return [
'enabled_providers' => [
'microsoft',
],
];- Visit
/backend/auth/signin - Click "Sign in with Microsoft"
- Authenticate with your Microsoft account
- You should be logged in to the Winter CMS backend!
Allow users from any Microsoft 365 organization:
MICROSOFT_TENANT=commonOr work/school accounts only (no personal accounts):
MICROSOFT_TENANT=organizationsRestrict to your specific Azure AD tenant:
MICROSOFT_TENANT=12345678-1234-1234-1234-123456789012Get your tenant ID from: Azure Portal → Azure Active Directory → Overview
Include tenant information:
MICROSOFT_INCLUDE_TENANT_INFO=trueInclude user profile photo:
MICROSOFT_INCLUDE_AVATAR=trueRequest additional scopes (comma-separated):
MICROSOFT_SCOPES=offline_access,User.ReadSee config/config.php for all available options.
You can use events to restrict which tenants are allowed:
// In a plugin or theme's boot() method
Event::listen('winter.sso.microsoft.authenticated', function ($ssoUser) {
$allowedTenants = ['tenant-id-1', 'tenant-id-2'];
if (!in_array($ssoUser->tenant['id'], $allowedTenants)) {
throw new AuthenticationException('Tenant not allowed');
}
});Event::listen('winter.sso.microsoft.afterLogin', function ($user, $ssoUser) {
// Get Microsoft 365 groups the user belongs to
$groups = $ssoUser->getRoles(); // Returns array of group names
// Assign Winter CMS role based on Microsoft group
if (in_array('Admins', $groups)) {
$user->role = 'developer';
$user->save();
}
});Event::listen('winter.sso.microsoft.registered', function ($user, $ssoUser) {
$user->fill([
'first_name' => $ssoUser->user['givenName'] ?? null,
'last_name' => $ssoUser->user['surname'] ?? null,
]);
$user->save();
});- Detailed Setup Guide - Step-by-step Azure AD configuration with screenshots
- Winter.SSO Documentation - Core SSO plugin docs
- Microsoft Identity Platform - Official Microsoft OAuth documentation
- SocialiteProviders Microsoft - Socialite provider documentation
Your Azure AD application must be configured with this exact redirect URI:
https://example.com/backend/winter/sso/handle/callback/microsoft
Replace https://example.com with your actual domain. The path must be exactly as shown.
Cause: Redirect URI in Azure AD doesn't match exactly.
Solution:
- Go to Azure Portal → App registrations → Your app → Authentication
- Ensure redirect URI is:
https://example.com/backend/winter/sso/handle/callback/microsoft - Must match exactly (including https/http, trailing slashes, etc.)
Cause: Using tenant-specific endpoint with multi-tenant app, or vice versa.
Solution:
- Multi-tenant: Use
MICROSOFT_TENANT=commonororganizations - Single-tenant: Use
MICROSOFT_TENANT=your-tenant-id - Ensure "Supported account types" in Azure AD matches your configuration
Cause: Azure AD is configured to require user assignment, but user not assigned.
Solution:
- Azure Portal → Enterprise applications → Your app → Users and groups
- Either assign users, or go to Properties and set "User assignment required?" to "No"
Cause: Provider not in enabled_providers array in Winter.SSO config.
Solution: Add 'microsoft' to config/winter/sso/config.php:
'enabled_providers' => ['microsoft'],See Winter.SSO Troubleshooting for general SSO issues.
For Azure-specific features like logout URLs, consider using the Microsoft-Azure Socialite provider instead. This would require creating a separate Winter.SSOProviderMicrosoftAzure plugin.
The Microsoft provider (this plugin) is recommended for most use cases.