Skip to content

Setting up an Azure app

Before Drupal can talk to Microsoft 365 you need an app registration in the Microsoft Entra admin center. One registration per tenant you want to connect to. This page walks through the registration and tells you which values to write down.

Creating the app

  1. Go to portal.azure.com and open App registrations.
  2. Click New registration and give the app a name. Users see this name on the consent screen, so use something they will recognize, not "drupal-test-2".
  3. Pick the account types. For an intranet that is usually Accounts in this organizational directory only. Pick a multitenant option only if people from outside your own tenant have to log in.
  4. Add a redirect URI of type Web. Which URI you need depends on the connector, see below.
  5. Register the app. Copy the Application (client) ID and the Directory (tenant) ID from the overview page.

Which redirect URI

The SSO submodule serves two callback routes. The connector with the machine name default uses the short one, every other connector gets its machine name appended:

Connector machine name Redirect URI
default https://www.example.com/o365/callback
intranet https://www.example.com/o365/callback/intranet

If you connect to two tenants, register the matching URI on each app. Getting this wrong gives you AADSTS50011 at login, which is Microsoft's way of saying the URI it received is not in the list.

Add the URIs for your acceptance and development environments too, while you are in there. An app registration takes any number of them.

Creating the client secret

  1. Open Certificates & secrets and click New client secret.
  2. Give it a description and an expiry. Microsoft caps this at 24 months.
  3. Copy the Value, not the Secret ID. The value is shown once. Navigate away and it is gone for good, and you get to create a new secret.

Put the expiry date in a calendar

A secret that quietly expires takes single sign-on down with it, and the error in the log is not obvious about the cause.

Granting API permissions

Open API permissions, choose Microsoft Graph and then Delegated permissions. The connector acts on behalf of the logged in user, so delegated is what you want; application permissions are not used.

A bare install of o365 asks for:

  • email
  • offline_access
  • openid
  • profile
  • User.Read

Every submodule you enable adds more. Outlook Calendar wants the Calendars.* scopes, Profiles and Personas wants People.Read and the Presence.* scopes, and so on. Rather than track that by hand, enable the submodules first and then open /admin/reports/o365-auth-scopes on your site. That report lists the scopes the site will actually request, per connector, including anything added through hook_o365_auth_scopes(). Copy that list into Azure.

Some permissions need an administrator to grant consent for the whole tenant. Presence.Read.All is the one that catches people out. If presence stays empty for everyone while the rest works, that is usually a missing admin consent rather than a bug.

What to write down

You leave Azure with four things:

  • the client ID
  • the client secret value
  • the tenant ID, or common for a multitenant app
  • the site URL you registered the redirect URI for

Putting the credentials in settings.php

Credentials never go into Drupal configuration, so they never end up in an exported config directory or in git. They go in settings.php, keyed by the machine name of the connector you are going to create:

$settings['o365'] = [
  'default' => [
    'client_id' => '<client id>',
    'client_secret' => '<client secret>',
    'tenant_id' => '<tenant id>',
  ],
  'intranet' => [
    'client_id' => '<client id>',
    'client_secret' => '<client secret>',
    'tenant_id' => '<tenant id>',
  ],
];

Each key may also carry redirect_login, the absolute URL users land on after a successful login. Set it there and it overrides whatever the connector entity says, which is handy when acceptance and production need different targets.

Upgrading from 5.x

5.x used a single fixed key:

$settings['o365']['api_settings']['client_id'] = '<client id>';
$settings['o365']['api_settings']['client_secret'] = '<client secret>';
$settings['o365']['api_settings']['tenant_id'] = '<tenant id>';

In 6.0.x that array is not read any more. Rename api_settings to the machine name of your connector, which for a single tenant site is usually default. The values themselves do not change.

Next

Continue with Installing and configuring the module.