Gordana Tasic

Gordana Tasic

  • 2k
  • 62
  • 2.5k

How to log in only once using Graph API?

Mar 16 2021 11:45 AM

I’m developing a small Windows form app to test Graph API functions. I have two functionalities in the application, user's log in and create a team. I created a class that contains a function for creating a GraphServiceClient. I call this function both when the users logs in and when I create a team. The problem is that the user login window is displayed both times, and I want that once the user logs in, to somehow save that GraphServiceClient instance so that the user does not have to double logs in. Here is the code:

 
  1. public static class GraphManager  
  2. {  
  3.     public static GraphServiceClient graphClient;  
  4.   
  5.     private static string[] scopes = new string[] { "user.read" };  
  6.     public static string TokenForUser = null;  
  7.     public static DateTimeOffset expiration;  
  8.   
  9.     private const string ClientId = "599ed98d-4356-4a96-ad37-04391e9c48dc";  
  10.   
  11.     private const string Tenant = "common"// Alternatively "[Enter your tenant, as obtained from the Azure portal, e.g. kko365.onmicrosoft.com]"  
  12.     private const string Authority = "https://login.microsoftonline.com/" + Tenant;  
  13.   
  14.     // The MSAL Public client app  
  15.     private static IPublicClientApplication PublicClientApp;  
  16.   
  17.     private static string MSGraphURL = "https://graph.microsoft.com/beta/";  
  18.     private static AuthenticationResult authResult;  
  19.   
  20.     public static GraphServiceClient GetGraphClient()  
  21.     {  
  22.         if(graphClient == null)  
  23.         {  
  24.             // Create Microsoft Graph client.  
  25.             try  
  26.             {  
  27.                 graphClient = new GraphServiceClient(  
  28.                     "https://graph.microsoft.com/v1.0",  
  29.                     new DelegateAuthenticationProvider(  
  30.                         async (requestMessage) =>  
  31.                         {  
  32.                             var token = await GetTokenForUserAsync();  
  33.                             requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", token);  
  34.                             // This header has been added to identify our sample in the Microsoft Graph service.  If extracting this code for your project please remove.  
  35.                             requestMessage.Headers.Add("SampleID""uwp-csharp-snippets-sample");  
  36.   
  37.                         }));  
  38.                 return graphClient;  
  39.             }  
  40.   
  41.             catch (Exception ex)  
  42.             {  
  43.                 Debug.WriteLine("Could not create a graph client: " + ex.Message);  
  44.             }  
  45.         }  
  46.         return graphClient;  
  47.     }  
  48.   
  49.     public static async Task<string> GetTokenForUserAsync()  
  50.     {  
  51.         if (TokenForUser == null || expiration <= DateTimeOffset.UtcNow.AddMinutes(5))  
  52.         {  
  53.             PublicClientApp = PublicClientApplicationBuilder.Create(ClientId)  
  54.           .WithAuthority(Authority)  
  55.           .WithRedirectUri("https://login.microsoftonline.com/common/oauth2/nativeclient")  
  56.            .WithLogging((level, message, containsPii) =>  
  57.            {  
  58.                Debug.WriteLine($"MSAL: {level} {message} ");  
  59.            }, LogLevel.Warning, enablePiiLogging: false, enableDefaultPlatformLogging: true)  
  60.           .Build();  
  61.   
  62.             // It's good practice to not do work on the UI thread, so use ConfigureAwait(false) whenever possible.  
  63.             IEnumerable<IAccount> accounts = await PublicClientApp.GetAccountsAsync().ConfigureAwait(false);  
  64.             IAccount firstAccount = accounts.FirstOrDefault();  
  65.   
  66.             try  
  67.             {  
  68.                 authResult = await PublicClientApp.AcquireTokenSilent(scopes, firstAccount)  
  69.                                                   .ExecuteAsync();  
  70.             }  
  71.             catch (MsalUiRequiredException ex)  
  72.             {  
  73.                 // A MsalUiRequiredException happened on AcquireTokenSilentAsync. This indicates you need to call AcquireTokenAsync to acquire a token  
  74.                 Debug.WriteLine($"MsalUiRequiredException: {ex.Message}");  
  75.   
  76.                 authResult = await PublicClientApp.AcquireTokenInteractive(scopes)  
  77.                                                   .ExecuteAsync()  
  78.                                                   .ConfigureAwait(false);  
  79.             }  
  80.   
  81.             TokenForUser = authResult.AccessToken;  
  82.         }  
  83.   
  84.         return TokenForUser;  
  85.     }  
  86.   
  87. }  
  88.   
  89. private async void button1_Click(object sender, EventArgs e)  
  90.     {  
  91.         
  92.         GraphServiceClient graphClient = GraphManager.GetGraphClient();  
  93.         User graphUser = await graphClient.Me.Request().GetAsync();  
  94.         label2.Text = graphUser.DisplayName;  
  95.     }  
  96.   
  97.  private async void button2_Click(object sender, EventArgs e)  
  98.     {  
  99.         GraphServiceClient graphClient = GraphManager.GetGraphClient();  
  100.   
  101.         var team = new Team  
  102.             {  
  103.                 DisplayName = "Test1Test2",  
  104.                 Description = "My sample team's description.",  
  105.                 AdditionalData = new Dictionary<stringobject>()  
  106.             {  
  107.                 {"template@odata.bind""https://graph.microsoft.com/beta/teamsTemplates('educationClass')" }  
  108.             }  
  109.             };  
  110.   
  111.             await graphClient.Teams.Request().AddAsync(team);  
  112.             MessageBox.Show("Successfully created team!");  
  113.     } 

Answers (3)