API '500' Error when delegating admin access on MySite (OneDrive / Office365) - sharepoint

I would value some advice as we are facing an issue with the Office 365 API where it returns 500 errors, when we request delegated administrative access to the Office 365 MySites Site Collection.
The use case scenario is the following:
We have independent organizations, 'A' and 'B' , which both own their respectives Azure Active Directroy accounts and O365/Azure subscriptions.
Organiation B wishes to utilise an application provide Organisation A which requires delegated administrative access to it's Office365 MySites Site Collection.
Organisation B successfully adds the app to their Active Directory Account by using the OAuth2 authorization process, granting the permissions that the application requires over their company active directory.
The final part is delegating access of an admin account in Organisation B to the Mysites site collection in Organisation B's Office 365 account. If we utilise the manual process via the administrative panel all works well, although programatically via the API we receive a '500' error.
We are using the following call to programmatically add the user as site collection administrator: (please note: I have used [ dummmy id's] below )
Endpoint URL:
https://<..org_a..>.my.sharepoint.com/personal/[[user_OrganisationA_com]]/_api/web/siteUsers/getByEmail(#u)?#u='[[info#_OrganisationA.com']]
Method: POST
Body: {'__metadata':{ 'type': 'SP.User' }, 'IsSiteAdmin':'true'}
HTTP Headers:
• "Content-Type": "application/json; odata=verbose"
• "X-HTTP-Method": "MERGE"
• "Authorization": "Bearer <OAuth2 token>"
• "Accept": "application/json"
On the request above we are trying to add info#_organisationB.com as site collection administrator to UserC's personal site in One Drive for Business service (UserC is identified by the email UserC#_organisationB.com). The user info#_organisationB.com has Global Administrator privileges in Organisation B's Office365 domain and UserC#_organisationB.com) is a basic user with no admin rights.
The call returns a 500 HTTP Status code (Internal Server Error) and the following message:
object(stdClass)[18]
public 'odata.error' =>
object(stdClass)[19]
public 'code' => string '-2146232832, Microsoft.SharePoint.SPException' (length=45)
public 'message' =>
object(stdClass)[20]
public 'lang' => string 'en-US' (length=5)
public 'value' => string 'You need to be a site collection administrator to set this property.' (length=68)
To our knowledge an API call should never return a 500 HTTP Status Code (Internal Server Error), if we are not allowed to do what we intend it should provide an Insufficiente permissions message or similar, however, the fact that we can manually apply this through the SharePoint Online management portal makes us believe we are hitting a bug that is stopping us from achieving what we intend.
Any advise would be appreciated!

Are you using SSL from the website you execute the request?

Related

Microsoft Graph to send mail with Client Credential Flow (application permission) and personal account

I am learning Microsoft Graph and for this I use Graph Explorer and Postman.
With Graph Explorer : I am Signed In with my personal user account (hotmail). As soon as I am connected, I can see the token. Strangely when I copy/paste this token in jwt.io it cannot be decoded. Yet I can perform query like https://graph.microsoft.com/v1.0/me which returns me some infos of myself as a user (with http 200). Or this query https://graph.microsoft.com/v1.0/me/sendMail which allow me to send a test and receive a test mail (with http 202). All of these requests was "delegated permission". So I don't have any problem using Graph Explorer with my personnal account (hotmail).
With Postman : this time I will perform some tests with "application permission". I followed the steps below:
On the Azure Portal
Step 1: App registrations / New registration / I give a name / Choose the 3rd account type (Accounts in any organizational directory and personal Microsoft accounts) / Click on Register button
Step 2: Api permissions / Add permission / Microsoft Graph / Application permissions / Mail.Send (send mail as any user)
Step 3: Grand admin consent for... button to activate the permission
Step 4: Certificate & Secrets / New client secret / Enter a description / Click Add button
Step 5: Obtain a token in Postman
POST
https://login.microsoftonline.com/{my-tenant-id-here}/oauth2/v2.0/token
HEADERS
Content-Type: application/x-www-form-urlencoded
BODY
client_id: {my-client-id-here}
client_secret: {my-client-secret-here}
grant_type: client_credentials
scope: https://graph.microsoft.com/.default
OK I got a token
When copy/paste this token in jwt.io I see this:
Step 6: Query for listing all users
GET
https://graph.microsoft.com/v1.0/users
AUTHORIZATION
Bearer token: {bearer-token-received-previously}
HEADERS
Content-Type: application/json
OK I got infos for all users (as json)
Step 7: Query for sending a mail
POST
https://graph.microsoft.com/v1.0/users/{user-principal-name}/sendMail
AUTHORIZATION
Bearer token: {bearer-token-received-previously}
HEADERS
Content-Type: application/json
BODY (JSON)
{
"message": {
"subject": "This is my subject",
"body": {
"contentType": "Text",
"content": "This is my content"
},
"toRecipients": [
{
"emailAddress": {
"address": "thierry.langie#skynet.be"
}
}
],
"ccRecipients": [
]
},
"saveToSentItems": "false"
}
NOT OK Error: MailboxNotEnabledForRESTAPI - REST API is not yet supported for this mailbox
I would like to know why I got this error ? I can send email with Graph Explorer (when using delegated permission) and not with Postman (when using application permission).
As you can see below, I grant admin consent in Enterprise applications on the Azure Portal.
I read somewhere that the error means the user doesn't have the mailbox in EXO cloud. EXO is O365 Exchange Online Cloud. So if you don't have mailbox in the cloud O365 Exchange REST APIs will not work for these users. If that is the case, what would you do ?
I have a Web application which should send mails from a shared mailbox. No matter which user is connected, this is always the same mailbox which is used to send mails. That's why I go with "application permission" and "Client credential flow".
As explained above, I use my personal account (hotmail) for testing purpose but in production I'll use a work account (not accessible from my dev environment).
As a side note, I know there are libraries to facilitate the process and avoid using REST API calls (urls) but I don't think that can explain the problem I am facing.
"MailboxNotEnabledForRESTAPI - REST API is not yet supported for this mailbox" This error message means that the email account you are using to send email doesn't have an Exchange Online license.
For a personal account, you should use Delegated permission, which you have tried in Microsoft Graph Explorer. See Permissions here.
.
If we add the personal account to your tenant as a guest user, although we can Assign a license to a guest user (I assume we can assign EXO license to the guest user), the mailbox hosted in EXO is different from the mailbox of the personal account. They are totally 2 separated mailboxes. And in fact I failed to assign EXO license to the guest.
So in this case Client Credential Flow applies to the AAD users, not the personal account.
UPDATE:
For personal account which uses Delegated permission (you have tried in Microsoft Graph Explorer), the authority endpoint is https://login.microsoftonline.com/commonm/oauth2/v2.0/authorize or https://login.microsoftonline.com/consumers/oauth2/v2.0/authorize.
But when you use client credential flow with Application permission, you have to specify the tenant id in the request https://login.microsoftonline.com/{tenant id}/oauth2/v2.0/authorize.
Although your personal account is added into the tenant as a guest user, it doesn't have EXO license (based on test we are unable to assign EXO license to it), so it won't be hosted in O365.
That is why we can't use client credential flow with personal account.

Inviting a guest User to a SharePoint Site using PowerAutomate

We are developing a PowerAutomate Flow to automate the process of inviting external users to a SharePoint Site.
Below are the steps being followed so far
Created an MS Form for an external user to register
Passing the response**(Email)** from the form to the flow
Adding the user to a SharePoint Group using email parameter and sending an email invite to the External User(Requirement)
I have been able to get to point no 2 , However I have been experiencing challenges achieving point no 3
Came across different articles online for adding a guest users , However most of them talk about adding the guest to Azure AD as shown below
https://medium.com/southworks/adding-a-guest-to-an-office-365-sharepoint-site-with-javascript-fa7604ad8678
https://laurakokkarinen.com/how-to-build-a-guest-user-self-service-registration-for-office-365-with-azure/
https://www.timlinenterprises.com/how-to-invite-external-users-using-microsoft-flow-and-microsoft-graph-api/
Also checked a few articles for running PowerShell commands from Flow , However this approach doesn't look straightforward either
The below article works only for internal users
https://www.c-sharpcorner.com/article/add-the-users-to-the-sharepoint-groups-using-microsoft-flow/
The end goal here is to invite external user to a SharePoint Site once the user registers himself through a registration form (MS Form)
Would appreciate if anyone could help me out in achieving this.
Thanks in advance
Before inviting the user to SharePoint you must add him to Azure AD. So you will need to configure an HTTP action to invite the user first.
If you are using SharePoint Modern Sites (those who have Microsoft 365 groups associated), you need to create a HTTP action to add the guest to the group:
HTTP Action Configuration Here
NOTE: HTTP will not accept "#" sign directly, so you need to put it into a "Compose" or "Variable" and add it as per my screenshot.
In the URI you have the Group ID from Azure AD.
In the Body it's the guest user ID
You will need to register and Azure AD App to use for the HTTP action and give it the following permissions:
Graph -> Application -> GroupMember.ReadWrite.All, Group.ReadWrite.All and Directory.ReadWrite.All
https://learn.microsoft.com/en-us/graph/api/group-post-members?view=graph-rest-1.0&tabs=http#permissions
Use the App ID and Secret to connect the HTTP action.
This is my solution to add Guest Users to Private Channels in MS Teams with PowerAutomate.
Step0 - Register the domain of the Guest Users in your AD account as a valida Guest Domain
Step1 - User a registration form (MS Forms)
Step2 - Create a Trigger Process in MS PowerAutomate to receive the Form Data. I like to create small/short flows to only capture and validate form data, and then call a separate Flow / RestService. This makes your solution a little bit more decoupled and reusable. (Imagine replacing the Form with a web app form or mobile app form in the future).
Create a second HTTP request trigger flow receiving the Form data (optional way to setup multi-flow solution)
Step3 - Create a Private Channel in teams via GrapAPI
GraphAPI - POST https://graph.microsoft.com/v1.0/teams/<teams_id>/channels
POST BODY:
{
"membershipType": "private",
"displayName": "<e.g. channel name from form data>",
"description": "<e.g. description from form data>",
"members": [
{
"#odata.type": "#microsoft.graph.aadUserConversationMember",
"user#odata.bind": "https://graph.microsoft.com/v1.0/users('owner.user#mydomain.com')",
"roles": [
"owner"
]
}
],
"#odata.type": "#Microsoft.Graph.channel"
}
Step4 - Call GraphAPI to retrieve the Guest User Details
GraphAPI: GET https://graph.microsoft.com/v1.0/users?$filter=mail eq 'guest.user#email.com'
I have added this in a loop - since I had many members who had to be added - and I also included a condition check to check if the domain is indeed valid
Now you can assign the output (or portions of the output) to some variables
Step5 - Retrieve the ID value from the step above (Step4). This is the value that must be used to add the new guest member.
Retrieve the ID from the Step4 output
Also set a variable to the account type - which should (MUST BE) be "guest"
Now - Add guest users to the private teams channel
Step6 - Call GraphAPI to add guest members
GraphAPI: POST https://graph.microsoft.com/v1.0/teams/<team_id>/channels/<channel_id>/members
Post Body:
The role must be "guest" for guest account
But valid options for other types of access can be
owner
member
guest
Microsoft documentation (HERE) states roles must be owner or empty
This did not work so well for me.
Use guest
{
"#odata.type": "#microsoft.graph.aadUserConversationMember",
"roles": [
"#{variables('membership_type')}"
],
"user#odata.bind": "https://graph.microsoft.com/v1.0/users('#{variables('principal_user')}')"
}
Bonus Step
Now you can catch all responses from the previous steps and respond back with an HTTP Request/Response connector.
A 200 response on successful executions
A non-200 response on failed executions (or how ever you desire)
To configure exception handling or failure handling responses do this below

'IntegratorKey xxxx for user Id xxx does not have access to API version v2' Docusign JWT API error

I get IntegratorKey xxxx for user Id xxx does not have access to API version v2 error when calling the DocuSign rooms API. My requests work against the Esign API. I've gone through the consent process. Here's my code:
from docusign_esign import ApiClient
import requests
api_client = ApiClient()
oauth = api_client.request_jwt_user_token(
client_id=integration_key,
user_id=user_id,
oauth_host_name='account.docusign.com',
private_key_bytes=private_key,
expires_in=3600,
scopes=(
'signature',
'impersonation',
'dtr.company.read',
'dtr.company.write',
'dtr.rooms.read',
'dtr.rooms.write',
'dtr.documents.read',
'dtr.documents.write'
)
)
headers = {
'Authorization': f'Bearer {oauth.to_dict()["access_token"]}',
'Accept': 'application/json',
'Content-Type': 'application/json'
}
rep = requests.get(
f'https://rooms.docusign.com/restapi/v2/accounts/{account_id}/rooms',
headers=headers
)
rep.text returns {"message":"IntegratorKey xxxx for user Id xxxx does not have access to API version v2. Attempted to access http://rooms.docusign.com/restapi/v2/accounts/xxx/rooms","errorCode":null}
You cannot use the Rooms API in production without first going through the Go-Live process.
The Go-Live process for the Rooms API is a bit different at this time.
Email go-live#docusign.com with the words "Rooms go-live" in the subject line, providing the following information:
The name and email of a Production Admin user, who can be any member
of the account with full administrative permissions
Your production API Account ID
Your demo API Account ID
The integration key of the application in the demo environment to be
pushed into production
The date range within which the 20+ required Rooms API calls were
performed
More information can be found here - https://developers.docusign.com/rooms-api/guides/golive
Items to check:
Did this work in the developer sandbox (demo.docusign.net) with (account-d.docusign.com as the IdP)?
Did you complete go-live process?
In production, you need to create a new private key for the production version of the integration key. The demo (developer sandbox) and production integration keys share the same guid value but are actually two separate keys with two sets of settings.
Is the user Id from a production account?
Did the user Id grant consent to the integration key within the production system? Either via Administrative Consent (blanket consent) or via Individual Consent.
First try with just the signature (the impersonation scope is not needed). The problem could be that your integration key needs special permissions to access the dtr.* scopes

Dynamics CRM 401 with token provided

I'm working on a dynamics crm integration for a Single-Tenant Server-to-server authentication. This is required to obtain tokens invisibly as the data will be used to create customer facing ui.
Therefore I’m getting a token back from Azure using the client_credentials grant type. However when I attempt to use this token to access any dynamics endpoint (such as those documented here: https://msdn.microsoft.com/en-us/library/mt607871.aspx)
All I get back is a 401 - access denied.
I’ve done the following:
Create an Azure application
Created and stored a key
Enabled permissions for Dynamics CRM online
I’ve seen some suggestion that I need a service user in the CRM itself to provide access, however when I try and create one the options described do not appear. (such as here: https://msdn.microsoft.com/en-us/library/mt790170.aspx#bkmk_ManuallyCreateUser )
Can you suggest any steps I might be missing here?
Heres a sample call using the token
{ method: 'GET',
url: 'https://<snip>/api/data/v8.2/accounts?$select=name&$top=3',
headers:
{ Authorization: 'Bearer <snip>',
Accept: 'application/json',
'OData-MaxVersion': '4.0',
'OData-Version': '4.0' }
}
EDIT:
Please note that I am using node.js here and C# / .net based answers are probably not going to be massively helpful
Here is a post on how to configure server to server auth. Assuming you ran through all the steps except creating the application user, you can do so by:
In CRM Navigate to Settings->Security->Users
Change the view from "Enabled Users" to "Application Users"
From the new user form change the form from "User" to "Application User".
You should now be able to create your application user.

Office Graph API - get items from list

Is there a way within the Office Graph API to access items in a specific list - and not just items that I can see, but items I may not have access to?
Microsoft Graph access to SharePoint objects is currently in the beta version of Graph. See https://developer.microsoft.com/en-us/graph/docs/api-reference/beta/resources/sharepoint.
To access specific items, the endpoint pattern would be:
GET https: //graph.microsoft.com/beta/sites/{site-id}/lists/{list-id}/items/{item-id}
For example: https:// graph.microsoft.com/beta/sites/mytenant.sharepoint.com:/sites/mysite:/Lists/Announcements/Items/1
As for being able to access items you do not have access to: No. That would be a horrible security problem if you could use any API to access such items.
There are two kinds of permission for app registered on the Microsoft Azure platform.
One is delegated permission. In this scenario, the user delegates access to a client application. We can call the REST API to get the data owned by who sign in.
The another is Application-level. In this scenario which permits a web service (a confidential client) to use its own credentials to authenticate when calling another web service, instead of impersonating a user. For example, a service or daemon app can retrieve all the users in a tenant if it has the Read all users' full profiles permission selected in the Azure Management Portal. And we can get the specific user's drive via the API like below:
GET /users/<id | userPrincipalName>/drive
More detail about REST API for handling the files on OneDrive for business, please refer to link below:
https://graph.microsoft.io/en-us/docs/api-reference/v1.0/resources/drive
And here is the link for the authentication protocols for the Azure AD support:
https://msdn.microsoft.com/en-us/library/azure/dn151124.aspx
No, you can't retrieve SharePoint list items using Graph API, but you can use SharePoint REST API for that. It's similar to Graph API and supports OAuth.
Check the documentation for SharePoint API here: https://msdn.microsoft.com/en-us/library/office/dn531433.aspx
To get items from a list within SharePoint, you can use SharePoint Rest API. A sample code to get items using rest api is as below:
// For SharePoint 2010
var strRestUrl = _spPageContextInfo.webServerRelativeUrl + "/_vti_bin/listdata.svc/{{listname}}
// For Office 365 or SharePoint 203
var strRestUrl = _spPageContextInfo.webAbsoluteUrl + "/_api/Web/Lists/GetByTitle({{listname}})/Items
$.ajax({
url: strRestUrl,
method: 'GET',
headers: { "Accept": "application/json; odata=verbose" },
success: function(response){
// success callback function
},
complete: function(){
// complete callback function
},
error: function (data) {
// error callback function
console.log(data.responseJSON.error);
}
});
If you are using SharePoint 2010 then Rest URL is different and if you are using SharePoint 2013/Office 365 rest URL is different. Hope this code will help you.
More details about REST API are as available at below link:
https://msdn.microsoft.com/en-us/library/office/dn531433.aspx

Resources