=== M365 Login === Contributors: friloo Tags: microsoft, entra id, azure ad, sso, login Requires at least: 6.0 Tested up to: 6.9 Requires PHP: 7.4 Stable tag: 1.0.0 License: GPLv2 or later License URI: https://www.gnu.org/licenses/gpl-2.0.html Adds a customisable "Sign in with Microsoft" button to the login page. Existing users sign in with their Microsoft 365 / Entra ID account, matched by e-mail address. == Description == **M365 Login** lets your existing WordPress users sign in with their Microsoft 365 (Microsoft Entra ID, formerly Azure AD) work or school account. It adds a button to the standard WordPress login screen and uses the OpenID Connect authorization code flow with PKCE. The plugin is deliberately small and strict: * **No user provisioning.** A Microsoft sign-in succeeds only when a WordPress user with the same e-mail address already exists. Nobody gets an account just by having a Microsoft login. * **Password login stays available.** The button is an additional option; the normal form is untouched. * **Fully customisable button.** Change the text, replace the Microsoft logo with your own icon from the media library, pick background, hover, text and border colours, adjust the corner radius, and choose whether the button appears above or below the login form – with a live preview. * **Clean settings screen** with a copy-and-paste redirect URI, a tenant connectivity test and a five-step setup guide. * **Shortcode** `[m365_login_button]` for custom login pages. = Security = * OpenID Connect **authorization code flow with PKCE (S256)** – tokens are exchanged server-to-server and never pass through the browser. * **Single-use state and nonce** values, bound to the browser with an HttpOnly, SameSite cookie (CSRF and replay protection). * The **ID token signature is verified** against Microsoft's published signing keys (JWKS, cached and refreshed on key rollover). Issuer, audience, tenant, expiry, not-before and nonce are all checked. Only RS256 is accepted. * Optional **tenant pinning**: when a tenant GUID is configured, tokens from any other tenant are rejected. * **Account binding**: on first sign-in the immutable Microsoft object ID is stored with the user; later sign-ins with the same e-mail but a different Microsoft identity are refused. * Optional **e-mail domain allow-list**. * The **client secret is encrypted at rest** (AES-256-GCM, key derived from your WordPress salts) and never displayed again. * Every setting is sanitised, every output escaped, every admin request nonce- and capability-checked. = Developer hooks = * `m365_login_show_button` – filter, hide the button conditionally. * `m365_login_authorize_params` – filter the parameters sent to Microsoft (e.g. `domain_hint`). * `m365_login_match_email` – filter the e-mail address used for the lookup. * `m365_login_allow_user` – filter, return `false` to block a matched user (e.g. group checks). * `m365_login_success` – action after a successful sign-in, receives the user and verified claims. == External services == This plugin connects to **Microsoft identity platform (Microsoft Entra ID)** to authenticate users. It is required for the plugin's only purpose – signing users in with their Microsoft account – and is only contacted when a user clicks the Microsoft button or when an administrator uses the "Test tenant" button. Endpoints used (all under `https://login.microsoftonline.com/`): * `/{tenant}/oauth2/v2.0/authorize` – the user's browser is redirected here to sign in at Microsoft. Microsoft receives the application (client) ID, the redirect URI of this site, a random state, nonce and PKCE challenge. * `/{tenant}/oauth2/v2.0/token` – the server exchanges the authorization code for an ID token. Microsoft receives the client ID, client secret, the code and the PKCE verifier. * `/{tenant}/discovery/v2.0/keys` – the server downloads Microsoft's public signing keys to verify the ID token. No user data is sent. * `/{tenant}/v2.0/.well-known/openid-configuration` – fetched only when an administrator clicks "Test tenant". No user data is sent. The plugin receives the user's e-mail address / user principal name, display name and Microsoft object ID from Microsoft and uses them solely to find the matching WordPress account. Nothing else is stored. Microsoft terms and privacy: [Microsoft Services Agreement](https://www.microsoft.com/servicesagreement), [Microsoft Privacy Statement](https://privacy.microsoft.com/privacystatement), [Microsoft identity platform documentation](https://learn.microsoft.com/entra/identity-platform/). == Installation == 1. Upload the plugin folder to `/wp-content/plugins/` or install it through the WordPress plugin screen, then activate it. 2. Go to **Settings → M365 Login** and copy the **Redirect URI** shown in the sidebar. 3. In the [Microsoft Entra admin center](https://entra.microsoft.com/) open **App registrations → New registration**. Choose *Accounts in this organizational directory only*, select the **Web** platform and paste the redirect URI. 4. From the app's overview page copy the **Application (client) ID** and the **Directory (tenant) ID** into the plugin settings. 5. Under **Certificates & secrets** create a client secret and paste its *value* into the plugin settings. 6. Under **Token configuration** add the optional claim **email** for ID tokens (recommended). The delegated permissions `openid`, `profile` and `email` are granted by default. 7. Save. The button now appears on `wp-login.php`. Customise it on the **Button** tab. Make sure every user who should be able to sign in has the same e-mail address in WordPress as in Microsoft 365. == Frequently Asked Questions == = Does the plugin create users? = No. Users must already exist in WordPress. The e-mail address is the only link between the Microsoft account and the WordPress account. This is intentional – it keeps the administrator in control of who can access the site. = Which accounts can sign in? = Any Microsoft account of the configured tenant whose e-mail address (or user principal name) matches an existing WordPress user. Restrict it further with the e-mail domain allow-list or the `m365_login_allow_user` filter. = Can I use it with personal Microsoft accounts (outlook.com)? = Set the tenant to `consumers` or `common`. Note that Microsoft does not allow query strings in redirect URIs for apps that support personal accounts, so your site must use pretty permalinks (the callback URL is then `/m365-login/callback` without a query string). = The sign-in fails with "No WordPress account exists for your Microsoft e-mail address" = The e-mail address in the Microsoft token does not match any WordPress user. Check the user's e-mail address in WordPress, enable the UPN fallback on the Security tab, or add the `email` optional claim in the app registration. = Does it work with custom login pages? = Yes, use the shortcode `[m365_login_button redirect="/dashboard/"]`. = Does it support multisite? = Yes. Settings are per site; a user must be a member of the site (or a super admin) to sign in. = What happens on uninstall? = The settings, cached data and the per-user Microsoft object ID are removed. == Screenshots == 1. The customised button on the WordPress login screen. 2. Settings – Connection tab with redirect URI and tenant test. 3. Settings – Button tab with live preview, colour pickers and icon picker. 4. Settings – Security tab. == Changelog == = 1.0.0 = * Initial release. == Upgrade Notice == = 1.0.0 = Initial release.