Access sharepoint\office 365 using CSOM and grant_type=client_credentials - sharepoint

I have followed the instructions in this example:
https://learn.microsoft.com/en-us/sharepoint/dev/sp-add-ins/using-csom-for-dotnet-standard
And can connect fine :-) using grant_type=password, username and password
However i want to connect using client id and client secret...
I have set these up in AzureAD
i have added the permissions:
i have exposed the api
this is the body of my request
at this point in the code i actually receive the token
but here it fails with a 401
i wonder if someone has an example of this working?
I have also tried this https://learn.microsoft.com/en-us/sharepoint/dev/solution-guidance/security-apponly-azureacs
and i can get it working, whoever according to the documentation this has been retired on November 7, 2018.
I not sure what auth method it uses or how to identify the auth method.

If this registration is only used for SharePoint, you do not need to expose an API.
You don't need scope. You will need to pass in the 'client_id' and 'resource' like below and it will look something similar to this for getting a token to make a call to SharePoint:
client_id: [appRegistrationClientId]#[tenantid]
Resource: 00000003-0000-0ff1-ce00-000000000000/[tenant].sharepoint.com#[tenant-id]
This will help too: https://anexinet.com/blog/getting-an-access-token-for-sharepoint-online/

Related

The provided value for the input value scope is not valid for OnlineMeeting.ReadWrite

I am trying to create meeting on behalf of a user for that I am trying to get the code. I have registered the app on Azure. Also generated Application(Client) ID I have also added the required permission in the API. But when I am visiting this page the page asks for the email id but once the users fill the email id it says The provided value for the input value scope is not valid for OnlineMeeting.ReadWrite in the redirect URL.
Please guide me to know what I am missing here.
Edit 1: As suggested by #Rukmini I tried this and here is the relevant details.
To obtain the the code I am building url like this image
This does not work when I pass the OnlineMeetings.ReadWrite scope. But when I pass https://graph.microsoft.com/.default as scope it works and I am able to authenticate and generate a code. Then I can use that code to get the access token like following image. But using this access token I can not create the meeting as it does not have the OnlineMeetings.ReadWrite scope as stated in this doc **https://learn.microsoft.com/en-us/graph/api/application-post-onlinemeetings?view=graph-rest-1.0&tabs=http**[![enter image description here]3]3
Let me know what I can do to generate code and access token for the OnlineMeetings.ReadWrite scope so that I can create the meeting on users behalf. Thanks
EDIT 2: I generated the authorization URL as suggested by #Rukmini using the following query parameters.
When I visited the link, I was presented with a login screen but as my previous error I see the same screen. Am I missing something here? Do I need to verify my app? Or Do I have to only use some specific IDs like we do in GCP and AWS?
Please let me know what I am missing here.
Thanks
I tried to reproduce the same in my environment and got the results successfully like below:
I created an Azure AD Multi-Tenant Application:
I granted Admin Consent to the API permissions like below:
I generated the code by using below endpoint and authorizing it via browser:
https://login.microsoftonline.com/common/oauth2/v2.0/authorize?
&client_id=ClientID
&response_type=code
&redirect_uri=https://jwt.ms
&response_mode=query
&scope=OnlineMeetings.ReadWrite
&state=12345
Now, I generated access token by using the below parameters:
https://login.microsoftonline.com/common/oauth2/v2.0/token
client_id:ClientID
client_secret:ClientSecret
scope:OnlineMeetings.ReadWrite
grant_type:authorization_code
redirect_uri:https://jwt.ms
code:code
Decode the access token using jwt.ms and check whether the scope is OnlineMeetings.ReadWrite:
I am able to create the Online meetings successfully by using the below query:
https://graph.microsoft.com/v1.0/me/onlineMeetings
Content-Type: application/json
{
"startDateTime":"2023-01-12T14:30:34.2444915-07:00",
"endDateTime":"2023-02-12T15:00:34.2464912-07:00",
"subject":"User Token Meeting"
}

Is it possible to access microsoft graph using custom audience?

I have an API that uses Azure AD to provide access to resources. It has one scope api://{client_id}/Api.Read and following API permissions:
User.Read.All,
User.Read.
When I receive an access token from the AD it has only one aud - {client_id} and when I try to access Microsoft graph (e.g. https://graph.microsoft.com/v1.0/me) I get "Access token validation failure. Invalid audience." response as expected.
My question is - Is it possible to access both graph API and my API using one token and how do it?
I am exchanging current token to a "proper" token using on-behalf-of call: https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-on-behalf-of-flow
Basically, you just make the following call (copied from the link above):
POST /oauth2/v2.0/token HTTP/1.1
Host: login.microsoftonline.com/<YOUR_TENANT>
Content-Type: application/x-www-form-urlencoded
grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer
&requested_token_use=on_behalf_of
&client_id=<YOUR_CLIENT_ID>
&client_secret=<YOUR_CLIENT_SECRET>
&assertion=<YOUR_CURRENT_TOKEN>
&scope=<YOUR_NEW_SCOPES>
The response contains the new token to access the resources that are requested in the scopes. My scenario is not exactly yours, but I think this should work for your case as well. You need to make this call server-side.
This assumes that the user has already consented that your app is okay to use <YOUR_NEW_SCOPES>, or otherwise this call will result in "interaction_required" or "invalid_grant" error (something like this, don't remember the exact error name) that basically means you need to raise UI prompt for the user to agree to the new scopes (how to do that is another question)

SharePoint Online multi-tenant REST calls return 404 on resources that definitely exist

I am attempting to access the SharePoint Online REST API (this is hand coded REST calls, no library being used).
Access tokens are acquired using authorization grant flow as follows:
I send the browser https://login.microsoftonline.com/common/oauth2/authorize?...
This redirects to a handler endpoint that we extract the access code from
I obtain the tenant ID by:
GET https://{tenantname}.sharepoint.com/_vti_bin/client.svc
Then extracting the tenant ID from the WWW-Authenticate header
I then POST https://login.microsoftonline.com/{tenantid}/oauth2/authorize to obtain the access token
When I use that access token, I am able to do queries using:
GET https://{tenantname}.sharepoint.com/_api/search/query?querytext=....
This works and returns documents.
But when I attempt to retrieve information about one of those documents:
GET https://{tenantname}.sharepoint.com/_api/web/getfilebyserverrelativeurl('/TestFiles/test.pdf')
I get a 404 response with the following body:
{"odata.error":{"code":"-2130575338, Microsoft.SharePoint.SPException","message":{"lang":"en-US","value":"The file /TestFiles/test.pdf does not exist."}}}
If I navigate to the URL in a browser (https://{tenantname}.sharepoint.com/TestFiles/test.pdf), it accesses the file without issue.
This makes me think that I'm running into some sort of permission issue.
I have tried setting the following scopes in the authorize redirect:
Attempt 1: scope = Web.Write AllSites.Write Site.Write
Attempt 2: scope = https://{tenantname}.sharepoint.com/.default
Attempt 3: scope = https://{tenantname}.sharepoint.com/Web.Write https://{tenantname}.sharepoint.com/AllSites.Write https://{tenantname}.sharepoint.com/Site.Write
No matter what I set as the scope parameter of the authorize URL, the JWT details of the access token show (I can post the entire decoded JWT if anyone needs it):
"scp": "User.Read"
Nothing I do has any impact on the scp in the token - I have no idea if that's the issue or not. If it is, I would appreciate hearing how to properly request scope.
The application registration in Azure Active Directory has desired permissions (plus more):
What am I doing wrong?
UPDATE: Switching to OAuth endpoint v2.0:
https://login.microsoftonline.com/common/oauth2/v2.0/authorize
With query parameters:
response_type = code
client_id = my app id
redirect_uri = my redirect uri
scope = <varying - I'll explain what happens under different scenarios below>
Here's what I've tried for scopes:
AllSites.Write Site.Write - the redirect has invalid_client with error_description = AADSTS650053: The application '' asked for scope 'AllSites.Write' that doesn't exist on the resource '00000003-0000-0000-c000-000000000000'. Contact the app vendor.
https://{tenantname}.sharepoint.com/AllSites.Write https://.sharepoint.com/Site.Write - the redirect has invalid_client with error description = AADSTS650053: The application '' asked for scope 'Site.Write' that doesn't exist on the resource '00000003-0000-0ff1-ce00-000000000000'. Contact the app vendor.
https://{tenantname}.sharepoint.com/.default - this goes through
But the resulting JWT has only scp=User.Read
The following works: GET https://{tenantname}.sharepoint.com/_api/search/query?querytext=
But the following returns a 404: GET https://{tenantname}.sharepoint.com/_api/web/getfilebyserverrelativeurl('/TestFiles/test.pdf')
I don't understand how Scope=.Default isn't including the allowed permissions from the application registration. And I definitely don't understand why the AllSites.Write scope is failing when it's explicitly specified.
If it helps, I have also tried all of the above using a tenant specific authorize endpoint instead of 'common':
https://login.microsoftonline.com/{tenantid}/oauth2/v2.0/authorize
UPDATE2: More scope changes:
I finally found a magical combination that works:
Use a tenant based URI for the /authorize and /token endpoint and use {tenanturl}\AllSites.Write for the scope (do NOT specify the Site.Write scope):
https://login.microsoftonline.com/{tenantid}/oauth2/v2.0/authorize?response_type=code&client_id={clientid}&redirect_uri={redirecturi}&scope=https%3A%2F%2F{tenantname}.sharepoint.com%2FAllSites.Write
The resulting JWT has the following:
"scp": "AllSites.Write User.Read"
I am completely perplexed about why Site.Write wasn't allowed. I suppose that AllSites.Write is a superset of Site.Write, so maybe not needed?
All of my testing so far has been on my own tenant, next step is to test on a different tenant and make sure it actually works there as well.
It seems you use v1.0 endpoint https://login.microsoftonline.com/common/oauth2/authorize but not v2.0 endpoint https://login.microsoftonline.com/common/oauth2/v2.0/authorize. If we use v1.0 endpoint, we should use resource instead of scope. So that is why the scp claim in your access token always the same no matter you modify the scope.
You should use resource with https://{tenant-name}.sharepoint.com and the parameter scope is useless when you use v1.0 endpoint.
If you still want to use scope parameter, you can also change the endpoint to v2.0. Just add v2.0 into your endpoint, like: https://login.microsoftonline.com/common/oauth2/v2.0/authorize
I finally found a magical combination that works:
use the https://login.microsoftonline.com/{tenantid}/oauth2/v2.0/authorize and https://login.microsoftonline.com/{tenantid}/oauth2/v2.0/token endpoints
specify {tenanturl}\AllSites.Write for the scope (do NOT specify the Site.Write scope - that was the primary problem):
https://login.microsoftonline.com/{tenantid}/oauth2/v2.0/authorize?response_type=code&client_id={clientid}&redirect_uri={redirecturi}&scope=https%3A%2F%2F{tenantname}.sharepoint.com%2FAllSites.Write
The resulting JWT has the following: "scp": "AllSites.Write User.Read"
This works across tenants and gets us the access we need.
For thoroughness, we also specify offline_access scope so we get a refresh_token in addition to the access_token.

Sharepoint REST api - Realm is not a configured realm of the current service namespace error 50169

I got this error trying to get an auth token from Sharepoint REST api. My SP is cloud based and I am using Postman to test the requests, as a previous attempt similarly ran into a dead end when much troubleshooting back and forth with Msoft lead no where .. Anyway, I have the following error and I was wondering if anyone could help me figure out what it is or how I can troubleshoot this issue.
error_description: "AADSTS50169: The realm 'realm' is not a configured realm of the current service namespace"
error_codes : 50169
I followed this tutorial
Thanks!
Edit: I went through and started again, this tut seems to be working I guess I may have missed a step (my guess is I didn't correctly configure the app permissions with xml when creating the app)
To do authorization of SharePoint online and use REST API via Postman, here is a solution for your reference:
First: get security Token
Access [https://login.microsoftonline.com/extSTS.srf] via Http Post method. The content of the http request is as follows.
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"
xmlns:a="http://www.w3.org/2005/08/addressing"
xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-
utility-1.0.xsd">
<s:Header>
<a:Action
s:mustUnderstand="1">http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue</a:Action>
<a:ReplyTo>
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
</a:ReplyTo>
<a:To s:mustUnderstand="1">https://login.microsoftonline.com/extSTS.srf</a:To>
<o:Security s:mustUnderstand="1"
xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<o:UsernameToken>
<o:Username>[username]</o:Username>
<o:Password>[password]</o:Password>
</o:UsernameToken>
</o:Security>
</s:Header>
<s:Body>
<t:RequestSecurityToken xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust">
<wsp:AppliesTo xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
<a:EndpointReference>
<a:Address>[endpoint]</a:Address>
</a:EndpointReference>
</wsp:AppliesTo>
<t:KeyType>http://schemas.xmlsoap.org/ws/2005/05/identity/NoProofKey</t:KeyType>
<t:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</t:RequestType>
<t:TokenType>urn:oasis:names:tc:SAML:1.0:assertion</t:TokenType>
</t:RequestSecurityToken>
</s:Body>
</s:Envelope>
The demonstration screenshot in Postman:
And the response content will include a security token as below, we can use this security token to get Access Token of SharePoint.
Second: get Access Token
Here i show you how to get access token of SharePoint online using the security token and SharePoint Rest API.
Access [https://yourdomain.sharepoint.com/_forms/default.aspx?wa=wsignin1.0] via http Post method. The content of the request is the security token that we have got above as below.
And the response as below:
We can see that there are two cookie, rtFa and FedAuth in response header, and these two cookie need to be added to the request in subsequent request.
Third: get Request Digest
Access [https://yourdomain.sharepoint.com/_api/contextinfo] via http Post method with that two cookies which we have got above.
And the response as below:
This is the final Token we want!
Then we can use REST API of SharePoint, we only need to add this token and the previous two cookie, as shown in the following figure.

Getting token in Office 365 Oauth2 authentication

I am implementing Oauth 2 authentication for Office 365 account in a java based server side application. After reading the documentation, I have done the following things:
I have office 365 subscription.
I have created an app in Azure
Actve directory, that is necessary to authenticate web app using
office 365 account.
I have client ID and secret. I have also
given all permission to the Azure app.
I am requesting authorization code using the Url:
https://login.microsoftonline.com/common/oauth2/authorize?client_id={client_id}&response_type=code&redirect_uri={redirect url}&response_mode=query
As a response of this, I am getting authorization code as expected:
http://localhost:8080?code={authorication code}&session_state=259479e4-84aa-42ea-91e9-9e919cc99587
Now I need to get token along with the user name (user ID from which the user in logged in), as I need the user name for further processing. For this, I am using the method described here:
https://azure.microsoft.com/en-us/documentation/articles/active-directory-protocols-oauth-code/
That is using a POST request like this:
POST /{tenant}/oauth2/token HTTP/1.1
Host: https://login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&client_id=2d4d11a2-f814-46a7-890a-274a72a7309e
&code=AwABAAAAvPM1KaPlrEqdFSBzjqfTGBCmLdgfSTLEMPGYuNHSUYBrqqf_ZT_p5uEAEJJ_nZ3UmphWygRNy2C3jJ239gV_DBnZ2syeg95Ki-374WHUP-i3yIhv5i-7KU2CEoPXwURQp6IVYMw-DjAOzn7C3JCu5wpngXmbZKtJdWmiBzHpcO2aICJPu1KvJrDLDP20chJBXzVYJtkfjviLNNW7l7Y3ydcHDsBRKZc3GuMQanmcghXPyoDg41g8XbwPudVh7uCmUponBQpIhbuffFP_tbV8SNzsPoFz9CLpBCZagJVXeqWoYMPe2dSsPiLO9Alf_YIe5zpi-zY4C3aLw5g9at35eZTfNd0gBRpR5ojkMIcZZ6IgAA
&redirect_uri=https%3A%2F%2Flocalhost%2Fmyapp%2F
&resource=https%3A%2F%2Fservice.contoso.com%2F
&client_secret=p#ssw0rd
Now the problem is that, when ever I send this post request, I always get error with error code some times 400 or 402 etc. I also user POST man in chrome to check the response of the call. It always return error like that:
{
"error": "invalid_grant",
"error_description": "AADSTS65001: The user or administrator has not consented to use the application with ID. Send an interactive authorization request for this user and resource.\r\nTrace ID: b834315e-ccb3-4533-b7c9-4af7b34054b9\r\nCorrelation ID: 784f18da-5479-4b69-b939-0067abfcc460\r\nTimestamp: 2016-08-02 07:28:22Z",
"error_codes": [
65001
],
"timestamp": "2016-08-02 07:28:22Z",
"trace_id": "b834315e-ccb3-4533-b7c9-4af7b34054b9",
"correlation_id": "784f18da-5479-4b69-b939-0067abfcc460"
}
(Note: I have registered all the apps using administrator login)
I have tried a lot to find out whats is going wrong here. I have added multiple apps in Azure Active directory but I am always getting similar response.
I request professionals to help me. . . ! Actually I want to allow user to click on a button in office 365 web add-in and use oauth2 authentication to login to our system. It will be great in somebody suggest me some good tutorial to successfully implement this.
If you were requesting the access token for the Office 365, the resource parameter in the send request should be https%3A%2F%2Foutlook.office.com.
And also you can use the Microsoft Graph as Philip suggested. You can refer here about how to choose the endpoint.
Receiving the error codes "interaction_required" or "invalid_grant" error codes means there is an issue with the "Refresh token" and it advised to:
Discard current refresh token
Request new authorization code

Resources