Creating custom authentication provider for OneDriveClient and GraphClient

This post is a contribution from Sohail Sayed, an engineer with the SharePoint Developer Support team

The following post demonstrates creating a custom authentication provider which can be used for authentication with the OneDriveClient or GraphClient classes.

 

Why create a custom authentication provider

The One Drive SDK sample at https://github.com/OneDrive/onedrive-sdk-csharp uses the MsaAuthenticationProvider which authenticates with OneDrive Personal only. There is an alternate DelegateAuthenticationProvider which works for OneDrive For Business but only for apps registered in https://apps.dev.microsoft.com and not in https://portal.azure.com .

Also you may scenarios where you may need to customize the authentication process. For example you may want to use a service account credential to authenticate and avoid prompting the user for credentials.

 

Creating the custom authentication provider

Creating a custom authentication provider involves the below steps

1.       Create a class implementing the Microsoft.Graph.IAuthenticationProvider

2.       Implement the method “Task AuthenticateRequestAsync(HttpRequestMessage request)” which will perform the authentication.

The AuthenticateRequestAsync method has a parameter of type HttpRequestMessage which represents the HttpRequest for the OneDriveClient or the GraphClient. The code for the authentication provider needs to add the AccessToken to the Authorization Header for this request.

 

Code Sample

Below implementation will prompt user for the first time to enter the user credentials for OneDrive. You need to reference the following NuGet Packages.

  • Microsoft.Graph.Core
  • Microsoft.IdentityModel.Clients.ActiveDirectory –  ADAL Library
 using Microsoft.Graph;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Http;
using System.Security;
using Microsoft.IdentityModel.Clients.ActiveDirectory;

namespace Sample
{
    // simple implementation of ODBAuth
    public class ODBAuthentication : IAuthenticationProvider
    {

        internal const string GraphApiUrl = "https://graph.microsoft.com";
        internal const string Authority = "https://login.microsoftonline.com/";

        public string TenantId { get; private set; }

        public string ClientId { get; private set; }
        public string RedirectUrl { get; set; }
        public string AccessToken { get; private set; }

        private IntPtr handle;

        // this works with a windows application
        // We need to get the current window handle
        // Within a windows form you can get the current windows handle using the property this.Handle
        public ODBAuthentication(string tenantId, string clientId, string redirectUrl, IntPtr handle)
        {
            this.TenantId = tenantId;
            this.ClientId = clientId;
            this.RedirectUrl = redirectUrl;
            this.handle = handle;
        }

        AuthenticationResult authenticationResult = null;

        public async Task AuthenticateRequestAsync(HttpRequestMessage request)
        {
            AuthenticationContext authenticationContext = new AuthenticationContext(Authority + TenantId, false);

            try
            {
                // tracking if the user has signed atleast once within the app 
                // you can avoid this by using the option PromptBehavior.Auto but this will sign-in with the default user
                // use PromptBehavior.RefreshSession if you want to give user the option to choose the user login first time
                // Alternatively for console application or background applications use the overload of AcquireTokenAsync to signin with a service account using silent sign in
                if (authenticationResult == null)
                {
                    authenticationResult = await authenticationContext
                        .AcquireTokenAsync(GraphApiUrl, ClientId, new Uri(this.RedirectUrl), new PlatformParameters(PromptBehavior.RefreshSession, handle))
                        .ConfigureAwait(false);
                }
                else
                {
                    // Use PromptBehavior.Auto for subsequent requests
                    authenticationResult = await authenticationContext
                      .AcquireTokenAsync(GraphApiUrl, ClientId, new Uri(this.RedirectUrl), new PlatformParameters(PromptBehavior.Auto, handle))
                      .ConfigureAwait(false);
                }


                request.Headers.Add("Authorization", "Bearer " + authenticationResult.AccessToken);

            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

    }
}

Below example uses the custom authentication provider with a OneDriveClient.  You need to create a native app in https://portal.azure.com with appropriate access for OneDrive and pass the TenantName, ClientID and RedirectUrl values from that app.

 ODBAuthentication odbAuth = new ODBAuthentication(tenantName, clientId, redirectUrl, this.Handle);
var oneDriveClient = new OneDriveClient("https://graph.microsoft.com/v1.0/me/", odbAuth);

Using the custom authentication provider with GraphClient class is similar.

 ODBAuthentication odbAuth = new ODBAuthentication(tenantName, clientId, redirectUrl, this.Handle);
var graphClient = new GraphServiceClient("https://graph.microsoft.com/v1.0",odbAuth);