Synchronize users from Azure AD to WordPress
Before you start
- You have installed the WPO365 | SYNC or WPO365 | INTRANET bundle (plus the WPO365 | LOGIN plugin that provides the basic functionality needed for either bundle to operate as expected).
- You are a Global Administrator for your company’s Office 365 tenant / Azure AD directory (or have at least the ability to create and / or update Azure Active Directory App registrations).
- You are an Administrator for your WordPress website.
- You already configured Single Sign-on by following the steps documented in this article.
Please check out this video https://youtu.be/kAmixcyvJCo for a video tutorial for this article.
To start synchronizing users it is important to ensure the correct configuration of the plugin. The table below summarizes all configuration options and their recommended value.
The correct configuration can be verified using the plugin's built-in self-test tool. To self-test the plugin go to WP Admin > WPO365 > Plugin self-test and click to Start self-test. The self-test offers to fix most of the issues for you. However, some options require you to copy data from Azure Active Directory.
|Enable user sync||User sync||Checked||Replace|
|Pages freed from authentication||Single Sign-on||/wp-json/wpo365/v1/||Add|
| Pages freed from authentication
|Prevent WordPress to send "email changed" emails||Miscellaneous||Checked||Replace|
|Enable WPO365 API for Microsoft Graph *||Integration||Checked||Replace|
|Require users to sign-in [...] **||Integration||[...] with Microsoft||Select|
|Allow apps to request any [...] endpoint||Integration||Unchecked||Replace|
|Custom Domains||User registration||See Azure Portal||Add|
* The WPO365 API for Microsoft Graph is only used when you test your WPO365 User synchronization query and is not required for normal operation of the WPO365 User synchronization processor. If you do not want to keep the WPO365 API for Microsoft Graph enabled you can thus disable it again immediately after you tested your query successfully.
API Permissions (App
To synchronize users from Azure AD to WordPress the WPO365 plugin will attempt to retrieve those users from Microsoft's unified API called Microsoft Graph. To do so, the plugin requires permissions to read all users (and optionally also all Azure AD groups) from Microsoft Graph. Those permissions can be made available to the plugin's User synchronization processor as delegated (granted to a signed-in user) as well as application (granted to an application) permissions. With delegated permissions you can only manually start User synchronization. With application permissions you can choose to trigger User synchronization manually as well as from an external task scheduling service plus from a schedule (using WP-Cron jobs). We therefore strongly recommend that you configure app-only integration. Please note that you must configure application permissions when you configured SAML 2.0 based Single Sign-on since SAML 2.0 does not support authorization scenarios through granting permissions.
Delegated scenario (permissions granted to the logged-in user)
- Review the API Permissions you previously granted in Azure Portal to the App registration that you created to enable OpenID Connect based Single Sign-on (see https://docs.wpo365.com/article/23-integration) and ensure that you have assigned delegated User.Read.All (and optionally delegated GroupMember.Read.All) permissions to your App.
Application scenario (recommend)
- Review the API Permissions you previously granted in Azure Portal to the App registration that you created to enable app-only integration (see https://www.wpo365.com/use-app-only-token/) and ensure that you have assigned application User.Read.All (and optionally application GroupMember.Read.All) permissions to your App.
Granting GroupMember.Read.All permissions is not optional if you intend to implement Azure AD group based access restrictions and / or want to dynamically assign WordPress roles based on Azure AD groups.
At this point the plugin should be able to synchronize users. Perform the following steps to test your configuration.
- Navigate to WP Admin > WPO365 > Plugin self-test and click to Start self-test.
- Carefully inspect the section INSTALLED EXTENSIONS and make sure you are using the latest version of the WPO365 | SYNC or WPO365 | INTRANET bundle.
- Scroll down to CONFIGURATION and make sure all but the following two tests are passed successfully:
- Debug log disabled It may even be helpful to enable the debug log in the beginning.
- Domain hint configured This configuration is not important for successfully synchronizing users.
- Continue scrolling so SYNC and make sure that all tests are passed successfully. You can click the link view in the Data column to see the test data retrieved by the plugin.
At this point you'll may notice that the test WP-Cron is disabled is not passed. Since User synchronization heavily relies on WP-Cron and WP-Cron not runs continuously it is strongly recommended that you hook WP-Cron into a n external task scheduling service. You can follow the steps explained in this article to achieve this
Adding a new User synchronization job
Now that the plugin is configured for user synchronization you must add at least one User synchronization job. To do so go to WP Admin > WPO365 > User sync and click Add new job.
Perform the following steps to configure a User synchronization job.
- Give your job a meaning full name e.g. ALL INTERNAL EMPLOYEES or WEBSITE ADMINS.
- Update the query so it selects exactly those users that you want to synchronize to your WordPress website. You can click Show sample queries to see examples of such queries. Each time when you change your query you must test the query. You cannot save the job if the query is not tested successfully.
Please note that you can also test your query with the help of Microsoft's Graph Explorer.
The default query filters for userType eq 'member' but when you synchronize users from Active Directory (on-premise) the userType may actually be null and the query does not return any users.
You may notice that the plugin automatically adds a $count= parameter which you should not remove. The count (= total rows) helps the plugin being able to track progress
If you customize the query you must include the $top= query parameter e.g. $top=10 or $top=20. The $top parameter defines the page size and will force Microsoft Graph to return the full result in pages. The user sync processor is aware of such pages and after processing a result page will request the next page until there are no pages left. Omitting the query parameter or defining pages with too many results may cause a time-out error and the user sync job will not be completed as expected.
The plugin automatically detects a Microsoft Graph $count query and automatically adds the ConsistencyLevel = True header and thus allowing for advanced queries with $filter using endsWith and $search (see this article if you want to build advanced queries).This means that you can write a User sync query that includes all users from a specific domain as follows: myorganization/users?$count=true&$filter=endsWith(userPrincipalName,%email@example.com%27)&$top=10.
- Select the actions that should be performed when users are being synchronized e.g.
Please note that if you do not check any of the options then user synchronization will simply log / preview the action it would have otherwise applied (see the next paragraph on monitoring progress. When you configure user synchronization for the first time it is strongly recommended that you preview the results by leaving any of the actions unchecked.
- Create new users.
- Update (custom user fields and / or dynamically assigned WordPress roles of) existing users.
- Delete users.
- Soft-delete users (only available if you previously selected to delete users).
- Re-assign posts to (only available if you previously unchecked the option to soft-delete users and please note that you must have checked the user successfully to be able to save the job).
WordPress users are deleted at the end of a user synchronization job. The user synchronization processor then analyzes all WordPress users that were not affected by the job that is about to complete and for each of those users checks whether its user name or email address has a domain component that matches with any of the domains in the Custom domains list on the plugin's User registration configuration page.
- Decide whether or not to ignore external identities (= Azure AD guest users) that may be included in the query result.
- Select a trigger e.g.
- Run manually by clicking the Save + Run now button at the bottom of the job's form.
- External link which you can use to externally start user synchronization e.g. when you want to use an external scheduler. This is especially useful if you want to run the job more than once per day, which is not possible if you select WordPress Cron.
- WordPress Cron which allows you to define a schedule e.g. once per day at a specific time.
- Decide whether you want to send a log i.e. a summary each time the job completes. If you check this option, you'll be able to configure a specific email address where the log will be sent to.
Once a user synchronization job is running or has finished you can monitor progress as shown below.
After a user synchronization job has finished you click the View results button at the bottom of the job's form.
The table with results provides you with the following information:
- All WordPress users.
- WordPress users that have been created during the last run.
- WordPress users that have been updated during the last run.
- WordPress users that have been earmarked as deactivated (= soft-deleted) during the last run.
- WordPress users that have been deleted during the last run.
- Azure AD users that are not synchronized due to an error during the last run.
- Logged Azure AD users that otherwise would have been created or updated or (soft-deleted) but none of those actions had been activated.
- The external link trigger may not work as expected if caching is enabled for your website. In that case the link will work for the very first time or each time after your purged / refreshed the cache. In such a case you should add a dynamic parameter to the URL with a value that is dynamically generated to break the cache.