Enterprise Contacts
IT Admin Guide

Setting up Enterprise Contacts
in your Microsoft 365 tenant

Everything is configured through Entra ID security groups — no MDM, no configuration profiles, no per-user setup required.

Overview

How it works

Enterprise Contacts is a multi-tenant iOS app registered in Azure. When a user logs in with their Microsoft work account, the app reads a special configuration group in your Entra ID tenant to discover the group prefix you have defined. It then looks for all security groups with that prefix and presents them as contact databases.

Setup is three steps:

1

Approve the app in your Entra ID tenant

Grant admin consent so users in your organisation can log in with their work account.

2

Create the configuration group

One security group that tells the app which prefix to use when looking for contact databases.

3

Create contact database groups

One security group per contact database you want to make available. Members of a group can access that database.


Step 1

Approve the app in Entra ID

Enterprise Contacts is a multi-tenant app registration. You need to add it to your tenant as an Enterprise Application and grant admin consent once.

1

Open the Azure Portal

Go to Entra ID → Enterprise Applications → New application.

2

Search for the app

Search for "Enterprise Contacts" in the App Gallery, or add it manually using its Application (client) ID:

260f14fb-fe92-4af0-9cf6-c0afda8251c5
3

Grant admin consent

Go to Enterprise Applications → Enterprise Contacts → Permissions → Grant admin consent for [your tenant]. This allows users to sign in without individual consent prompts.

4

Assign users (optional)

By default all users in your tenant can log in. If you want to restrict access, enable User assignment required under Properties and add only the relevant users or groups.

Permissions requested: The app requests five delegated, read-only permissions. No write access to your directory or mailbox is ever requested.
View permissions & justification
Permission Why it is needed Admin consent
User.Read Reads the signed-in user's own profile (/me) — display name, job title, department, and profile photo — shown on the My Profile screen. Also used to resolve the user's ID for membership checks. No
Contacts.Read Reads contacts from the signed-in user's own Exchange contact folders (/me/contactFolders/…). Required for database type 2 (My Contacts). No
Contacts.Read.Shared Reads contacts from another user's shared Exchange contact folder (/users/{id}/contactFolders/…). Required for database type 0 (Exchange mailbox), for example a shared reception mailbox. No
Group.Read.All Lists and reads Entra ID security groups to discover the configuration group (App_EnterpriseContacts_Config) and all contact database groups matching your chosen prefix. Without this the app cannot find any databases. Yes
GroupMember.Read.All Reads the transitive members of each database group to fetch contact details and verify that the signed-in user is authorised to access a given database. Without this no contacts can be synced. Yes
Delegated permissions only. All five permissions are delegated — the app acts on behalf of the signed-in user and is bounded by that user's own access rights in your tenant. The app holds no application-level permissions and cannot act without a signed-in user.

Step 2

Create the configuration group

Create a single security group named exactly App_EnterpriseContacts_Config. The app looks for this group in your tenant to read your chosen group prefix.

Group name: Must be exactly App_EnterpriseContacts_Config — case-sensitive.

Set the group Description to the following JSON, replacing Your_Prefix_Here_ with your chosen prefix:

Description field: {"groupPrefix":"Your_Prefix_Here_"}

Example — if your organisation is Contoso and you want to use the prefix EC_Contoso_:

{"groupPrefix":"EC_Contoso_"}
Membership: The config group does not need any members. Its description is all that matters.

Step 3

Create contact database groups

Each contact database visible in the app is backed by one Entra ID security group. The group name must start with your chosen prefix. The group description defines how the database behaves.

Group name format

Name: {YourPrefix}{DatabaseLabel} Example: EC_Contoso_CompanyContacts

Group description format

The description must be a JSON object. The app also accepts the older pipe-delimited format for groups created before this change — both formats work side by side.

Field Type Values Description
name string Any string Display name shown in the app. Required.
description string Any string Short subtitle shown when adding the database manually. Can be empty.
autoLoad boolean true or false true = added automatically for all members on first launch. false = only available via the + button.
deleteable boolean true or false true = user can remove the database. false = delete button is disabled.
type integer 0, 1, or 2 0 = Exchange mailbox, 1 = Entra ID group, 2 = My Contacts folder. Required.
primaryId string See reference below Main identifier. UPN for mailbox/myContacts. Object ID (GUID) for Entra ID group. Required.
secondaryId string Folder ID Required for type 0 (mailbox) only. The Exchange folder ID of the contacts folder to sync. Omit for other types.

Examples

Type 0 — Exchange mailbox

Name: EC_Contoso_SharedMailbox Description: { "name": "Shared Mailbox", "description": "Reception desk contacts", "autoLoad": false, "deleteable": true, "type": 0, "primaryId": "reception@contoso.com", "secondaryId": "<exchange-folder-id>" }
Mailbox read access is required. Enterprise Contacts uses delegated permissions — it can only read what the signed-in user is already allowed to access in Exchange. For type 0 databases, each user who should sync that mailbox's contacts must have at least Reviewer (read) permission on the relevant contact folder in Exchange. The app does not grant or bypass mailbox permissions — if a user lacks access, the sync will return a permission error. Grant folder-level access via Exchange Admin Center or PowerShell (Add-MailboxFolderPermission).

Type 1 — Entra ID group

Type 1 uses two separate Entra ID groups.

These are two different groups. A user in the access group sees the database. The contacts they see are the members of the contact group. A user can be in one, both, or neither — they are completely independent.

Group 1 — Access group (you create this)

Create this group with your prefix. Add the users or teams who should see this database as members. Put the config JSON in the description.

Name: EC_Contoso_CompanyContacts Object ID: a3f8b2c1-4d5e-6f7a-8b9c-0d1e2f3a4b5c Members: Sales Team, HR Team, ... Description: { "name": "Company Contacts", "description": "All company contacts", "autoLoad": true, "deleteable": false, "type": 1, "primaryId": "7e2d4f1a-9b3c-5e6d-7f8a-1b2c3d4e5f6a" }

Group 2 — Contact group (existing or new)

This can be any Entra ID group whose members you want to appear as contacts — an existing distribution list, security group, or a brand new group you create specifically for this purpose. You do not configure it in any special way; just copy its Object ID into primaryId in the access group's description.

Name: All-Employees Object ID: 7e2d4f1a-9b3c-5e6d-7f8a-1b2c3d4e5f6a ← this goes in primaryId

Type 2 — My Contacts folder

Name: EC_Contoso_MyContacts Description: { "name": "My Contacts", "description": "Personal Exchange contacts", "autoLoad": true, "deleteable": true, "type": 2, "primaryId": "jane@contoso.com" }
Membership controls access. Only users who are members of a database group (directly or via nested group) will see that database. The auto-discover process checks transitive membership, so nested groups work correctly.

Reference

primaryId values by type

Type primaryId secondaryId
0 — Mailbox User UPN, e.g. john@contoso.com Exchange folder ID (required)
1 — Entra ID group Object ID (GUID) of the contact source group — the group whose members become contacts. This is not the access group (the prefixed group) — it is a separate existing group. Not used — omit
2 — My Contacts User UPN, e.g. jane@contoso.com Not used — omit
Finding an Exchange folder ID: Use the Microsoft Graph Explorer (Graph Explorer) and call GET /users/{upn}/contactFolders to list all contact folders and their IDs for a given mailbox.

Legacy format (pipe-delimited)

Groups created before the JSON format was introduced continue to work without any changes. The app automatically detects the format and parses accordingly. There is no need to migrate existing groups.

Legacy pipe-delimited format (still supported): Name|Description|autoLoad|deleteable|type|primaryId|secondaryId Example: Company Contacts|All company contacts|1|0|1|<entra-group-object-id>

Security

Hardening the app registration

Enterprise Contacts is a public OAuth client — there is no client secret embedded in the app, by design. The trade-off is that the client ID is technically discoverable. The steps below close off the most practical abuse vectors and are recommended for all production deployments.

1

Restrict the redirect URI to mobile only

In Entra ID → App registrations → Enterprise Contacts → Authentication, confirm that the only platform configured is Mobile and desktop applications and the only redirect URI is:

msauth.com.nordexfood.ENTContacts://auth

Remove any Web platform entries. Without a web redirect URI the authorisation flow can only complete by handing the auth code to a custom URL scheme that iOS routes exclusively to the Enterprise Contacts app. A script or browser tab initiating the same flow has no way to receive the code.

2

Require user assignment

In Entra ID → Enterprise Applications → Enterprise Contacts → Properties, set User assignment required to Yes. Then go to Users and groups and add only the users or groups who should have access to the app.

Anyone outside those assignments cannot complete authentication — even if they attempt to use the client ID directly.

3

Require App Protection Policy (requires Intune)

If your organisation has Microsoft Intune or Microsoft 365 E3/E5 licensing, create a Conditional Access policy targeting the Enterprise Contacts application that requires an App Protection Policy. This is the strongest available control — it rejects any token acquired outside of an Intune-managed app, regardless of client ID.

If your tenant does not have Intune licensing, steps 1 and 2 together provide a solid baseline and match the security posture of most commercial enterprise mobile apps.

Why there is no client secret. Mobile apps cannot securely store a secret — the app binary can be extracted and inspected. Requiring a secret would create a false sense of security. The redirect URI restriction (step 1) is the correct mitigation for public clients and is the approach recommended by Microsoft's own identity platform guidance.