Skip to content

Preparing for DPG Outlook Office Addin

This document describes the configuration required to enable Single sign-on (App registration) for DPG Outlook Office Addin.

New or existing customer?

If you are a new customer, this app registration will be prepared as part of the initial configuration and delivery.

If you are an existing customer, and you have not previously prepared for using the new DPG Outlook Office Addin, you need to configure the app registration as instructed below. Once this is completed, and details about the app registration are handed over to the DPG Service Center, you you should not make changes to the app registration unless instructed by Timengo DPG Support.

DPG Outlook Office Addin authenticates with Azure as a Registered Application and authenticates using OAuth 2.0. For more information about this, see this Microsoft page.

There are two ways to register the app with Azure: You can run the PowerShell script provided below, or you can manually configure Azure by following step-by-step instructions.

This is the PowerShell script that can configure Azure for you:

Create-DPGAppRegistration script (zip file)

Or you can view it and copy it from here:

Create-DPGAppRegistration
# DPG Office Addin PowerShell Script Template
# Script to create Azure App Registration for DPG Office Add-in
# Requires Azure AD PowerShell module (Az.Resources) and Microsoft.Graph module

# Parameters
param(
    [Parameter(Mandatory=$false)]
    [string]$AppName = "DPG Office Add-in (dpgofficeaddin.dpgapi.dk)",

    [Parameter(Mandatory=$false)]
    [string[]]$RedirectUris = @(
        "https://dpgofficeaddin.dpgapi.dk",
        "brk-multihub://dpgofficeaddin.dpgapi.dk"
    ),

    [Parameter(Mandatory=$false)]
    [string]$MicrosoftOfficeClientId = "ea5a67f6-b6f3-4338-b240-c655ddc3cc8e",

    [Parameter(Mandatory=$false)]
    [string]$TenantId
)

# Check if required modules are installed
if (-not (Get-Module -ListAvailable -Name Microsoft.Graph.Authentication)) {
    Write-Host "Microsoft Graph PowerShell module not found. Installing..."
    Install-Module Microsoft.Graph -Scope CurrentUser -Force
}

if (-not (Get-Module -ListAvailable -Name Az.Accounts)) {
    Write-Host "Az.Accounts module not found. Installing..."
    Install-Module -Name Az.Accounts -Scope CurrentUser -Force
}

# Import required modules
Import-Module Az.Accounts
Import-Module Microsoft.Graph.Applications
Import-Module Microsoft.Graph.Authentication

# Disconnect from Microsoft Graph
Write-Host "Disconnecting from Microsoft Graph... So we can connect with required permissions"
Disconnect-MgGraph -ErrorAction SilentlyContinue | Out-Null

# Resolve tenant to use (optional interactive picker when multiple)
try {
    if ([string]::IsNullOrWhiteSpace($TenantId)) {
        Write-Host "Detecting available tenants..."
        Disconnect-AzAccount -ErrorAction SilentlyContinue | Out-Null
        Connect-AzAccount | Out-Null

        $tenants = Get-AzTenant | Select-Object Id, Name, DefaultDomain
        if (-not $tenants -or $tenants.Count -eq 0) {
            throw "No tenants available for the signed-in account."
        }

        if ($tenants.Count -gt 1) {
            Write-Host "Multiple tenants found:`n"
            for ($i = 0; $i -lt $tenants.Count; $i++) {
                $t = $tenants[$i]
                Write-Host ("[{0}] {1} ({2}) - {3}" -f ($i+1), $t.Name, $t.DefaultDomain, $t.Id)
            }

            do {
                $choice = Read-Host "Enter the number of the tenant to use"
                $parsed = 0
                $validInt = [int]::TryParse($choice, [ref]$parsed)
                $valid = $validInt -and ($parsed -ge 1) -and ($parsed -le $tenants.Count)
                if (-not $valid) { Write-Host "Invalid choice. Try again." -ForegroundColor Yellow }
            } while (-not $valid)

            $TenantId = $tenants[$parsed - 1].Id
        }
        else {
            $TenantId = $tenants[0].Id
        }
    }
}
catch {
    Write-Error "Failed to detect/select tenant: $_"
    exit 1
}

# Connect to Microsoft Graph with required permissions
try {
    Write-Host "Connecting to Microsoft Graph..."
    $scopes = @(
        "Application.ReadWrite.All",
        "Directory.ReadWrite.All",
        "DelegatedPermissionGrant.ReadWrite.All"
    )

    Connect-MgGraph -TenantId $TenantId -Scopes $scopes | Out-Null
}
catch {
    Write-Error "Failed to connect to Microsoft Graph: $_"
    exit 1
}

# Resolve tenant to use
try {
    $ctx = Get-MgContext
    $tenantId = $ctx.TenantId
    if ([string]::IsNullOrWhiteSpace($tenantId)) {
        throw "Could not resolve tenant ID from Microsoft Graph context."
    }
    Write-Host "Directory (tenant) ID selected: $tenantId"
}
catch {
    Write-Error "Failed to resolve tenant ID: $_"
    exit 1
}

# Create the application registration
try {
    # Create the application
    Write-Host "Creating application registration..."

    # Create with SPA redirect URIs (your previous script used SPARedirectUri)
    $app = New-MgApplication `
        -DisplayName $AppName `
        -SignInAudience "AzureADMyOrg" `
        -Spa @{ RedirectUris = $RedirectUris }

    if (-not $app) {
        throw "Failed to create application"
    }

    Write-Host "Application created successfully!"
    Write-Host "Application (client) ID: $($app.AppId)"
    Write-Host "Directory (tenant) ID: $tenantId"

    # Set the Application ID URI
    Write-Host "Setting Application ID URI..."
    $appIdUri = "api://dpgofficeaddin.dpgapi.dk/$($app.AppId)"
    Update-MgApplication -ApplicationId $app.Id -BodyParameter @{
        identifierUris = @($appIdUri)
    } | Out-Null

    # Create scope ID that we'll use for both the scope and pre-authorized application
    $scopeId = [guid]::NewGuid()

    # Build requiredResourceAccess for Microsoft Graph delegated permissions
    Write-Host "Adding API permissions..."
    $graphResourceAppId = "00000003-0000-0000-c000-000000000000" # Microsoft Graph

    $requiredResourceAccess = @(
        @{
            resourceAppId  = $graphResourceAppId
            resourceAccess = @(
                @{ id = "64a6cdd6-aab1-4aaf-94b8-3cc8405e90d0"; type = "Scope" }, # email
                @{ id = "37f7f235-527c-4136-accd-4a02d197296e"; type = "Scope" }, # openid
                @{ id = "14dad69e-099b-42c9-810b-d002981feec1"; type = "Scope" }, # profile
                @{ id = "570282fd-fa5c-430d-a7fd-fc8dc98a9dca"; type = "Scope" }, # Mail.Read
                @{ id = "e1fe6dd8-ba31-4d61-89e7-88639da4683d"; type = "Scope" }, # User.Read
                @{ id = "e383f46e-2787-4529-855e-0e479a3ffac0"; type = "Scope" }, # Mail.Send
                @{ id = "7b9103a5-4610-446b-9670-80643382c1fa"; type = "Scope" }, # Mail.Read.Shared
                @{ id = "a367ab51-6b49-43bf-a716-a1fb06d2a174"; type = "Scope" }  # Mail.Send.Shared
            )
        }
    )

    Write-Host "Adding 'Authenticated' scope..."
    $oauth2PermissionScopes = @(
        @{
            id = $scopeId
            adminConsentDescription = "Authenticated"
            adminConsentDisplayName = "Authenticated"
            userConsentDescription = "Authenticated"
            userConsentDisplayName = "Authenticated"
            isEnabled = $true
            type = "User"
            value = "Authenticated"
        }
    )

    Update-MgApplication -ApplicationId $app.Id -BodyParameter @{
        api = @{
            oauth2PermissionScopes = $oauth2PermissionScopes
            requestedAccessTokenVersion = 2
        }
        requiredResourceAccess = $requiredResourceAccess
    } | Out-Null

    Write-Host "Pre-authorizing Microsoft Office client..."
    Start-Sleep -Seconds 5

    Update-MgApplication -ApplicationId $app.Id -BodyParameter @{
        api = @{
            preAuthorizedApplications = @(
                @{
                    appId = $MicrosoftOfficeClientId
                    delegatedPermissionIds = @($scopeId)
                }
            )
        }
    } | Out-Null

    # Create a service principal for the application
    Write-Host "Creating service principal..."
    $servicePrincipal = New-MgServicePrincipal -AppId $app.AppId
    Start-Sleep -Seconds 5  # Wait for service principal to be fully created

    # Get Microsoft Graph service principal
    Write-Host "Getting Microsoft Graph permissions..."
    $graphServicePrincipal = Get-MgServicePrincipal -Filter "appId eq '$graphResourceAppId'"

    # Grant admin consent for all required permissions
    Write-Host "Granting admin consent for permissions..."
    try {
        Write-Host "Service Principal ID: $($servicePrincipal.Id)"
        Write-Host "Graph Service Principal ID: $($graphServicePrincipal.Id)"

        New-MgOauth2PermissionGrant `
            -ClientId $servicePrincipal.Id `
            -ConsentType "AllPrincipals" `
            -ResourceId $graphServicePrincipal.Id `
            -Scope "email openid profile Mail.Read User.Read Mail.Send Mail.Read.Shared Mail.Send.Shared" | Out-Null

        Write-Host "Successfully granted admin consent for permissions" -ForegroundColor Green
    }
    catch {
        Write-Host "Failed to grant admin consent for permissions: $_" -ForegroundColor Red
    }

    Write-Host "App registration setup completed successfully!"
    Write-Host ""
    Write-Host "Application details for handover to Timengo DPG:"
    Write-Host "Application (client) ID: $($app.AppId)"
    Write-Host "Directory (tenant) ID: $tenantId"

    $cwd = Split-Path -Path $PSCommandPath -Parent
    Set-Content -Path $cwd\DPGOfficeAddin-TechnicalDetails.txt -Value "Application (client) ID: $($app.AppId)`nDirectory (tenant) ID: $tenantId"
    write-host "Details saved to $cwd\DPGOfficeAddin-TechnicalDetails.txt"

    # Disconnect from Microsoft Graph
    Write-Host "Disconnecting from Microsoft Graph..."
    Disconnect-MgGraph -ErrorAction SilentlyContinue | Out-Null
}
catch {
    Write-Error "Failed to create app registration: $_"
    exit 1
}

Step-by-step instructions

Following the steps to manually configure Azure helps you to understand the configuration. The script provided above is an automated version of the steps below. Note that completing each step in sequence is important!

Complete the following steps to configure the App registration in Azure:

  1. Log in to Azure as an administrator, and go to Microsoft Entra ID.
  2. Select App registrations, and select New registration:
    App registrations

  3. Specify details for the app registration

    • Set Name as DPG Office Add-in (dpgofficeaddin.dpgapi.dk)
    • Select Supported account types as Accounts in this organization directory only (Single tenant)
    • Set Redirect URI to Single-page application (SPA), and set the value to https://dpgofficeaddin.dpgapi.dk
    • Finish by selecting Register.

    New registration

  4. Make a note of the Application (client) ID and Directory (tenant) ID from the Overview section as highlighted below.
    Get IDs

  5. Select Expose an API, and select Add to create an Application ID URI.

  6. Update the Application ID URI to api://dpgofficeaddin.dpgapi.dk/<Application (client) ID>, and finish by selecting Save:
    Update ID URI

  7. Now select Add a scope in the Expose an API pane, and insert the text Authenticated as shown below. Make sure to select Admin and users in the Who can consent? field, and Enabled in the State field. Finish by selecting Add scope:
    Add scope

  8. Still in the Expose an API pane, select Add a client application, and insert ea5a67f6-b6f3-4338-b240-c655ddc3cc8e, which pre-authorizes all Microsoft Office Application endpoints. Also select the Authorized scopes box, and finish by selecting Add application:
    Add application

  9. Open the API permissions pane, and select Add a permission:
    Add permission

  10. Select Microsoft Graph:
    MS Graph

  11. Select Delegated permissions:
    MS Graph permissions

  12. Select permissions for email, openid, profile, Mail.Read, Mail.Send, Mail.Read.Shared, Mail.Send.Shared, and User.Read. Finish by selecting Add permissions:
    MS Graph permissions
    MS Graph permissions
    MS Graph permissions
    MS Graph permissions

  13. In the Configured permissions pane, select Grant admin consent for…, and finish by selecting Yes.
    MS Graph permissions

  14. Once permissions have been granted, the Configured permissions view should look like this:
    MS Graph permissions

  15. Select Manifest, and change the value for "accessTokenAcceptedVersion" from null to 2, and select Save to finish.
    Manifest

  16. Select Authentication for the app registration you have created. In the section Single-page application Redirect URIs, select Add URI, and add the value brk-multihub://dpgofficeaddin.dpgapi.dk. Select Save to finish.
    Authentication

Handover to Timengo DPG

After completing the configuration steps, you must hand over the following details to Timengo DPG as specified in the welcome letter:

  • DPG Outlook Office Add-In configuration details:
    • Application (client) ID
    • Directory (tenant) ID

You have now completed the configuration for DPG Outlook Office Addin.