Download shared file programmatically using OneDrive for Business API - azure

I have a scenario where userA shares a file with userB on OneDrive for Business. They both belong to the same Office365 tenant.
Is there a way to programmatically retrieve shared file content using userB identity (OAuth access token)? I've tried using 2.0 API syntaxt, which works for userA, but I'm getting 401 error when trying to execute this request with userB access token, even though file was shared with userB.
https://{tenantid}-my.sharepoint.com/_api/v2.0/drives/{driveId}/items/{itemId}/
Or maybe there is a way I could use Azure AD Application delegated permission to access this file on behalf of its owner having driveId and itemId?

As far as I know, this feature is not supported yet.
There is a request for this functionality on UserVoice which you can vote on.

As for March 2016, the only way I was able to retrieve shared file content programmatically from OneDrive for Business was by:
Creating SharePoint Provider hosted addin with FullControl permission for the whole Tenant
Registering the app under https://{tenantid}-my.sharepoint.com/_layouts/15/AppRegNew.aspx
Creating app catalog on SharePoint Online and publishing the app to the catalog
Installing app on at least one SharePoint site collection within the Tenant
Using ClientSecret and ClientId executing following code from http://blogs.msdn.com/b/vesku/archive/2015/01/05/customizing-onedrive-for-business-sites-with-app-model.aspx
Uri url = new Uri("https://{tenantid}-my.sharepoint.com/personal/{user}");
string realm = TokenHelper.GetRealmFromTargetUrl(url);
var token = TokenHelper.GetAppOnlyAccessToken(TokenHelper.SharePointPrincipal,url.Authority, realm).AccessToken;
token variable contains AccessToken that can be used as Bearer token in OneDrive for Business API requests (e.g. getting files from other users 'OneDrives').
https://{tenantid}-my.sharepoint.com/_api/v2.0/drives/{driveId}/items/{itemId}/

Related

Basic Microsoft Graph App to retrieve a shared Excel File

I am trying to understand Microsoft Graph APIs but I found them kind of confusing. There's an excel file that is shared with me on OneDrive. I want to download it using Microsoft Graphs. I was able to generate the app and set up its configurations and permissions so that I can send a request and get an authorization token that I can use to send requests.
However, I have a couple problems, even in Graph Explorer, which I use as my account, not as the app.
To find out the file Id that is shared with me, I used the "files shared with me" API that is under OneDrive. (https://graph.microsoft.com/v1.0/me/insights/shared)
I copied the id that I get from there and used it in "worksheets in a workbook" API under Excel category. https://graph.microsoft.com/v1.0/me/drive/items/{drive-item-id}/workbook/worksheets)
However I got Item Not found error. The problem is, even though I can see it on oneDrive as a shared object I can't seem to open it using the second API.
How can I download the Excel file that is shared with me through OneDrive? Which API should I use? The app that will send the requests is a standalone app that will send the requests without human authorization. I don't know the correct terminology here but Microsoft doesn't allow it to have a /me request, it gets "/me request is only valid with delegated authentication flow.", therefore I probably need someway for app to see that oneDrive link. But I was unable to find a working way.
The error message "/me request is only valid with delegated authentication flow." means what it says. There are two main ways to authenicate a application with the graph API. Application authenication and On behalf of user authencitation. So the error message is telling you that you are using the application authenication and the API path /me is only accessable with On behalf of user authencitation (e.g. delegated authentication). This makes sense because when using the application authenication who is me?
The API endpoints says what authentication types they support. If you take the worksheets API it says under permissions section:
Permission type - Permissions (from least to most privileged)
Delegated (work or school account) - Files.ReadWrite
Delegated (personal Microsoft account) - Not supported.
Application - Not supported.
Which is telling us that Application and Delegated for personal Microsoft accounts are not supported and that Delegated for work/school accounts requires the Files.ReadWrite permission.
To download the drive item you can use the download item API.
This supports both Application and Delgated permissions. For Application permisions you will not be able to use the /me path though. You will most likely have to use something like:
/users/{userId}/drive/items/{item-id}/content
I am assuming your file is stored in a work account one drive storage and not in one of the other storage places (AD group, etc).

MSAL PublicClientApplicationBuilder with AzureAD external user cannot access SharePoint

We have a Windows Application using MSAL with PublicClientApplicationBuilder to access SharePoint with the delegated permissions of the logged on user.
When our code is used with a login of a user who was invited as an external user in another AzureAD and his user is added to the members of a SharePoint site collection, we get an access token which results in HTTP 401. Using a user from the other AzureAD directly to log in does work. It is just with external user, we fail to get access.
When the user logs into SharePoint in the browser, using his external user login, he can access the other tenants SharePoint. So his external user account has permissions on that site collection, but it works only in the browser, not from our MSAL client.
Some details:
We created the app registration as multi tenant app in our AzureAD with the needed read and write permissions from the SharePoint delegated permission list.
An admin of the other AzureAD consented the delegated permissions for all users and we did the same in our AzureAD. So no matter which user tries to login and use the app will find consented permissions.
We use this code to get a public client app:
var clientAppId = "our-app-clientID";
var redirectUri = "https://login.microsoftonline.com/common/oauth2/nativeclient";
_clientApp = PublicClientApplicationBuilder.Create(clientAppId)
.WithRedirectUri(redirectUri)
.WithLogging(Log, LogLevel.Verbose, false)
// .WithTenantId("we tried our and the other tenants ID")
.Build();
The commented line .WithTenantId was just added while we tried to find a solution.
We can see that it makes a difference for the token content. Without that line or with our tenantId we see the users "oid" is the objectId from the user in our AzureAD.
When we use the tenantId of the other AzureAD, we get the oid of the external user object in that other AzureAD.
So we had hopes that the latter call would succeed, but it fails as well, this time with HTTP 403. So the user token seems to get a bit further, but still not to the SharePoint site collection.
Any idea if this scenario is possible?
Would be nice, if possible and best if we would not have to call WithTenantId because otherwise we would some need to lookup the correct tenantId on the client machine - not sure where to get it from, except asking an admin from the other tenant and putting the value in some app config file or the Windows registry.
• The issue most probably according to your description suggests that the scopes might not be added correctly to the ‘Sharepoint API’ because since you are accessing the sharepoint site from a public client using MSAL authentication, the scopes/permissions to access the sharepoint site from a public client in Azure AD needs to be added and extended to service the requests from external user accounts also.
To do so, you need to add scopes/permissions to Sharepoint API through the Azure portal as when you are calling SharePoint APIs outside of the Microsoft Graph, you call ‘/_api/web/lists’ and it will retrieve all the lists. Thus, if your public client app performs this action using the Microsoft Graph API permissions then you will get an access denied error message as you are encountering HTTP 403 error.
• Thus, in your case, to access the sharepoint sites, you will need to add the scopes ‘AllSites.Read’ and ‘Sites.ReadWrite.All’ to the Sharepoint API for your public client app as the scope for ‘Sites.Read’ in the Microsoft Graph API isn’t enough for it. Also, ensure to add the ‘https://<domain>.sharepoint.com/AllSites.Write’ and ‘https://<yoursite>.sharepoint.com/Sites.ReadWrite.All’ scopes also to the Sharepoint API for that public client app.
To access the Sharepoint API through public client, you use AAD auth for which Microsoft recommends using a certificate rather than a secret. For more information regarding this, kindly use the below documentation link: -
https://learn.microsoft.com/en-us/azure/active-directory/develop/msal-authentication-flows#client-credentials
• Also, ensure that ‘https://microsoft.sharepoint-df.com/Sites.Search.All’ and ‘https://yourtenant.sharepoint.com/Sites.Search.All’ are also added as scope in your application as Sharepoint online site might reject the token because of invalid audience.
For more information regarding the scope modification, kindly refer the below link for more details: -
https://github.com/AzureAD/microsoft-authentication-library-for-js/issues/400

Unable to delete Sharepoint Online term store items programmatically

I'm trying to delete terms or term sets from the default taxonomy store in a C# application which authenticates with an Azure App. I've tried using certificate and app secret authentication as well as a user account context. Using the certificate/app secret, the authentication is successful and I can read terms but receive an error when I try to delete a term:
Microsoft.SharePoint.Client.ServerUnauthorizedAccessException: 'Access denied. You do not have permission to perform this action or access this resource.'
Tried this using both using CSOM and PnP Framework. The App has full read and write permissions for the SharePoint API and Graph API relating to SharePoint/Term Store.
Using user account, I get an error that the login/password could not be found. MFA is disabled for this account in 365 Admin, but it seems the web portal still asks for this to be set up when logging in via browser.
Using the MS Graph API and the same Azure App, I can also create terms, but Graph does not support deleting terms at the moment so this method cannot be used.

Azure Ad B2B authentication retrieve data from external user CRM

We want to build a web app through which Dynamics crm customer's can login. Once they login we would like to show them their CRM's instance contact list. We have implemented Azure B2B Authentication and hosted app but I don't know how to retrieve data from logged in customer's crm .
https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/blob/master/2-WebApp-graph-user/2-3-Multi-Tenant/README.md#about-this-sample
Any help appreciated.
Take a look at CRM connection string examples. You can prompt logged in user for authentication. It creates a new connection to Common Data Service using the current logged in user via OAuth.
I wanted to connect to CRM to work with solutions for a project, so I used to CRM SDK for that by referring to PowerApps samples repo. And my project authenticates user using Azure B2B, and I wanted the same user to connect to CRM. So I used On-Behalf-Of flow.
I first got access token after authenticating user for the AD app. Then I used this token to get another token using UserAssertion for the target org (Ex: https://org12345.crm.dynamics.com/). You'll need to add Dynamics CRM permission like this Registering AD App. Now once I have the token for my target org, I use it like this to connect to CRM:
Uri serviceUrlDestination = new Uri(orgUrl + #"/xrmservices/2011/organization.svc/web?SdkClientVersion=8.2");
OrganizationWebProxyClient sdkServiceDestination = new OrganizationWebProxyClient(serviceUrlDestination, false);
sdkServiceDestination.HeaderToken = AccessToken;
CrmServiceClient serviceClient = new CrmServiceClient(sdkServiceDestination);
I don't know how to retrieve contact list of the logged in user as I used this for mainly for solutions, but once you are connected to CRM from the logged in user's context, I think you should be able to do other operations as well.

OneDrive Personal Daemon Api Access

I have a Personal OneDrive Account Purchased (not Free Tier).
What am I trying to do ?
To write a Daemon in Python that will connect to OneDrive Personal Account Folders and upload / show contents.
What did I tried doing ?
I learned Microsoft Graph is the way to go to access all personal business accounts.
So I signed in with Azure (Free) Portal with my OneDrive Credentials myname#yandex.com , after signing in it created a Azure Default Directory with mynameyan...#onmicrosoft.com as principal user.
Followed Tutorial and created App under App Registration granted it all the Permissions and Also admin Consent through the portal and generated Client Secret and Downloaded the sample code from QuickStart under Portal->Azure Directory-> App Reg..
Ran it on my computer with just one change in the code. After getting the Access Token , I changed the Graph Endpoint to /me/drives/root and I got a "Tenant does not have SPO License" , also I noticed when I change the graph endpoint to /users it yields me mynameyan..#onmicrosoft.com as principal account name. When I expect myname#yandex.com
So in graph Explorer I tried and it yields me proper principal account name as myname#yandex.com also lists all the onedrive personal files as expected.
Problem ?
I cannot authenticate myself properly , since my application will be a Daemon I can't present myself a Login Page with redirect URLs so "Code Flow" type of Acquiring Authentication Token for Personal Accounts will not work for me as mentioned in the Tutorials.
Also if I forcefully query /me it says "Please use consumer endpoint" if I change the Authentication Endpoint it says invalid Client ID and Credentials (Because I think that onmicrosoft.com principal name cannot be used to query OneDrive Personal which belongs to myname#yandex.com )
What do I request ?
An idea of how would others implement this daemon with brief if not detailed steps of configuration in Azure and Code , if possible a Sample code and an Algorithm.
I am new bla bla....hehe , actually I am new to Azure and is also using OAuth First Time. Thanks in advance. I will edit the question if someone needs more information on this to help me.
You cannot use daemon to access personal account OneDrive files.
Daemon app will use Application permission (without user) to do the operation.
But based on the Microsoft Graph Get Files Permissions, Only Delegated permission is supported for personal Microsoft account. And Delegated Permission means app + user permission.
Currently you have to implement Get access on behalf of a user and use auth code flow to access personal account OneDrive files with Microsoft Graph API.

Resources