2

I upgraded my UWP app from OneDrive SDK to Microsoft Graph SDK. The app has been registered earlier at https://apps.dev.microsoft.com/ (under "Live SDK applications").

I have implemented the new authentication using MSAL.NET (NuGet package Microsoft.Identity.Client). Here is the code I use for authentication:

    public class AuthenticationService
    {
        private const string Tenant = "common"; 
        private const string Authority = "https://login.microsoftonline.com/" + Tenant;
    
        private const string MSGraphURL = "https://graph.microsoft.com/v1.0/";
        private const string RedirectUri = "https://login.microsoftonline.com/common/oauth2/nativeclient";
    
        private readonly string[] scopes;
    
        private readonly IPublicClientApplication publicClientApp;
    
        private GraphServiceClient graphClient;
    
        private AuthenticationResult authResult;
    
        public AuthenticationService(string clientId, string[] scopes)
        {
            this.scopes = scopes;
    
            this.publicClientApp = PublicClientApplicationBuilder.Create(clientId)
                .WithAuthority(Authority)
                .WithUseCorporateNetwork(false)
                .WithRedirectUri(RedirectUri)
                    .WithLogging((level, message, containsPii) =>
                    {
                        Debug.WriteLine($"MSAL: {level} {message} ");
                    }, Microsoft.Identity.Client.LogLevel.Warning, enablePiiLogging: false, enableDefaultPlatformLogging: true)
                .Build();
        }
        public string TokenForUser => authResult?.AccessToken;
    
        public DateTimeOffset? TokenExpireOn => authResult?.ExpiresOn;
    
        public GraphServiceClient SignIn()
        {
            if (graphClient == null)
            {
                graphClient = new GraphServiceClient(MSGraphURL,
                    new DelegateAuthenticationProvider(async (requestMessage) =>
                    {
                        if (string.IsNullOrEmpty(TokenForUser))
                        {
                            authResult = await AuthenticateAsync();
                        }
                        requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", TokenForUser);
                    }));
            }
    
            return graphClient;
        }
    
        public async Task SignOutAsync()
        {
            try
            {
                authResult = null;
                graphClient = null;
    
                foreach (IAccount account in await publicClientApp.GetAccountsAsync().ConfigureAwait(false))
                {
                    await publicClientApp.RemoveAsync(account).ConfigureAwait(false);
                }
            }
            catch (MsalException ex)
            {
                Log.Exception(ex);
            }
        }
    
        private async Task<AuthenticationResult> AuthenticateAsync()
        {
            IEnumerable<IAccount> accounts = await publicClientApp.GetAccountsAsync().ConfigureAwait(false);
            IAccount firstAccount = accounts.FirstOrDefault();
    
            AuthenticationResult authResult;
            try
            {
                authResult = await publicClientApp.AcquireTokenSilent(scopes, firstAccount)
                                                    .ExecuteAsync().ConfigureAwait(false);
            }
            catch (MsalUiRequiredException ex)
            {
                Log.Exception(ex);
    
                authResult = await publicClientApp.AcquireTokenInteractive(scopes)
                                                    .ExecuteAsync()
                                                    .ConfigureAwait(false);
    
            }
            return authResult;
        }
    }

Above code works only if I register my app in Azure Portal and get the new clientId from there. Trying to use the old application ID results this exception:

Microsoft.Identity.Client.MsalClientException: 'Error: ClientId is not a Guid.'

I cannot renew my app registration as the app is using app folder (Files.ReadWrite.AppFolder) and registering the app again would result existing users to loose their data.

So how do I authenticate my app against the Microsoft Graph API using the old "Live SDK application" App Id and preferably using the current Windows account (no sign in UI required)?

kine
  • 1,352
  • 2
  • 12
  • 24

2 Answers2

0

Finally found a fix:

  1. Make sure your app is associated with the Store.

  2. Find the system assigned app's redirect URI with this code:

string URI = string.Format("ms-appx-web://Microsoft.AAD.BrokerPlugIn/{0}", WebAuthenticationBroker.GetCurrentApplicationCallbackUri().Host.ToUpper());
  1. Register your app in the Azure portal and add the redirect URI you obtained in the previous step to your app registration. Under your app registration page select from menu "Authentication" and add the URI to the list "Redirect URIs".

  2. Add these packages to your solution from https://github.com/CommunityToolkit/Graph-Controls:

  • CommunityToolkit.Authentication
  • CommunityToolkit.Authentication.Uwp
  • CommunityTookit.Graph
  • CommunityToolkit.Graph.Uwp
  1. Sample utility class for accessing OneDrive (get clientId from your app registration page):
    public class OneDriveClient
    {
        private readonly static string[] DefaultScopes = new string[] { "Files.ReadWrite.AppFolder", "offline_access", "openid" };

        private GraphServiceClient client;

        public OneDriveClient(string clientId, string[] scopes)
        {
            var webAccountProviderConfig = 
                new WebAccountProviderConfig(WebAccountProviderType.Local, clientId);
            ProviderManager.Instance.GlobalProvider = 
                new WindowsProvider(scopes ?? DefaultScopes, webAccountProviderConfig);
            ProviderManager.Instance.ProviderStateChanged += OnProviderStateChanged;
        }

        private void OnProviderStateChanged(object sender, ProviderStateChangedEventArgs e)
        {
            if (e.NewState == ProviderState.SignedIn)
            {
                this.client = ProviderManager.Instance.GlobalProvider.GetClient();
            }
        }

        public bool IsAuthenticated => ProviderManager.Instance.State == ProviderState.SignedIn;

        public Task SignInAsync() => ProviderManager.Instance.GlobalProvider.SignInAsync();

        public Task SignOutAsync() => ProviderManager.Instance.GlobalProvider.SignOutAsync();

        public Task<Drive> GetDriveAsync() => this.client.Drive.Request().GetAsync();
    }

Now you can access the same App Folder which was created with the old OneDrive SDK. For details see also this sample.

kine
  • 1,352
  • 2
  • 12
  • 24
-1

You need to create a new app registration in the Azure Portal. Also you need to login using a work or school account or personal (Microsoft) account trough one of the supported MSAL flows. Files.ReadWrite.AppFolder is a permission. Adding it to a new application won't delete or loose anything.

AlfredoRevilla-MSFT
  • 3,171
  • 1
  • 12
  • 18
  • 1
    The upgraded app must be able to access the existing app folder and not to create a new one. Registering the app again causes a new app folder to be created (as app folder is associated with the application ID I guess). So creating a new app registration does not solve this. – kine Oct 02 '20 at 12:03
  • @kine do you have documentation that states an app folder is created for a new app? – AlfredoRevilla-MSFT Oct 05 '20 at 17:19
  • I have tested it myself, see [this](https://stackoverflow.com/questions/63953408/how-to-upgrade-from-onedrive-sdk-to-microsoft-graph-sdk-and-keep-the-old-appfold). – kine Oct 06 '20 at 06:09
  • 1
    @kine I see. I will reach within the appropiate team and come back to you. – AlfredoRevilla-MSFT Oct 09 '20 at 23:56
  • @AlfredoR Please see the following question: https://stackoverflow.com/questions/66073712/how-to-migrate-a-uwp-apps-authentication-from-onedrive-sdk-to-graph This is a similar problem and my app will, pretty much, die if I can't figure out how to make this work – jasonxz Feb 06 '21 at 04:56
  • 1
    @AlfredoR Any solution yet? This is a big problem since I cannot publish my app update until this is resolved somehow. – kine Apr 24 '21 at 10:13
  • Hey @kine, sorry for the lack of response, I left MSFT in December 2020 and do not check SO regularly. I suggest you move this one to [MSFT Q&A](https://learn.microsoft.com/en-us/answers/topics/microsoft-graph-files.html). In the meantime, I will contact my old team to pick up your question here too. – AlfredoRevilla-MSFT Jul 01 '21 at 11:07