PowerShell

Microsoft Graph – InvalidAuthenticationToken – Access token validation failure. Invalid audience

Today I had a need to connect to Microsoft Graph and do some tasks on Office 365. Since I have already done similar stuff for my PSwinDocumentation.O365HealthService PowerShell module that I've described in PowerShell to get all information about Office 365 Service HealthI thought this will be easy run as I'll just reuse the code I've done for that module. As always for Graph related tasks you need to register your application and assign correct permissions. I've used my own article for that with changes to which API I want to access. Now that I've done all that I've extracted my Connect-O365Graph function from my module and started connecting.

function Connect-O365Graph {
    [cmdletBinding()]
    param(
        [string][alias('ClientID')] $ApplicationID,
        [string][alias('ClientSecret')] $ApplicationKey,
        [string] $TenantDomain
    )
    $Body = @{
        grant_type    = "client_credentials"
        resource      = "https://manage.office.com"
        client_id     = $ApplicationID
        client_secret = $ApplicationKey
    }
    try {
        $Authorization = Invoke-RestMethod -Method Post -Uri "https://login.microsoftonline.com/$($TenantDomain)/oauth2/token" -Body $body -ErrorAction Stop
    } catch {
        $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " "
        Write-Warning -Message "Connect-O365Graph - Error: $ErrorMessage"
    }
    if ($Authorization) {
        @{'Authorization' = "$($Authorization.token_type) $($Authorization.access_token)" }
    } else {
        $null
    }
}


$ApplicationID = '3f53f084'
$DirectoryID = $TenantDomain = 'e486b948'
$ApplicationSecret = '3=bA' # expires  12/2/2020

$Authorization = Connect-O365Graph -ApplicationID $ApplicationID -ApplicationKey $ApplicationSecret -TenantDomain $DirectoryID
$Authorization | Format-List *

The code worked, as always (!), without a problem. I got my usual Authorization Token from that command.

Now we just need to execute some simple Graph query and we're good to go.

$RestSplat = @{
    Uri         = 'https://graph.microsoft.com/v1.0/Groups/'
    Headers     = $Authorization
    Method      = 'GET'
    ContentType = "application/json"
}

Invoke-RestMethod @RestSplat

But to my surprise this just wasn't working.

Invoke-RestMethod : {
  "error": {
    "code": "InvalidAuthenticationToken",
    "message": "Access token validation failure. Invalid audience.",
    "innerError": {
      "request-id": "8f9235b6-4054-4400",
      "date": "2019-12-03T10:22:23"
    }
  }
}

After testing that my authorization token works as designed I finally was able to find where I've made mistake.

InvalidAuthenticationToken - Access token validation failure. Invalid audience.

My fault was that I was assuming it's all using same resource to connect and I was simply using https://manage.office.com. But in fact I should have been using https://graph.microsoft.com for those queries.

function Connect-O365Graph {
    [cmdletBinding()]
    param(
        [string][alias('ClientID')] $ApplicationID,
        [string][alias('ClientSecret')] $ApplicationKey,
        [string] $TenantDomain,
        [ValidateSet("https://manage.office.com", "https://graph.microsoft.com")] $Resource = "https://manage.office.com"
    )
    $Body = @{
        grant_type    = "client_credentials"
        resource      = $Resource
        client_id     = $ApplicationID
        client_secret = $ApplicationKey
    }
    try {
        $Authorization = Invoke-RestMethod -Method Post -Uri "https://login.microsoftonline.com/$($TenantDomain)/oauth2/token" -Body $body -ErrorAction Stop
    } catch {
        $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " "
        Write-Warning -Message "Connect-O365Graph - Error: $ErrorMessage"
    }
    if ($Authorization) {
        @{'Authorization' = "$($Authorization.token_type) $($Authorization.access_token)" }
    } else {
        $null
    }
}
$Authorization = Connect-O365Graph -ApplicationID $ApplicationID -ApplicationKey $ApplicationSecret -TenantDomain $DirectoryID -Resource https://graph.microsoft.com
$Authorization | Format-List *

In this case, I've changed my PowerShell function to accept different resource URLs. After providing proper Resource URI everything started to work! This is something to remember when playing with Graph, that there may be different Resource EndPoints that we need to use.

This post was last modified on April 1, 2021 16:44

Przemyslaw Klys

System Architect with over 14 years of experience in the IT field. Skilled, among others, in Active Directory, Microsoft Exchange and Office 365. Profoundly interested in PowerShell. Software geek.

Share
Published by
Przemyslaw Klys

Recent Posts

Active Directory Replication Summary to your Email or Microsoft Teams

Active Directory replication is a critical process that ensures the consistent and up-to-date state of…

2 weeks ago

Syncing Global Address List (GAL) to personal contacts and between Office 365 tenants with PowerShell

Hey there! Today, I wanted to introduce you to one of the small but excellent…

5 months ago

Active Directory Health Check using Microsoft Entra Connect Health Service

Active Directory (AD) is crucial in managing identities and resources within an organization. Ensuring its…

7 months ago

Seamless HTML Report Creation: Harness the Power of Markdown with PSWriteHTML PowerShell Module

In today's digital age, the ability to create compelling and informative HTML reports and documents…

8 months ago

How to Efficiently Remove Comments from Your PowerShell Script

As part of my daily development, I create lots of code that I subsequently comment…

9 months ago

Unlocking PowerShell Magic: Different Approach to Creating ‘Empty’ PSCustomObjects

Today I saw an article from Christian Ritter, "PowerShell: Creating an "empty" PSCustomObject" on X…

9 months ago