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)?