azuremicrosoft-graph-apisharepoint-onlinemicrosoft-graph-sdks

How to set a specific user as the modifier when uploading a file to SharePoint using Graph SDK with App-Only Authentication?


I am using Microsoft Graph SDK(C#) V5.56 with App-Only Authentication to upload files to SharePoint. However, when I upload a file, the lastModifiedBy field is always set to "SharePoint App". I need to set the lastModifiedBy field to a specific user instead of the SharePoint App.

Is there a way to upload a file to SharePoint and have the lastModifiedBy field reflect a user of my choice instead of the SharePoint App while using App-Only Authentication?

This code is working well but it set lastModifiedBy to 'SharePoint App' in sharepoint.

public static async Task ReplaceFileInOneDriveAsync(GraphServiceClient gsc, string driveId, string itemId, MemoryStream memoryStream)
{
    memoryStream.Position = 0;

    Microsoft.Kiota.Abstractions.RequestInformation requestInformations = gsc.Drives[driveId].Items[itemId].Content.ToPutRequestInformation(memoryStream);
    requestInformations.URI = new Uri(requestInformations.URI.OriginalString + "?@microsoft.graph.conflictBehavior=replace");
    var uploadResult = await gsc.RequestAdapter.SendAsync<DriveItem>(requestInformations, DriveItem.CreateFromDiscriminatorValue);
}

Also I tried some code starting with Users like this but failed.

gsc.Users["user1@constone.com"].Drives["someID"].....this doesn't contains Items :(

Please suggest!


Solution

  • As I mentioned in comments, lastModifiedBy field is set based on the context in which the file is modified.

    When I ran below code to upload the file using App-Only Authentication, it set lastModifiedBy to 'SharePoint App' as the operation is performed on behalf of the application.

    using System.Net.Http.Headers;
    using Azure.Core;
    using Azure.Identity;
    
    namespace UserProperties
    {
        public class GraphHandler
        {
            private readonly string _clientId = "appId";
            private readonly string _clientSecret = "secret";
            private readonly string _tenantId = "tenantId";
            private readonly string _authorityHost = "https://login.microsoftonline.com/";
    
            public async Task UploadFileToSharePoint(string siteId, string driveId, string fileName, string filePath)
            {
                try
                {
                    var accessToken = await GetAccessTokenAsync();
                    var uploadUrl = $"https://graph.microsoft.com/v1.0/sites/{siteId}/drives/{driveId}/items/root:/{fileName}:/content";
    
                    using (var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
                    using (var httpClient = new HttpClient())
                    {
                        httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
                        using (var httpRequest = new HttpRequestMessage(HttpMethod.Put, uploadUrl))
                        {
                            httpRequest.Content = new StreamContent(fileStream);
                            httpRequest.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
    
                            using (var response = await httpClient.SendAsync(httpRequest))
                            {
                                response.EnsureSuccessStatusCode();
                                Console.WriteLine("File uploaded successfully.");
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"Error uploading file: {ex.Message}");
                }
            }
    
            private async Task<string> GetAccessTokenAsync()
            {
                var options = new TokenCredentialOptions
                {
                    AuthorityHost = new Uri(_authorityHost)
                };
    
                var clientSecretCredential = new ClientSecretCredential(_tenantId, _clientId, _clientSecret, options);
                var tokenRequestContext = new TokenRequestContext(new string[] { "https://graph.microsoft.com/.default" });
    
                var accessTokenResult = await clientSecretCredential.GetTokenAsync(tokenRequestContext);
    
                return accessTokenResult.Token;
            }
        }
    
        class Program
        {
            static async Task Main(string[] args)
            {
                var handler = new GraphHandler();
                var siteId = "siteId";
                var driveId = "driveId";
                var fileName = "logo.jpg";
                var filePath = "C:\\Users\\xxxxxxx\\Downloads\\srrprofile.jpg";
                await handler.UploadFileToSharePoint(siteId, driveId, fileName, filePath);
            }
        }
    }
    

    SharePoint Portal:

    enter image description here

    To set a specific user as the modifier, you need to switch to Delegated flows like interactive flow or authorization code flow that involves user interaction.

    I registered one Entra ID application and granted permissions of Delegated type as below:

    enter image description here

    While using interactive flow, make sure to add redirect URI in Mobile & Desktop applications platform and enable public client flow option like this:

    enter image description here

    Now, I ran below modified code that asks the user to login and uploads file to SharePoint setting that user as modifier as below:

    using System.Net.Http.Headers;
    using Azure.Core;
    using Azure.Identity;
    
    namespace UserProperties
    {
        public class GraphHandler
        {
            private readonly string _clientId = "appId";
            private readonly string _tenantId = "tenantId";
            private readonly string _authorityHost = "https://login.microsoftonline.com/";
    
            public async Task UploadFileToSharePoint(string siteId, string driveId, string fileName, string filePath)
            {
                try
                {
                    var accessToken = await GetAccessTokenAsync();
                    var uploadUrl = $"https://graph.microsoft.com/v1.0/sites/{siteId}/drives/{driveId}/items/root:/{fileName}:/content";
    
                    using (var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
                    using (var httpClient = new HttpClient())
                    {
                        httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
                        using (var httpRequest = new HttpRequestMessage(HttpMethod.Put, uploadUrl))
                        {
                            httpRequest.Content = new StreamContent(fileStream);
                            httpRequest.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
    
                            using (var response = await httpClient.SendAsync(httpRequest))
                            {
                                response.EnsureSuccessStatusCode();
                                Console.WriteLine("File uploaded successfully.");
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"Error uploading file: {ex.Message}");
                }
            }
    
            private async Task<string> GetAccessTokenAsync()
            {
                var options = new InteractiveBrowserCredentialOptions
                {
                    AuthorityHost = new Uri(_authorityHost)
                };
    
                var interactiveCredential = new InteractiveBrowserCredential(_tenantId, _clientId, options);
                var tokenRequestContext = new TokenRequestContext(new string[] { "https://graph.microsoft.com/.default" });
    
                var accessTokenResult = await interactiveCredential.GetTokenAsync(tokenRequestContext);
    
                return accessTokenResult.Token;
            }
        }
    
        class Program
        {
            static async Task Main(string[] args)
            {
                var handler = new GraphHandler();
                var siteId = "siteId";
                var driveId = "driveId";
                var fileName = "logo.jpg";
                var filePath = "C:\\Users\\xxxxxx\\Downloads\\srrprofile.jpg";
                await handler.UploadFileToSharePoint(siteId, driveId, fileName, filePath);
            }
        }
    }
    

    SharePoint Portal:

    enter image description here