# Changelog All notable changes to this project are documented in this file. The format follows [Keep a Changelog](https://keepachangelog.com/) and the plugin adheres to [Semantic Versioning](https://semver.org/). ## [1.1.0] – 2026-09-23 ### Added - User sync (new "User sync" tab): imports Microsoft 365 / Entra ID users as WordPress accounts – the whole tenant or the (nested) members of selected groups, guests optional – and links existing accounts by e-mail address. - Default role plus group → role mapping with a Graph-powered group picker; mapped roles either added to or replacing the default role (first match wins, reorderable). Roles of accounts that existed before the sync are only managed on request. - Selectable profile attributes (display name, first/last name, job title, department, company, office, employee ID, phones, address, language) and the profile photo, which replaces the Gravatar. - Deactivation or deletion of WordPress accounts whose Microsoft 365 account was disabled, deleted or removed from the sync groups; automatic reactivation. Deactivated accounts cannot sign in at all (Microsoft, password, application passwords) and lose all sessions. - Safeguards: dry run, safety stop above 20 % deprovisioning (at least 5 accounts), abort on any Graph error, deletion only on a 404 for the object ID, protected pre-existing administrators and own account, content reassignment required for deletion, run lock. - Scheduled sync via WP-Cron (hourly, twice daily, daily), `wp m365-login sync [--dry-run]`, report of the last run in the settings. - "Microsoft 365" column and deactivate/reactivate row actions on the users screen; read-only Microsoft 365 section on the profile screen. - Graph client: paging, retry on throttling (429/503/504), user, group member and photo endpoints. - Filters and actions for the sync (`m365_login_sync_*`, `m365_login_user_disabled`, `m365_login_user_enabled`). ### Changed - The group picker is reusable (security groups, sync groups, role mapping). ### Fixed - "Generate certificate" and removing the certificate did not keep the change and encrypted a stored client secret a second time (internal settings writes ran through the form sanitiser). ## [1.0.0] – 2026-09-22 ### Added - "Sign in with Microsoft" button on `wp-login.php` (OpenID Connect authorization code flow with PKCE). - Matching of existing WordPress users by e-mail address (optional UPN fallback), no user provisioning. - Settings screen (own top-level menu entry "M365 Login") with connection, button and security tabs, live button preview, colour presets, media-library icon picker, redirect-URI copy button and tenant connectivity test. - ID token verification against Microsoft's JWKS (RS256, issuer, audience, tenant, expiry, nonce). - Encrypted client secret storage (AES-256-GCM). - Certificate based client authentication (RFC 7523 `private_key_jwt`): one-click generation of a 3072-bit RSA key pair with self-signed certificate, `.cer` download, own PEM upload, expiry display; step-by-step guides for both methods in the settings. - Security audit (docs/security-audit.md) with fixes: unverified `email` claim ignored in multi-tenant mode, login-start rate limit, trusted proxy IP header. - Account binding to the Microsoft object ID, e-mail domain allow-list. - Entra group restriction with a Graph-powered group picker; membership verified via the `groups` claim or Microsoft Graph `checkMemberGroups`. - Button-only mode that hides the password form and blocks password sign-in on `wp-login.php`, with a secret, rate-limited fallback link and a `wp-config.php` emergency constant. - Custom login page support: automatic button in `wp_login_form()` forms, `m365_login_button()` / `m365_login_messages()` template functions, custom login URL for error messages, fallback link and logout redirect. - `[m365_login_button]` shortcode (with `divider` and `messages` attributes) and developer hooks. - German translation.