Microsoft Graph API: Access token validation failure. Invalid audience - oauth-2.0

I am trying to migrate my app from Office 365 REST v2.0 to Microsoft Graph (v1.0). The token exchange seems to be working but as soon as I am trying to call an API, I am getting the following error:
(
[errorNumber] => 401
[error] => Request returned HTTP error 401
[message] => {
"error": {
"code": "InvalidAuthenticationToken",
"message": "Access token validation failure. Invalid audience.",
"innerError": {
"date": "2021-03-16T15:36:21",
"request-id": "dda1e33a-2774-4986-8c45-1487404fbb72",
"client-request-id": "e842d9a8-d71b-0563-f1ce-e58052e5bdb9"
}
}
}
)
The access_token has the following audience:
"aud": "https://outlook.office.com"
Here is the endpoint that I am using:
https://login.microsoftonline.com/common/oauth2/v2.0/token
Payload:
grant_type=authorization_code
&code=0.AR8A3XwQy0FAmkSxxxx
&redirect_uri=https%3A%2F%2Fxxx.com%2Fproxy%2Foffice365authorize
&client_id=e2147faf-87f0-4e7f-xxxx-xxxxxxxxxxx
&client_secret=xxxxxxxxxxxx
Any hint would be greatly appreciated, thanks!

This means your token has the wrong audience, to call the Micrsoft Graph API, you need to get the token for Microsoft Graph i.e. the access token needs the "aud": "https://graph.microsoft.com".
Looks you are using the AAD auth code flow to get the token, so when you request an authorization code, use the scope with https://graph.microsoft.com/.default.
https://login.microsoftonline.com/common/oauth2/authorize?
client_id=xxxxx
&response_type=code
&redirect_uri=xxxxxx
&response_mode=query
&scope=https://graph.microsoft.com/.default
&state=12345
Also use scope=https://graph.microsoft.com/.default when requesting the token.
POST https://login.microsoftonline.com/common/oauth2/v2.0/token
client_id=xxxxxx
&scope=https://graph.microsoft.com/.default
&code=0.AR8A3XwQy0FAmkSxxxx
&redirect_uri=xxxxxx
&grant_type=authorization_code
&client_secret=xxxxx
To call the API successfully, also make sure you have grant correct Delegated Microsoft Graph API permissions for your client app depends on the API you want to call, e.g. if you want to call List users, you need the permissions here.

Related

"AADSTS54005: OAuth2 Authorization code was already redeemed, please retry with a new valid code or use an existing refresh token" Az API Management

I am trying to obtain an authorization token to consume a published API in Azure API Management, for which I am performing the following steps:
Call the authorization URL as follows:
https://login.microsoftonline.com/common/oauth2/authorize?
client_id=<CLIENT_ID>
&response_type=code
&response_mode=query
&redirect_uri=<REDIRECT_URI>
&scope=SCOPE
Immediately after, I call the following URL with the obtained authorization code and other parameters in the body and to send them as form-data:
POST https://login.microsoftonline.com/common/oauth2/token
client_id=<CLIENT_ID>
scope=SCOPE
grant_type=authorization_code
client_secret=<CLIENT_SECRET>
code=<AUTHORIZATION_CODE_PREVIOUS_STEP>
As a result, I get the following error and cannot continue:
{
"error": "invalid_grant",
"error_description": "AADSTS54005: OAuth2 Authorization code was already redeemed, please retry with a new valid code or use an existing refresh token.\r\nTrace ID: f0264d85-2f41-4009-9e8e-1a211209e100\r\nCorrelation ID: c6b15ffb-82e8-49aa-941f-6c85be4d9601\r\nTimestamp: 2022-01-18 15:06:55Z",
"error_codes": [
54005
],
"timestamp": "2022-01-18 15:06:55Z",
"trace_id": "f0264d85-2f41-4009-9e8e-1a211209e100",
"correlation_id": "c6b15ffb-82e8-49aa-941f-6c85be4d9601"
}
I understand that the authorization code is for one use only but, in my case, on the first attempt I get this error.
Any help is appreciated

Unknown Error when sending/replying to message on MS Teams using Graph API

I am trying to send a message or reply to a message using Graph APIs for MS Teams. I have the correct permissions set and also have access to Protected APIs (if thats a concern).
The APIs I use to send messages are for both channel and 1:1 chat message.
POST URL Request:
https://graph.microsoft.com/beta/chats/{chat-id}/messages/{message-id}/replies
https://graph.microsoft.com/beta/chats/{chat-id}/messages/
https://graph.microsoft.com/beta/users/{user-id}/chats/{chat-id}/messages/
https://graph.microsoft.com/beta/teams/{team-id}/channels/{channel-id}/messages/{message-id}/replies
https://graph.microsoft.com/beta/teams/{team-id}/channels/{channel-id}/messages
Permissions set are ChannelMessage.Send, Group.ReadWrite.All, ChatMessage.Send for both delegated and application level.
I use a 2-step process to authorize the client /authorize and then /adminconsent.
When trying to post message I always get "UnknownError" and empty message with 401 status code.
{
"error": {
"code": "UnknownError",
"message": "",
"innerError": {
"date": "2020-07-10T04:58:06",
"request-id": "ff58128b-585b-4242-99c4-011c8e537d94"
}
}
}
Is this some issue with my app or from MS graph side?
Issue was with the access token. Using app-only permissions to send message is not supported.
Ref: https://github.com/microsoftgraph/microsoft-graph-docs/issues/8998

How to update user's hireDate attribute in Azure AD using Graph REST API?

I searched for similar questions but did not find answer I was looking for.
My goal is to update all users in AAD with hireDate.
At first I tried to do so using client credentials flow.
POST https://login.microsoftonline.com/espiradev.onmicrosoft.com/oauth2/token
Content-Type:application/x-www-form-urlencoded
grant_type:client_credentials
client_id:{{client_id}}
client_secret:{{client_secret}}
resource:https://graph.microsoft.com
After I got access code I called:
PATCH https://graph.microsoft.com/v1.0/users/[user1]
Authorization:bearer {{access_token}}
Content-Type:application/json
{
"hireDate": "2019-05-01T00:00:00Z"
}
Response:
"error": {
"code": "-1, Microsoft.Office.Server.Directory.DirectoryObjectUnauthorizedAccessException",
"message": "Attempted to perform an unauthorized operation.",
"innerError": {}
}
Second try was using password flow (client and user credentials). I used my global admin [user1] credentials and called same HTTP request. Response was HTTP 204 (everything OK).
POST https://login.microsoftonline.com/espiradev.onmicrosoft.com/oauth2/token
Content-Type:application/x-www-form-urlencoded
grant_type:password
client_id:{{client_id}}
client_secret:{{client_secret}}
resource:https://graph.microsoft.com
username:{{user1_upn}}
password:{{user1_password}}
Unfortunately, when I tried to update other [user2] it went like this:
PATCH https://graph.microsoft.com/v1.0/users/[user2]
Authorization:bearer {{access_token}}
Content-Type:application/json
{
"hireDate": "2019-05-01T00:00:00Z"
}
Response:
"error": {
"code": "-1, Microsoft.Office.Server.Directory.DirectoryObjectUnauthorizedAccessException",
"message": "Attempted to perform an unauthorized operation.",
"innerError": {}
}
If I am using [user2] credentials to get access token then I can update [user2] hireDate, but can not update [user1].
Application permissions:
Application permissions
UPDATED:
Decoded access token has these permissions:
"scp": "Directory.AccessAsUser.All Directory.ReadWrite.All User.ManageIdentities.All User.ReadWrite User.ReadWrite.All"
UPDATED[2]:
both [user1] and [user2] has Office 365 E1 licences assigned (including SharePoint Online (Plan 1))
Am I doing something wrong? If anyone has a solution to share, it would be much appreciated.
Apart from the office licenses, the global admin user should have Sites.ReadWrite.All scope permission in the token to update the "hireDate" property for other users.

How to get list of all subscribed channels of user using youtube api?

I am using Laravel-php, I have following code :
$client = new Google_Client();
$client->setClientId(env('GOOGLE_ID'));
$client->setClientSecret(env('GOOGLE_SECRET'));
//$client->setRedirectUri($redirect_uri);
$client->addScope("https://www.googleapis.com/auth/youtube.force-ssl");
$client->addScope("https://www.googleapis.com/auth/youtube");
$client->addScope("https://www.googleapis.com/auth/youtube.readonly");
$client->addScope("https://www.googleapis.com/auth/youtubepartner");
$youtube = new \Google_Service_YouTube($client);
$searchResponse = $youtube->channels->listChannels('snippet', array('mine' => true));
//$subscriptions = Curl::to('https://www.googleapis.com/youtube/v3/subscriptions')->withData(['part' => 'snippet', 'mine' => 'true'])->get();
echo "<pre>";
print_r($searchResponse);
Above code gives me following error :
Google_Service_Exception in REST.php line 118:
{
"error": {
"errors": [
{
"domain": "usageLimits",
"reason": "dailyLimitExceededUnreg",
"message": "Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup.",
"extendedHelp": "https://code.google.com/apis/console"
}],
"code": 403,
"message": "Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup."
}
}
I have tried to use CURL call also but that also gives me same error, any suggestions will save my day
What am I missing in code ?
Your error means that you haven't set up a Google APIs console project. The resource you are accessing requires OAuth authorization. You need to obtain authorization credentials in the Google Developers Console to be able to use OAuth 2.0 authorization.
Open the Credentials page.
The API supports API keys and OAuth 2.0 credentials. In your case, use OAuth 2.0 for your project:
OAuth 2.0: Your application must send an OAuth 2.0 token with any request that accesses private user data. Your application sends a client ID and, possibly, a client secret to obtain a token. You can generate OAuth 2.0 credentials for web applications, service accounts, or installed applications.
See the Creating OAuth 2.0 credentials section for more information.
You may also check this related thread: list user subscriptions to all youtube channels after getting access token
First thing is that it needs to be an authenticated call.
So you need to get the person to "Authenticate" through the Oauth2 and collect the token.
Then with the token send this call
https://www.googleapis.com/youtube/v3/subscriptions?part=id,snippet,contentDetails&maxResults=50&channelId='.$channelId.'&access_token='.$access_token
Then you can access the JSON response and collect them.

"Insufficient Permission" to retrieve user youtube subscriptipns after getting access token

I'm working on a scripts that checks if the user is already subscribed to my channel. The idea is to get all the channels the user had subscribed into then check if my channel id is one of them. First I get the access token correctly using POST and it works fine than send these as GET but the result is "failed to open stream: HTTP request failed! HTTP/1.0 403 Forbidden false". Doc page: https://developers.google.com/youtube/v3/docs/subscriptions/list#request_url
$data =file_get_contents('https://www.googleapis.com/youtube/v3/subscriptions?part=snippet
&maxResults=50&access_token='.$token.'&mine=true&key=My API Key');
var_export($data);
and pasting the full url
https://www.googleapis.com/youtube/v3/channels?part=snippet&mine=true&access_token={Access_Token}
I get this
{
"error": {
"errors": [
{
"domain": "global",
"reason": "insufficientPermissions",
"message": "Insufficient Permission"
}
],
"code": 403,
"message": "Insufficient Permission"
}
}
Add a heaer:
Authorization: Bearer ya29.DwG_A_V6cybZ2KGqRwPMBF02w0sYw9msqSKoCBI53So0zzIHFRKlwEv68C4aI_NdadQ4wKHUrV2pBA
key is your client id
Google restricts access with API keys. If you go over the free limits, they charge you. You need to get a Google API key and add it to the URL like this: &key=YOUR_API_KEY
Create the API key from Google's console (you'll need to sign up and create a project): https://console.cloud.google.com/apis/credentials
Your new URL for the request would be:
https://www.googleapis.com/youtube/v3/channels?part=snippet&mine=true&access_token={Access_Token}&key=YOUR_API_KEY
I was having this error, and I solved it when I found out I needed to add the Youtube scope to my OAuth sign-in request: "https://www.googleapis.com/auth/youtube"

Resources