{"id":303112,"date":"2026-06-25T03:57:52","date_gmt":"2026-06-25T03:57:52","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/sso-for-microsoft-entra\/"},"modified":"2026-06-25T04:17:44","modified_gmt":"2026-06-25T04:17:44","slug":"sso-for-microsoft-entra","status":"publish","type":"plugin","link":"https:\/\/wordpress.org\/plugins\/sso-for-microsoft-entra\/","author":14300937,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"2.6.1","stable_tag":"2.6.1","tested":"7.0","requires":"6.0","requires_php":"8.0","requires_plugins":null,"header_name":"SSO for Microsoft Entra","header_author":"Khoi Pro, CODE TOT","header_description":"Single Sign-On authentication for WordPress using Microsoft Entra ID (Azure AD) via OpenID Connect with PKCE.","assets_banners_color":"10497a","last_updated":"2026-06-25 04:17:44","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/github.com\/codetot-web\/sso-for-microsoft-entra","header_author_uri":"https:\/\/codetot.com","rating":0,"author_block_rating":0,"active_installs":0,"downloads":42,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"2.6.0":{"tag":"2.6.0","author":"khoipro","date":"2026-06-25 03:57:13"},"2.6.1":{"tag":"2.6.1","author":"khoipro","date":"2026-06-25 04:17:44"}},"upgrade_notice":[],"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3585603,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3585603,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256},"icon.svg":{"filename":"icon.svg","revision":3585603,"resolution":false,"location":"assets","locale":false}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3585603,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3585603,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250},"banner.svg":{"filename":"banner.svg","revision":3585603,"resolution":false,"location":"assets","locale":false}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["2.6.0","2.6.1"],"block_files":[],"assets_screenshots":[],"screenshots":{"1":"<strong>Settings page<\/strong> \u2014 Connection, authentication, and user provisioning settings.","2":"<strong>Login page<\/strong> \u2014 Microsoft sign-in button on the WordPress login form."}},"plugin_section":[],"plugin_tags":[13289,241505,3883,5136,2469],"plugin_category":[],"plugin_contributors":[194478,88058],"plugin_business_model":[],"class_list":["post-303112","plugin","type-plugin","status-publish","hentry","plugin_tags-azure","plugin_tags-entra","plugin_tags-microsoft","plugin_tags-single-sign-on","plugin_tags-sso","plugin_contributors-codetot","plugin_contributors-khoipro","plugin_committers-khoipro"],"banners":{"banner":"https:\/\/ps.w.org\/sso-for-microsoft-entra\/assets\/banner-772x250.png?rev=3585603","banner_2x":"https:\/\/ps.w.org\/sso-for-microsoft-entra\/assets\/banner-1544x500.png?rev=3585603","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":"https:\/\/ps.w.org\/sso-for-microsoft-entra\/assets\/icon.svg?rev=3585603","icon":"https:\/\/ps.w.org\/sso-for-microsoft-entra\/assets\/icon.svg?rev=3585603","icon_2x":false,"generated":false},"screenshots":[],"raw_content":"<!--section=description-->\n<p><strong>SSO for Microsoft Entra<\/strong> enables your WordPress site to authenticate users through Microsoft Entra ID (formerly Azure Active Directory). Users can sign in with their existing Microsoft 365 \/ work accounts \u2014 no separate WordPress password required.<\/p>\n\n<p><strong>Key features:<\/strong><\/p>\n\n<ul>\n<li><strong>OpenID Connect (OIDC)<\/strong> with PKCE \u2014 the most secure OAuth 2.0 flow, no client secret exposure.<\/li>\n<li>Automatic user provisioning \u2014 create WordPress accounts on first SSO login.<\/li>\n<li>Encrypted client-secret storage using WordPress secret keys.<\/li>\n<li>Configurable rate limiting on SSO login attempts.<\/li>\n<li>Optional auto-redirect from the WordPress login page directly to Entra.<\/li>\n<li>Contextual Help tabs with setup guides built into the settings page.<\/li>\n<li>Vietnamese translation included. Community translations via translate.wordpress.org.<\/li>\n<li>No jQuery dependency.<\/li>\n<\/ul>\n\n<h3>External Services<\/h3>\n\n<p>This plugin communicates with Microsoft Entra ID (Azure AD) endpoints to perform OpenID Connect authentication.<\/p>\n\n<p><strong>What data is sent and when:<\/strong><\/p>\n\n<ul>\n<li>When a user clicks \"Sign in with Microsoft\", their browser is redirected to the Microsoft authorization endpoint. No user data is sent by the plugin at this stage \u2014 Microsoft handles the login form.<\/li>\n<li>After the user authenticates, the plugin exchanges an authorization code for tokens by sending the code, client ID, client secret, and PKCE verifier to the Microsoft token endpoint. This happens server-to-server.<\/li>\n<li>The plugin fetches the OIDC discovery document and JSON Web Key Set (JWKS) to validate token signatures. These are public endpoints and no user data is sent.<\/li>\n<\/ul>\n\n<p><strong>Endpoints contacted:<\/strong><\/p>\n\n<ul>\n<li>Authorization: <code>https:\/\/login.microsoftonline.com\/{tenant}\/oauth2\/v2.0\/authorize<\/code><\/li>\n<li>Token exchange: <code>https:\/\/login.microsoftonline.com\/{tenant}\/oauth2\/v2.0\/token<\/code><\/li>\n<li>OIDC discovery: <code>https:\/\/login.microsoftonline.com\/{tenant}\/v2.0\/.well-known\/openid-configuration<\/code><\/li>\n<li>JWKS (token signing keys): URL from discovery document, typically <code>https:\/\/login.microsoftonline.com\/{tenant}\/discovery\/v2.0\/keys<\/code><\/li>\n<li>Logout: <code>https:\/\/login.microsoftonline.com\/{tenant}\/oauth2\/v2.0\/logout<\/code><\/li>\n<\/ul>\n\n<p>All endpoints are owned and operated by Microsoft Corporation. The <code>{tenant}<\/code> value is the Directory (tenant) ID configured by the site administrator.<\/p>\n\n<ul>\n<li><a href=\"https:\/\/privacy.microsoft.com\/en-us\/privacystatement\">Microsoft Privacy Statement<\/a><\/li>\n<li><a href=\"https:\/\/www.microsoft.com\/en-us\/servicesagreement\">Microsoft Terms of Service<\/a><\/li>\n<\/ul>\n\n<p>No data is sent to any other third-party services. Authentication tokens are validated locally using public signing keys and are never stored beyond the active session.<\/p>\n\n<h3>Support<\/h3>\n\n<ul>\n<li><strong>Bug reports and feature requests:<\/strong> <a href=\"https:\/\/github.com\/codetot-web\/sso-for-microsoft-entra\/issues\">GitHub Issues<\/a><\/li>\n<li><strong>Documentation:<\/strong> Click the Help button on the plugin settings page, or see the <a href=\"https:\/\/github.com\/codetot-web\/sso-for-microsoft-entra\">GitHub README<\/a>.<\/li>\n<li><strong>Security vulnerabilities:<\/strong> Please report privately via <a href=\"https:\/\/github.com\/codetot-web\/sso-for-microsoft-entra\/security\/advisories\">GitHub Security Advisories<\/a>.<\/li>\n<\/ul>\n\n<h3>Upgrade Notices<\/h3>\n\n<h4>2.6.0<\/h4>\n\n<p>No manual action required. Legacy <code>microsoft_entra_sso_*<\/code> options are migrated automatically to <code>sfme_*<\/code> on the next admin page load.<\/p>\n\n<h4>2.2.0<\/h4>\n\n<p>SAML 2.0 support has been removed. If you were using SAML, switch to OpenID Connect: create an Azure App Registration, set the redirect URI to <code>https:\/\/yoursite.com\/sso\/callback<\/code>, and enter your Tenant ID, Client ID, and Client Secret.<\/p>\n\n<h4>2.0.2<\/h4>\n\n<p>Client Secret field is now hidden for SAML setups and no longer triggers a missing-field warning.<\/p>\n\n<h4>2.0.1<\/h4>\n\n<p>Fix WordPress 6.9 compatibility header and Plugin Check compliance.<\/p>\n\n<h4>2.0.0<\/h4>\n\n<p><strong>Breaking:<\/strong> Plugin renamed and all internal prefixes changed. Settings auto-migrate on activation \u2014 just deactivate and reactivate. Requires PHP 8.1+.<\/p>\n\n<h4>1.1.0<\/h4>\n\n<p><strong>Breaking:<\/strong> Update Azure redirect URI to <code>https:\/\/yoursite.com\/sso\/callback<\/code>. Re-enter client secret (encryption changed). Flush permalinks.<\/p>\n\n<h4>1.0.0<\/h4>\n\n<p>Initial release.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Upload the <code>sso-for-microsoft-entra<\/code> folder to <code>\/wp-content\/plugins\/<\/code> or install via the WordPress plugin installer.<\/li>\n<li>Activate the plugin from the <strong>Plugins<\/strong> screen.<\/li>\n<li>In Azure Portal, go to <strong>App registrations \u2192 + New registration<\/strong>.<\/li>\n<li>Set <strong>Redirect URI<\/strong> (Web) to <code>https:\/\/yoursite.com\/sso\/callback<\/code>.<\/li>\n<li>Copy the <strong>Application (client) ID<\/strong> and <strong>Directory (tenant) ID<\/strong> from the overview page.<\/li>\n<li>Go to <strong>Certificates &amp; secrets \u2192 + New client secret<\/strong> \u2192 copy the Value.<\/li>\n<li>In WordPress, go to <strong>Settings \u2192 Entra SSO<\/strong>, enter <strong>Tenant ID<\/strong>, <strong>Client ID<\/strong>, and <strong>Client Secret<\/strong>. Click <strong>Save Changes<\/strong>.<\/li>\n<li>Go to <strong>API permissions \u2192 + Add permission \u2192 Microsoft Graph \u2192 Delegated: openid, profile, email<\/strong>.<\/li>\n<li>Test in an incognito window \u2014 click \"Sign in with Microsoft\" on the login page.<\/li>\n<\/ol>\n\n<p>For detailed instructions, click the <strong>Help<\/strong> button on the settings page, or see the <a href=\"https:\/\/github.com\/codetot-web\/sso-for-microsoft-entra\">setup guide on GitHub<\/a>.<\/p>\n\n<!--section=faq-->\n<dl>\n<dt id=\"does%20this%20plugin%20work%20with%20personal%20microsoft%20accounts%20%28outlook.com%29%3F\"><h3>Does this plugin work with personal Microsoft accounts (outlook.com)?<\/h3><\/dt>\n<dd><p>No. It is designed for organisational accounts managed through a Microsoft Entra ID tenant.<\/p><\/dd>\n<dt id=\"what%20happens%20when%20a%20user%20logs%20in%20for%20the%20first%20time%3F\"><h3>What happens when a user logs in for the first time?<\/h3><\/dt>\n<dd><p>If <strong>Auto-Create Users<\/strong> is enabled, the plugin creates a WordPress account using the email and display name from the Entra token with the <strong>Subscriber<\/strong> role. Administrators can promote users to other roles manually.<\/p><\/dd>\n<dt id=\"is%20the%20client%20secret%20stored%20securely%3F\"><h3>Is the client secret stored securely?<\/h3><\/dt>\n<dd><p>Yes. Encrypted using libsodium (XSalsa20-Poly1305) or AES-256-GCM with a key derived from WordPress secret keys. Never written to log files.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>2.6.1<\/h4>\n\n<ul>\n<li><strong>Fixed:<\/strong> WordPress.org plugin directory assets (icon, banner) served from the correct SVN path.<\/li>\n<\/ul>\n\n<h4>2.6.0<\/h4>\n\n<ul>\n<li><strong>Added:<\/strong> Database upgrade system with <code>sfme_db_version<\/code> and automatic migration of legacy option prefixes.<\/li>\n<li><strong>Added:<\/strong> OAuth state is now bound to the initiating browser session via a short-lived <code>sfme_oauth_session<\/code> cookie.<\/li>\n<li><strong>Added:<\/strong> <code>sfme_allow_email_linking<\/code> filter and <code>sfme_user_linked_by_email<\/code> action for controlling email-based account linking.<\/li>\n<li><strong>Changed:<\/strong> Minimum PHP requirement is now <strong>8.0<\/strong>.<\/li>\n<li><strong>Fixed:<\/strong> <code>uninstall.php<\/code> now fully removes all current-version plugin data.<\/li>\n<\/ul>\n\n<h4>2.5.3<\/h4>\n\n<ul>\n<li><strong>Fixed:<\/strong> Remove <code>.gitkeep<\/code> placeholder files that were incorrectly included in the release package (WordPress Plugin Check: hidden_files).<\/li>\n<\/ul>\n\n<h4>2.5.2<\/h4>\n\n<ul>\n<li><strong>Fixed:<\/strong> ID token signature verification failed (<code>jwt_signature_invalid<\/code>) for Entra apps that use per-application signing keys. The plugin now appends <code>?appid={client_id}<\/code> when fetching the JWKS so the app-specific signing key is included.<\/li>\n<\/ul>\n\n<h4>2.5.1<\/h4>\n\n<ul>\n<li><strong>Fixed:<\/strong> <code>\/sso\/login<\/code> returning 404 after activation \u2014 rewrite rule is now registered before flush.<\/li>\n<\/ul>\n\n<h4>2.5.0<\/h4>\n\n<ul>\n<li><strong>Breaking:<\/strong> Removed role mapping and default role selector. All new SSO users are assigned the Subscriber role. Administrators promote users manually.<\/li>\n<li><strong>Removed:<\/strong> Role Mapping settings section and Role_Mapper class.<\/li>\n<\/ul>\n\n<h4>2.4.0<\/h4>\n\n<ul>\n<li><strong>Added:<\/strong> Settings link on the Plugins page next to Deactivate.<\/li>\n<\/ul>\n\n<h4>2.3.0<\/h4>\n\n<ul>\n<li><strong>Fixed:<\/strong> Validate <code>$_SERVER['REQUEST_METHOD']<\/code> before accessing it (Plugin Check compliance).<\/li>\n<li><strong>Fixed:<\/strong> Sanitize <code>redirect_to<\/code> parameter with <code>sanitize_url()<\/code>.<\/li>\n<li><strong>Fixed:<\/strong> Prefix template variables with <code>sfme_<\/code> to avoid global namespace collisions.<\/li>\n<li><strong>Fixed:<\/strong> Suppress expected slow DB query warning on Entra OID user lookup.<\/li>\n<li><strong>Fixed:<\/strong> Reduce tags to 5 maximum per WordPress.org guidelines.<\/li>\n<\/ul>\n\n<h4>2.2.0<\/h4>\n\n<ul>\n<li><strong>Breaking:<\/strong> Removed SAML 2.0 support. The plugin now uses OpenID Connect with PKCE exclusively.<\/li>\n<li><strong>Breaking:<\/strong> Removed <code>robrichards\/xmlseclibs<\/code> and <code>litesaml\/lightsaml<\/code> dependencies \u2014 no Composer vendor packages required.<\/li>\n<li><strong>Breaking:<\/strong> Removed SAML Metadata Import section, protocol selector, and <code>\/sso\/saml-acs<\/code> endpoint.<\/li>\n<li><strong>Fixed:<\/strong> Client secret sanitization no longer trims whitespace before encrypting (preserves secrets with leading\/trailing spaces).<\/li>\n<li><strong>Fixed:<\/strong> Removed <code>load_plugin_textdomain()<\/code> call \u2014 unnecessary for WordPress.org hosted plugins since WordPress 4.6.<\/li>\n<li><strong>Improved:<\/strong> External Services section in readme rewritten with detailed data flow description.<\/li>\n<\/ul>\n\n<h4>2.0.3<\/h4>\n\n<ul>\n<li><strong>Fixed:<\/strong> JS lint errors in protocol toggle (CI green).<\/li>\n<\/ul>\n\n<h4>2.0.2<\/h4>\n\n<ul>\n<li><strong>Fixed:<\/strong> Skip Client Secret requirement when SAML protocol is selected.<\/li>\n<li><strong>Fixed:<\/strong> Hide Client Secret field in settings when SAML 2.0 is active.<\/li>\n<li><strong>Fixed:<\/strong> Settings URL slug and plugin name in admin notices.<\/li>\n<\/ul>\n\n<h4>2.0.1<\/h4>\n\n<ul>\n<li><strong>Fixed:<\/strong> Update \"Tested up to\" to WordPress 6.9.<\/li>\n<li><strong>Fixed:<\/strong> Include composer.json in distribution (Plugin Check compliance).<\/li>\n<li><strong>Added:<\/strong> README.md for GitHub with badges, support links.<\/li>\n<li><strong>Added:<\/strong> Support section in readme.txt with GitHub Issues link.<\/li>\n<\/ul>\n\n<h4>2.0.0<\/h4>\n\n<ul>\n<li><strong>Breaking:<\/strong> Renamed plugin from \"Microsoft Entra SSO\" to \"SSO for Microsoft Entra\" for trademark compliance.<\/li>\n<li><strong>Breaking:<\/strong> All internal names changed \u2014 namespace (<code>SFME<\/code>), option keys (<code>sfme_*<\/code>), CSS\/JS classes (<code>sfme-*<\/code>). Existing settings auto-migrate on activation.<\/li>\n<li><strong>Breaking:<\/strong> Requires PHP 8.1+ (LightSaml dependency).<\/li>\n<li><strong>Added:<\/strong> Auto-extract Tenant ID and Client ID from federation metadata URL.<\/li>\n<li><strong>Added:<\/strong> Auto-switch to SAML protocol when importing metadata.<\/li>\n<li><strong>Added:<\/strong> Configurable rate limiting settings in admin (Max Attempts, Window).<\/li>\n<li><strong>Added:<\/strong> Contextual Help tabs on settings page (Quick Start, Azure Setup, SAML Setup, Troubleshooting).<\/li>\n<li><strong>Added:<\/strong> WordPress.org plugin assets (icon, banner).<\/li>\n<li><strong>Added:<\/strong> Vietnamese translation.<\/li>\n<li><strong>Fixed:<\/strong> SAML signature verification \u2014 replaced manual XML canonicalization with LightSaml library.<\/li>\n<li><strong>Fixed:<\/strong> UTF-8 BOM in Microsoft federation metadata causing XML parse failure.<\/li>\n<li><strong>Fixed:<\/strong> SAML Issuer using home URL instead of client ID (AADSTS700016).<\/li>\n<li><strong>Fixed:<\/strong> Metadata wiped on settings save \u2014 now preserves AJAX-imported values.<\/li>\n<\/ul>\n\n<h4>1.2.0<\/h4>\n\n<ul>\n<li>Auto-extract Tenant ID and Client ID from federation metadata URL on import.<\/li>\n<li>Auto-switch to SAML protocol when importing metadata.<\/li>\n<li>Rate limiting settings in admin UI.<\/li>\n<li>Strip UTF-8 BOM from Microsoft metadata XML.<\/li>\n<li>Use client ID as SAML AuthnRequest Issuer.<\/li>\n<li>Preserve SAML metadata on settings form save.<\/li>\n<\/ul>\n\n<h4>1.1.0<\/h4>\n\n<ul>\n<li><strong>Security:<\/strong> Fix critical SAML Signature Wrapping (XSW) and XPath injection.<\/li>\n<li><strong>Security:<\/strong> Fix double rate-limiting lockout after 2 logins.<\/li>\n<li><strong>Security:<\/strong> Add JWKS cache-refresh-on-failure.<\/li>\n<li><strong>Security:<\/strong> Use HKDF for encryption key derivation.<\/li>\n<li><strong>Changed:<\/strong> SSO endpoints moved from <code>wp-login.php<\/code> to <code>\/sso\/*<\/code> custom URLs.<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>Initial release.<\/li>\n<li>OpenID Connect with PKCE, SAML 2.0, user provisioning, role mapping, rate limiting.<\/li>\n<\/ul>","raw_excerpt":"Single Sign-On authentication for WordPress using Microsoft Entra ID (Azure AD) via OpenID Connect with PKCE.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/303112","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=303112"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/khoipro"}],"wp:attachment":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=303112"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=303112"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=303112"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=303112"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=303112"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=303112"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}