After the successful token generation I get 401 error when I try to get my mails via Graph API

Zsolt Kallai 5 Reputation points
2023-08-03T13:36:40.4333333+00:00

Good Afternoon,

I would like to write a powershell script to get my emails from my outlook via Oauth2 token without user login, but unfortunately no luck. I am able to generate correctly my token successfully and I can see on "jwt.ms" website there is a required permisson on it, but for some reason its just not working.

If I generate a token with "graph explorer" and paste into my code directly, (so if i am not generating the token from powershell code), all option works fine and I can get back all details from my outlook. So its something regarding the token and permisson but I am not sure what excatly.
access

Interesting thing is, if I change thte code from:

$Uri = "https://graph.microsoft.com/v1.0/users/*********************************/messages"

to:

$Uri = "https://graph.microsoft.com/v1.0/users/*********************************/

In this case the API will give back my profile details.

jwt.ms result:
https://pastebin.com/tMmxfn5d

  "roles": [
    "Mail.ReadWrite",
    "Mail.ReadBasic.All",
    "Directory.Read.All",
    "User.Read.All",
    "Mail.Read",
    "Mail.Send",
    "Contacts.Read",
    "Mail.ReadBasic"
  ],

Error message:

Invoke-RestMethod: The remote server returned an error: (401) Unauthorized. At line:29 char:17
+ ... rResponse = Invoke-RestMethod -Method Get -Uri $Uri -Headers $Headers ...
+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
# Define the URI and parameters
$Uri = "https://login.microsoftonline.com/*********************************/oauth2/v2.0/token"
$Body = @{
    "grant_type"    = "client_credentials"
    "client_id"     = "*********************************"
    "client_secret" = "*********************************"
    "scope"      = "https://graph.microsoft.com/.default"
}
$ContentType = "application/x-www-form-urlencoded"

# Send the POST request
$Response = Invoke-RestMethod -Method Post -Uri $Uri -Body $Body -ContentType $ContentType


# Display the access token
Write-Output "Access Token: $($Response.access_token)"

# Replace "{id | userPrincipalName}" with the id or userPrincipalName of the user
$Uri = "https://graph.microsoft.com/v1.0/users/*********************************/messages"

# Define the header for the "user" request
$Headers = @{
    "Authorization" = "Bearer $($Response.access_token)"
}


# Send the GET request
$UserResponse = Invoke-RestMethod -Method Get -Uri $Uri -Headers $Headers

# Display the "user" information
Write-Output $UserResponse

Thank you.

Windows for business | Windows Server | User experience | PowerShell
Microsoft Security | Microsoft Graph
{count} votes

1 answer

Sort by: Most helpful
  1. CarlZhao-MSFT 46,376 Reputation points
    2023-08-04T08:03:11.7366667+00:00

    Hi @Zsolt Kallai

    • Make sure the target user has an O365 license.
    • Make sure the target user is a work account and not a personal or guest account.

    I did a quick test with your script and it works fine.

    3

    Hope this helps.

    If the reply is helpful, please click Accept Answer and kindly upvote it. If you have additional questions about this answer, please click Comment.


Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.