The two routes

Microsoft 365 calendars can be reached through the Microsoft Graph API, which means registering an application in Entra ID, obtaining consent, storing a client secret, and refreshing tokens. Or they can be published as an ICS feed, which means clicking Publish and copying a URL.

For a website that needs to show what is on, the second is almost always correct. Graph is the right answer when you need to write events back, read across many users' calendars, or react to changes in real time. Showing a schedule on a public page needs none of that.

Why storing a client secret on a website is a bad trade

An Azure app registration with calendar permissions is a credential that can read calendar data across your tenant, depending on the scopes granted. Putting it in a WordPress database — a database on shared hosting, backed up to who knows where, accessible to every plugin you install — is a meaningful risk to accept in exchange for a nicer sync.

A published ICS URL is a secret too, but a much smaller one: it grants read access to exactly one calendar and can be revoked by unpublishing, without touching anything else in your tenant.

The policy that stops you

Calendar publishing is controlled by tenant policy, and in many organisations it is switched off. If Publish a calendar is missing or greyed out in Outlook's settings, that is what has happened. An administrator has to enable it — in Exchange Online this is a sharing policy setting — and no WordPress plugin can route around it.

If your IT department will not enable publishing, the pragmatic answer is usually a dedicated calendar on a separate account whose only job is to hold public events. That is often easier to get approved than a policy change, and it has the useful side effect of keeping internal appointments out of a public feed entirely.

What to publish

Create a calendar specifically for the events that belong on the website, share it with whoever maintains the schedule, and publish only that one. Publishing a working calendar and relying on the website to hide the private entries is the wrong way round — the feed is public the moment it is published, whatever the site chooses to display.

What the site does with it

Your WordPress server fetches the ICS on a schedule and turns it into real events with your theme's styling and your categories. Nothing is embedded, nothing loads from Microsoft in the visitor's browser, and no credential beyond the feed URL is stored on the site.