Unable to get MS Teams Shifts Schedule using MS Graph API - 403 Forbidden error

Karim Saleh 0 Reputation points
2023-05-19T13:40:04.4066667+00:00

Hi There,

I have been learning MS Graph API for the past few weeks to provision MS Teams Shifts using Powershell in my organization.

I have made a script to list all all Teams a user is a member of using their UPN and it worked fine.

But when it comes to the Script to List all Shift schedules in a Team, I always get a 403 Forbidden request. I am not sure how to resolve this issue as my Azure App Reg has all the required permissions. Also when I tested it on MS Graph Explorer it works fine but while on Powershell I have been facing the same error.

I have attached bellow a copy of my code along with the permissions that I have set for the API

Permissions Applied to the API following MS Graph Documentation
Updated API Permissions
Microsoft Graph>Delegated>email
Microsoft Graph>Delegated>Group.ReadWrite.All
Microsoft Graph>Delegated>profile
Microsoft Graph>Delegated>User.Read.All
Microsoft Graph>Delegated>WorkforceIntegration.ReadWrite.All
Microsoft Graph>Delegated>Schedule.ReadWrite.All

Microsoft Graph>Application>Schedule.ReadWrite.All
Microsoft Graph>Application>User.Read.All
Microsoft Graph>Application>Group.ReadWrite.All

Code Snippet

Import-Module Microsoft.Graph.Teams -ErrorAction SilentlyContinue
Import-Module Microsoft.Graph.Authentication -ErrorAction SilentlyContinue

# App Registration details
$clientId = "REDACTED"
$clientSecret = "REDACTED"
$tenantId = "REDACTED"
$teamId = "REDACTED"

# Set Microsoft Graph API URL and token endpoint
$graphAPIURL = "https://graph.microsoft.com/beta/teams/$teamId/schedule/shifts"
$tokenEndpoint = "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token"

# Set the scope for accessing Microsoft Graph
$scope = "https://graph.microsoft.com/.default"

# Create a token request
$tokenRequestBody = @{
    grant_type    = "client_credentials"
    client_id     = $clientId
    client_secret = $clientSecret
    scope         = $scope
}

# Get the access token
$tokenResponse = Invoke-RestMethod -Uri $tokenEndpoint -Method Post -Body $tokenRequestBody -ContentType "application/x-www-form-urlencoded"

# Call the Microsoft Graph API to list all shifts in the specified team
$headers = @{
    "Authorization" = "Bearer $($tokenResponse.access_token)"
}
try {
    $response = Invoke-RestMethod -Uri $graphAPIURL -Method Get -Headers $headers -ContentType "application/json"
    # Display the shifts
    $response.value
}
catch {
    Write-Host "StatusCode: $($_.Exception.Response.StatusCode.Value__)"
    Write-Host "StatusDescription: $($_.Exception.Response.StatusDescription)"
}
Microsoft Security | Microsoft Graph
{count} votes

3 answers

Sort by: Most helpful
  1. CarlZhao-MSFT 46,376 Reputation points
    2023-05-22T07:20:42.82+00:00

    Hi @Karim Saleh

    This is a known issue.

    When you call this API endpoint in the application context, you need to add the MS-APP-ACTS-AS request header:

    $headers = @{
        "Authorization" = "Bearer $($tokenResponse.access_token)"
        "MS-APP-ACTS-AS" = $userId 
    }
    

    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.

    1 person found this answer helpful.

  2. Simon Knutzen 25 Reputation points
    2025-01-10T14:39:21.0866667+00:00

    Hello together,

    it is really nice that you provided a solution (thanks for that!), but is there any information on why the MS-APP-ACTS-AS header is needed and if it will change in the future?

    For me, this seems like a bug and not a feature: If one is using the app-only access (which I'm clearly doing here) there should be no need for a MS-APP-ACTS-AS header (since the App is not acting as someone else but should authenticate by its own).

    This is still an issue for me since my customer is really unhappy that we need a user id in a header of an app only access prozess (since this is not really security comliant).

    Has anyone more information on this?

    Thanks!

    Simon

    1 person found this answer helpful.
    0 comments No comments

  3. GDB 11 Reputation points
    2024-09-02T10:35:45.5366667+00:00

    For those who're still struggling with this problem, my test result is that the required uid is one of the members in the Team (you looking for the Shifts in this Team).

    (Sorry) In Python:

    url = 'https://graph.microsoft.com/v1.0/users/<UPN of a Team member user>'
    r = requests.get(url=url, headers=headers).json()
    uid = r['id']
    
    headers = {
       'Authorization': f'Bearer {access_token}',
       'Content-Type': 'application/json',
       'MS-APP-ACTS-AS': f'{uid}'
    }
    

    The query result if the uid is not a Team member:

    {'error': {'code': 'NotFound', 'message': '{"error":{"code":"NotFound","message":"Sorry, the user was not found and may have been deleted","details":[],"innererror":{"code":" ...
    
    0 comments No comments

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.