Register Adaxes as an app in Entra ID

To allow Adaxes to interact with your Entra organization and perform operations on your behalf, you need to register Adaxes as an application in Entra ID.

App registration establishes a trust relationship between Adaxes and the Microsoft identity platform. This enables Adaxes to authenticate as the app and access resources according to the permissions you assign. The app registration may serve one or more of the following purposes:

  • Grant Adaxes access to manage Entra ID, Microsoft 365, and Exchange Online
  • Allow users to sign in to the Adaxes web interface using Entra account credentials
  • Enable Adaxes to send email notifications via Exchange Online

This article outlines the steps to register the application and configure its permissions for managing your Entra organization. For details on how to configure the app for sending emails, see Configure mail settings.

If you prefer a quick automated setup of an app and all its permissions, you can use this script instead of following the below steps.

Create an application

To register an application and grant it all the necessary permissions, you need an account with at least the following roles:

  • Application Administrator role in Entra ID
  • Role Management role in Exchange Online
  1. Sign in to the Microsoft Entra admin center.

  2. Browse to Entra ID > App registrations and select New registration.

  3. Enter the application name (e.g. Adaxes).

  4. Configure the redirect URI to enable cloud-only accounts to sign in to Adaxes web interface.

    • In the Redirect URI (optional) section, select Single-page application (SPA) from the drop-down menu.

    • Specify the URL of your Adaxes web interface. Make sure the URL does not end with a slash and does not include the configuration name, such as Admin, HelpDesk, or SelfService.

      Example:

      https://server.example.com/Adaxes
      

    If you haven't deployed the web interface yet or are unsure of its final URL, feel free to skip this step and come back to it later.

     How to set the redirect URI after creating the app {id=configure-redirect-uri}
    1. Sign in to the Microsoft Entra admin center.

    2. Browse to Entra ID > App registrations and select the application Adaxes uses to manage your Entra domain.

    3. On the app Overview page, click Authentication.

    4. Click Add Redirect URI.

    5. In the dialog that opens, select Single-page application.

    6. Specify the URL of your Adaxes web interface in the Redirect URI field. Make sure the URL does not end with a slash and does not include the configuration name, such as Admin, HelpDesk, or SelfService.

      Example:

      https://server.example.com/Adaxes
      
    7. Click Configure.

  5. Click Register.

  6. Copy the Application (client) ID and paste it into the corresponding field in Adaxes administration console.

  7. Copy the Directory (tenant) ID and paste it into the corresponding field in Adaxes administration console.

Add a client secret

  1. On the app Overview page in the Entra admin center, click Add a certificate or secret.

  2. Click New client secret.

  3. Specify a description for the new client secret, select its expiration period, and then click Add

  4. Copy the client secret Value and paste it into the Client secret field in Adaxes administration console.

Adaxes cannot authenticate with these credentials yet because the app lacks the required permissions and roles. Read on for details about how to set them up.

Add API permissions

In this section, you'll assign the API permissions that enable Adaxes to perform its core tasks. Required permissions are grouped by API, and each table outlines what Adaxes functionality depends on which permission.

Microsoft Graph API permissions

Adaxes relies on these permissions to manage users, reset passwords, assign licenses, and perform other directory-level operations.

  • Permission

  • Reason

  • User.ReadWrite.All

  • View, create, update, and delete user accounts.

  • User-PasswordProfile.ReadWrite.All

  • Reset users' passwords.

  • UserAuthenticationMethod.ReadWrite.All

  • Reset users' multifactor authentication methods.

  • User.EnableDisableAccount.All

  • Enable and disable accounts of role-assignable group members.

  • LicenseAssignment.ReadWrite.All

  • Assign and revoke Microsoft 365 licenses.

  • Application.Read.All

  • Notify about the application client secret expiration date.

    If you do not add this permission, it is recommended to set the Entra.AppSecretExpirationWarningDaysThreshold parameter to 0 to prevent errors in the notification area. For details on changing configuration parameter values, see this help article.

  • AuditLog.Read.All

  • Read users' last sign in information. Required only for domain management.

  • Sites.ReadWrite.All

  • Modify properties stored in external sources e.g. employee hire date stored in SharePoint. Required only for domain management.

  • Group.ReadWrite.All

  • View, create, update, delete groups and add/remove group members. Required only for domain management.

  • RoleManagement.ReadWrite.Directory

  • Create role-assignable groups. Required only for domain management.

  • DeviceManagementConfiguration.ReadWrite.All

  • Propagate password self-service client settings to Entra devices. Required only for domain management.

To add them:

  1. On the app Overview page in the Entra admin center, click API permissions.

  2. Click Add a permission.

  3. Click Microsoft Graph and then select Application permissions.

  4. Select the required permissions from the list.

    You may omit permissions for features you don't plan to use. You may also add extra permissions if you plan to extend the built-in functionality with custom scripts that perform operations not listed above.

  5. When done, click Add permissions.

Office 365 Exchange Online permissions

These permissions enable Adaxes to authenticate with Exchange Online and send emails as an application. They do not grant access to manage mailboxes, groups, or other Exchange resources – those capabilities are controlled separately via admin roles.

  • Permission

  • Reason

  • Exchange.ManageAsApp

  • Connect to Exchange Online.

  • SMTP.SendAs.App

  • Send emails as an app. Optional

To add them:

  1. On the app Overview page in the Entra admin center, click API permissions.

  2. Click Add a permission.

  3. Activate the APIs my organization uses tab.

  4. Locate and click the Office 365 Exchange Online API.

  5. Select Application permissions.

  6. Select the required permissions from the list.

  7. Click Add permissions.

Alternative option: add permissions to the application manifest

All the required Microsoft Graph API permissions and Office 365 Exchange Online permissions are also available as a JSON that can be pasted directly into the Entra application manifest instead of adding them one by one.

 Details {id="json-manifest"}
  1. On the app Overview page in the Entra admin center, click Manifest.

  2. Locate the requiredResourceAccess key in the manifest.

  3. Set the key to the following value.

"requiredResourceAccess": [
    {
        "resourceAppId": "00000003-0000-0000-c000-000000000000",
        "resourceAccess": [
            {
                "id": "9a5d68dd-52b0-4cc2-bd40-abcf44ac3a30",
                "type": "Role"
            },
            {
                "id": "b0afded3-3588-46d8-8b3d-9842eff778da",
                "type": "Role"
            },
            {
                "id": "9241abd9-d0e6-425a-bd4f-47ba86e767a4",
                "type": "Role"
            },
            {
                "id": "62a82d76-70ea-41e2-9197-370581804d09",
                "type": "Role"
            },
            {
                "id": "5facf0c1-8979-4e95-abcf-ff3d079771c0",
                "type": "Role"
            },
            {
                "id": "9e3f62cf-ca93-4989-b6ce-bf83c28f9fe8",
                "type": "Role"
            },
            {
                "id": "9492366f-7969-46a4-8d15-ed1a20078fff",
                "type": "Role"
            },
            {
                "id": "cc117bb9-00cf-4eb8-b580-ea2a878fe8f7",
                "type": "Role"
            },
            {
                "id": "3011c876-62b7-4ada-afa2-506cbbecc68c",
                "type": "Role"
            },
            {
                "id": "741f803b-c850-494e-b5df-cde7c675a1ca",
                "type": "Role"
            },
            {
                "id": "50483e42-d915-4231-9639-7fdb7fd190e5",
                "type": "Role"
            }
        ]
    },
    {
        "resourceAppId": "00000002-0000-0ff1-ce00-000000000000",
        "resourceAccess": [
            {
                "id": "dc50a0fb-09a3-484d-be87-e023b12c6440",
                "type": "Role"
            },
            {
                "id": "7146a1f0-8703-45b3-9eae-527a64c00995",
                "type": "Role"
            }
        ]
    }
]
  1. Click Save.

  2. Click API permissions.

  3. Verify that the list contains the required permissions.

After adding the API permissions, click Grant admin consent for <tenant name> and then click Yes to confirm. Admin consent is required to make the added permissions effective.

Assign Exchange admin roles

The app requires the following admin roles.

  • Role

  • Reason

  • Mail Recipients

  • Manage existing mailboxes, mail users, and mail contacts. Verify that all the required roles are assigned to the Adaxes application in Exchange Online.

  • Mail Recipient Creation

  • Create mailboxes, mail users, mail contacts, and distribution groups.

  • Distribution Groups

  • Create and manage distribution groups and their members.

  • Security Group Creation and Membership

  • Create and manage mail-enabled security groups and their members.

  • Move Mailboxes

  • Move mailboxes between servers in an organization.

  • Retention Management

  • Manage retention policies.

  • Organization Client Access

  • Define which Exchange ActiveSync mobile devices are allowed.

Unlike API permissions, Exchange Online admin roles cannot be assigned directly to an app. Instead, you must create an Exchange service principal that corresponds to the Entra service principal of the registered application. This allows Exchange to recognize the app as a manageable identity.

This has to be done via the Exchange Online Powershell V3 module from Microsoft. Make sure you have it installed.

  1. Obtain the service principal identifiers

    You'll need the Application ID and Object ID of the app's Entra service principal.

    • Open the Microsoft Entra admin center.

    • Browse to Entra ID > Enterprise apps and select your application.

    • The identifiers will be displayed in the Properties section, in the Application ID and Object ID fields respectively.

  2. Run the PowerShell script

    Launch Windows PowerShell and execute the following script. The script will create an Exchange service principal if one doesn't already exist, combine the required roles into a new role group, and add the app to that role group. In the script:

    • $applicationId – the Application ID of the Entra service principal.
    • $objectId – the Object ID of the Entra service principal.
    • $displayName – a user-friendly display name for the new Exchange service principal.
    • $roleGroupName – the name of the new role group that will contain all the permissions required by Adaxes. For example, Adaxes app permissions.
    $applicationId = "<appID>"
    $objectId = "<objectID>"
    $displayName = "<displayName>"
    $roleGroupName = "<roleGroupName>"
    
    $roles = @(
        "Mail Recipients",
        "Mail Recipient Creation",
        "Distribution Groups",
        "Security Group Creation and Membership",
        "Move Mailboxes",
        "Retention Management",
        "Organization Client Access"
    )
    
    Connect-ExchangeOnline
    try 
    {
        $servicePrincipal = Get-ServicePrincipal -Identity $applicationId -ErrorAction Stop
    }
    catch 
    {
        # Create Exchange principal if it doesn't exist.
        $servicePrincipal = New-ServicePrincipal `
            -AppId $applicationId -ObjectId $objectId -DisplayName $displayName
    }
    New-RoleGroup -Name $roleGroupName -Roles $roles -Members $servicePrincipal.Identity
    Disconnect-ExchangeOnline
    

The app registration is ready. You can now return to the Adaxes administration console and complete the rest of the steps there.

Quick app registration with a script

If you are already familiar with the manual app registration process but want to skip the repetitive steps, you can do it with a PowerShell script provided below. The script requires Microsoft Graph and Exchange Online Powershell V3 modules.

The script will prompt you to authenticate using an account with at least the following roles:

  • Application Administrator role in Entra ID
  • Role Management role in Exchange Online
 Register application

The script registers an app with the specified name, creates a client secret, and assigns all required API permisions and Exchange admin roles to the app.

If the app registration succeeds, the script outputs the Application (client) ID, Directory (tenant) ID, and Client Secret into the console. If the app registration fails at any point, the script rolls back the changes in your Entra ID.

In the script:

  • $appName – the display name for the app registration.
  • $redirectUri – the URI of your Adaxes web interface. For example: https://server.example.com/Adaxes.
  • $secretDisplayName – a friendly name for the client secret.
  • $secretExpiryDaysFromNow – number of days until the client secret expires.
  • $roleGroupName – the name of the Exchange role group that will contain all required roles.
  • $maxAttempts – the maximum number of attempts to create the Exchange service principal. Sometimes the principal is not created on the first attempt because of propagation delays in Entra ID.
# Aplication registration parameters.
$appName = "Adaxes App"
$redirectUri = "https://server.example.com/Adaxes"
$secretDisplayName = "Adaxes Client Secret"
$secretExpiryDaysFromNow = 730 # 2 years
$roleGroupName = "Adaxes Application Role Group"
$maxAttempts = 5

# Required API permissions for the application.
$requiredResourceAccess = @(
    @{
        resourceAppId  = "00000003-0000-0000-c000-000000000000" # Microsoft Graph
        resourceAccess = @(
            @{ id = "b0afded3-3588-46d8-8b3d-9842eff778da"; type = "Role" } # AuditLog.Read.All
            @{ id = "9a5d68dd-52b0-4cc2-bd40-abcf44ac3a30"; type = "Role" } # Application.Read.All
            @{ id = "62a82d76-70ea-41e2-9197-370581804d09"; type = "Role" } # Group.ReadWrite.All
            @{ id = "9492366f-7969-46a4-8d15-ed1a20078fff"; type = "Role" } # Sites.ReadWrite.All
            @{ id = "741f803b-c850-494e-b5df-cde7c675a1ca"; type = "Role" } # User.ReadWrite.All
            @{ id = "50483e42-d915-4231-9639-7fdb7fd190e5"; type = "Role" } # UserAuthenticationMethod.ReadWrite.All
            @{ id = "cc117bb9-00cf-4eb8-b580-ea2a878fe8f7"; type = "Role" } # User-PasswordProfile.ReadWrite.All
            @{ id = "3011c876-62b7-4ada-afa2-506cbbecc68c"; type = "Role" } # User.EnableDisableAccount.All
            @{ id = "5facf0c1-8979-4e95-abcf-ff3d079771c0"; type = "Role" } # LicenseAssignment.ReadWrite.All
            @{ id = "9241abd9-d0e6-425a-bd4f-47ba86e767a4"; type = "Role" } # DeviceManagementConfiguration.ReadWrite.All
            @{ id = "9e3f62cf-ca93-4989-b6ce-bf83c28f9fe8"; type = "Role" } # RoleManagement.ReadWrite.Directory
        )
    },
    @{
        resourceAppId  = "00000002-0000-0ff1-ce00-000000000000" # Exchange Online
        resourceAccess = @(
            @{ id = "dc50a0fb-09a3-484d-be87-e023b12c6440"; type = "Role" } # Exchange.ManageAsApp
            @{ id = "7146a1f0-8703-45b3-9eae-527a64c00995"; type = "Role" } # SMTP.SendAs.App
        )
    }
)

# Required Exchange Online roles.
$roles = @(
    "Mail Recipients",
    "Mail Recipient Creation",
    "Distribution Groups",
    "Security Group Creation and Membership",
    "Move Mailboxes",
    "Retention Management",
    "Organization Client Access"
)

# Ensure the required modules are installed.
if (-not (Get-Module -ListAvailable Microsoft.Graph)) { throw "Microsoft.Graph module not found." }
if (-not (Get-Module -ListAvailable ExchangeOnlineManagement)) { throw "ExchangeOnlineManagement module not found." }

try {
    # Connect to Exchange Online and Microsoft Graph.
    Connect-MgGraph -Scopes "Application.ReadWrite.All", "AppRoleAssignment.ReadWrite.All"
    Connect-ExchangeOnline
}
catch { throw "Failed to connect to Entra ID or Exchange Online: $_" }

# Verify that the specified app and role group name is unique.
if (Get-MgApplication -Filter "displayName eq '$appName'") { throw "An app named '$appName' already exists." }
if (Get-RoleGroup -Identity $roleGroupName -ErrorAction SilentlyContinue) { throw "A role group named '$roleGroupName' already exists." }

try {
    # Create Entra application registration and service principal.
    $app = New-MgApplication `
        -DisplayName $appName `
        -RequiredResourceAccess $requiredResourceAccess `
        -Spa @{ RedirectUris = @($redirectUri) } `
        -ErrorAction Stop
    $secret = Add-MgApplicationPassword `
        -ApplicationId $app.Id `
        -PasswordCredential @{
        DisplayName = $secretDisplayName
        EndDateTime = (Get-Date).AddDays($secretExpiryDaysFromNow)
    } `
        -ErrorAction Stop
    $servicePrincipal = New-MgServicePrincipal -AppId $app.AppId

    # Grant admin consent for the API permissions.
    foreach ($resource in $requiredResourceAccess) {
        $resourceAppId = $resource.resourceAppId
        $targetApi = Get-MgServicePrincipal -Filter "appId eq '$resourceAppId'"

        foreach ($permission in $resource.resourceAccess) {
            $params = @{
                "PrincipalId" = $servicePrincipal.Id
                "ResourceId"  = $targetApi.Id
                "AppRoleId"   = $permission.Id
            }
            New-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $servicePrincipal.Id -BodyParameter $params
        }
    }

    # Create a service principal in Exchange Online.
    $exchangeServicePrincipal = $null
    $attempt = 0
    while ($attempt -lt $maxAttempts -and -not $exchangeServicePrincipal) {
        $attempt++
        try {
            $exchangeServicePrincipal = New-ServicePrincipal `
                -AppId $app.AppId `
                -ObjectId $servicePrincipal.Id `
                -DisplayName $appName `
                -ErrorAction Stop
            break
        }
        catch {
            if ($attempt -ge $maxAttempts) {
                throw "Exchange service principal creation failed after $maxAttempts attempts."
            }
            $retryInterval = $attempt * $maxAttempts
            Write-Warning "Attempt $attempt to create Exchange service principal failed. Retrying in $retryInterval seconds."
            Start-Sleep -Seconds $retryInterval
        }
    }
    
    # Create a role group in Exchange Online and assign it to the service principal.
    $roleGroup = New-RoleGroup `
        -Name $roleGroupName `
        -Roles $roles `
        -Members $exchangeServicePrincipal `
        -ErrorAction Stop
}
catch {
    Write-Error "Failed to create the application registration: $_"
    if ($app) {
        # Remove incomplete application registration.
        Remove-MgApplication -ApplicationId $app.Id -Confirm:$false
    }
    if ($exchangeServicePrincipal) {
        # Remove Exchange service principal.
        Remove-ServicePrincipal -Identity $exchangeServicePrincipal -Confirm:$false
    }
    if ($roleGroup) {
        # Remove Exchange role group.
        Remove-RoleGroup -Identity $roleGroupName -Confirm:$false
    }
    return
}

# Output a summary of the created application.
Write-Host `n"App '$appName' created successfully."
Write-Host "Application ID: $($app.AppId)"
Write-Host "Tenant ID: $((Get-MgOrganization).Id)"
Write-Host "Client Secret: $($secret.SecretText)"

# Disconnect from Microsoft Graph and Exchange Online.
Disconnect-MgGraph | Out-Null
Disconnect-ExchangeOnline -Confirm:$false
 Remove application

The script deletes the app registration with the specified name from you Entra ID, deletes the related Entra and Exchange service principals, and deletes the role group created for the app in Exchange.

In the script:

  • $appName – the display name of the app registration.
  • $deleteRoleGroup – set to $true to delete the role created during app registration, or set to $false to leave it in Exchange Online.
$appName = "Adaxes App"
$deleteRoleGroup = $true

try {
    # Connect to Exchange Online and Microsoft Graph.
    Connect-MgGraph -Scopes "Application.ReadWrite.All", "AppRoleAssignment.ReadWrite.All"
    Connect-ExchangeOnline
}
catch { throw "Failed to connect to Entra ID or Exchange Online: $_" }
    
# Find the app and the Exchange service principal.
$app = Get-MgApplication -Filter "displayName eq '$appName'"
if (-not $app) { throw "App '$appName' not found." }
$servicePrincipal = Get-ServicePrincipal $app.AppId
if (-not $servicePrincipal) { throw "Exchange service principal for app '$appName' not found." }

# Remove any role groups assigned to the app.
if ($deleteRoleGroup) {
    $roleGroups = Get-RoleGroup | Where-Object { $_.Members -contains $servicePrincipal.Id }
    if ($roleGroups) {
        $roleGroups | ForEach-Object { Remove-RoleGroup $_ -Confirm:$false }
    }
    else {
        Write-Host "No role groups assigned to '$appName' found."
    }
}

# Remove the Exchange service principal and the app registration.
Remove-ServicePrincipal -Identity $servicePrincipal.Id -Confirm:$false
Remove-MgApplication -ApplicationId $app.Id -Confirm:$false

# Disconnect from Microsoft Graph and Exchange Online.
Disconnect-MgGraph | Out-Null
Disconnect-ExchangeOnline -Confirm:$false