{"id":4908,"date":"2020-06-25T16:00:08","date_gmt":"2020-06-25T23:00:08","guid":{"rendered":"https:\/\/officedevblogs.wpengine.com\/?p=4908"},"modified":"2020-06-25T16:00:08","modified_gmt":"2020-06-25T23:00:08","slug":"a-lap-around-microsoft-graph-toolkit-day-11-microsoft-graph-toolkit-proxy-provider","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/a-lap-around-microsoft-graph-toolkit-day-11-microsoft-graph-toolkit-proxy-provider\/","title":{"rendered":"A Lap around Microsoft Graph Toolkit Day 11 \u2013 Microsoft Graph Toolkit Proxy Provider"},"content":{"rendered":"<p><b><span data-contrast=\"auto\">Author:\u00a0<\/span><\/b><b><span data-contrast=\"auto\">Ashish Trivedi<\/span><\/b><span data-ccp-props=\"{&quot;201341983&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:259}\">, Microsoft Office Development MVP<\/span><\/p>\n<p><a href=\"https:\/\/twitter.com\/_AshishTrivedi\"><span data-contrast=\"none\">@<\/span><span data-contrast=\"none\">_<\/span><span data-contrast=\"none\">AshishTrivedi<\/span><\/a><span data-contrast=\"auto\">\u00a0|\u00a0<\/span><a href=\"https:\/\/www.linkedin.com\/in\/trivediashish\/\"><span data-contrast=\"none\">LinkedIn<\/span><\/a><span data-ccp-props=\"{&quot;201341983&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:259}\">\u00a0<\/span><\/p>\n<h3><span class=\"TextRun SCXW89476804 BCX0\" lang=\"EN-CA\" xml:lang=\"EN-CA\" data-contrast=\"none\"><span class=\"NormalTextRun SCXW89476804 BCX0\" data-ccp-parastyle=\"heading 2\">Introduction<\/span><\/span><span class=\"EOP SCXW89476804 BCX0\" data-ccp-props=\"{&quot;201341983&quot;:0,&quot;335559738&quot;:40,&quot;335559739&quot;:0,&quot;335559740&quot;:259}\">\u00a0<\/span><\/h3>\n<p><span data-contrast=\"auto\">Hey\u00a0<\/span><span data-contrast=\"auto\">d<\/span><span data-contrast=\"auto\">evs, welcome to day 1<\/span><span data-contrast=\"auto\">1<\/span><span data-contrast=\"auto\">\u00a0of the\u00a0<\/span><a href=\"https:\/\/aka.ms\/mgtlap\"><span data-contrast=\"none\">Microsoft Graph Toolkit blog series<\/span><\/a><span data-contrast=\"auto\">!<\/span><span data-contrast=\"auto\">\u00a0<\/span><span data-contrast=\"auto\">Today we will explore the\u00a0<\/span><span data-contrast=\"auto\">Microsoft Graph Toolkit proxy provider<\/span><span data-contrast=\"auto\">.<\/span><span data-ccp-props=\"{&quot;201341983&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:259}\">\u00a0<\/span><\/p>\n<p><strong>What is\u00a0the\u00a0proxy\u00a0provider?\u00a0<\/strong><\/p>\n<p><span data-contrast=\"auto\">As the name suggest<\/span><span data-contrast=\"auto\">s,<\/span><span data-contrast=\"auto\">\u00a0this\u00a0<\/span><span data-contrast=\"auto\">Microsoft Graph Toolkit (MGT)\u00a0<\/span><span data-contrast=\"auto\">provider enable<\/span><span data-contrast=\"auto\">s<\/span><span data-contrast=\"auto\">\u00a0you to\u00a0<\/span><span data-contrast=\"auto\">use a proxy API\u00a0<\/span><span data-contrast=\"auto\">behind the Graph Toolkit components<\/span><span data-contrast=\"auto\">\u00a0rather\u00a0<\/span><span data-contrast=\"auto\">than\u00a0<\/span><span data-contrast=\"auto\">calling the\u00a0<\/span><span data-contrast=\"auto\">Microsoft\u00a0<\/span><span data-contrast=\"auto\">Graph API directly.<\/span><span data-contrast=\"auto\">\u00a0You will transform the<\/span><span data-contrast=\"auto\">\u00a0API calls such as below \u2013\u00a0<\/span><span data-ccp-props=\"{&quot;201341983&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:259}\">\u00a0<\/span><\/p>\n<p><a href=\"https:\/\/graph.microsoft.com\/v1.0\/me\"><span data-contrast=\"none\">https:\/\/graph.microsoft.com\/v1.0\/me<\/span><\/a><span data-contrast=\"auto\">\u00a0==&gt;\u00a0<\/span><a href=\"https:\/\/yourapi.com\/api\/GraphProxy\/v1.0\/me\"><span data-contrast=\"none\">https:\/\/YourAPI.com\/api\/GraphProxy\/v1.0\/me<\/span><\/a><span data-contrast=\"auto\">\u00a0<\/span><span data-ccp-props=\"{&quot;201341983&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:259}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">When you use the proxy provider, you can use your backend authentication<\/span><span data-contrast=\"auto\">\u00a0to power the Microsoft Graph Toolkit by routing calls to Microsoft Graph through your own backend.\u00a0<\/span><span data-ccp-props=\"{&quot;201341983&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:259}\">\u00a0<\/span><\/p>\n<ul>\n<li style=\"font-weight: 400\" data-leveltext=\"\" data-font=\"\" data-listid=\"0\" data-aria-posinset=\"1\" data-aria-level=\"1\"><span data-contrast=\"auto\">You can use the proxy provider i<\/span><span data-contrast=\"auto\">n various application development scenarios, two of them are listed as below &#8211;\u00a0<\/span><span data-contrast=\"auto\">If you\u2019re an\u00a0<\/span><span data-contrast=\"auto\">ISV enterprise<\/span><span data-contrast=\"auto\">\u00a0partner<\/span><span data-contrast=\"auto\">\u00a0developing products\u00a0<\/span><span data-contrast=\"auto\">that call<\/span><span data-contrast=\"auto\">\u00a0<\/span><span data-contrast=\"auto\">product<\/span><span data-contrast=\"auto\">&#8211;<\/span><span data-contrast=\"auto\">specific APIs along with\u00a0<\/span><span data-contrast=\"auto\">Microsoft\u00a0<\/span><span data-contrast=\"auto\">Graph APIs, you\u00a0<\/span><span data-contrast=\"auto\">can\u00a0<\/span><span data-contrast=\"auto\">bundle them\u00a0<\/span><span data-contrast=\"auto\">all\u00a0<\/span><span data-contrast=\"auto\">with the<\/span><span data-contrast=\"auto\">\u00a0<\/span><span data-contrast=\"auto\">proxy provider.<\/span><span data-ccp-props=\"{&quot;134233279&quot;:true,&quot;201341983&quot;:0,&quot;335551550&quot;:1,&quot;335551620&quot;:1,&quot;335559685&quot;:720,&quot;335559739&quot;:160,&quot;335559740&quot;:259}\">\u00a0<\/span><\/li>\n<li style=\"font-weight: 400\" data-leveltext=\"\" data-font=\"\" data-listid=\"0\" data-aria-posinset=\"1\" data-aria-level=\"1\"><span data-contrast=\"auto\">If you\u2019re\u00a0<\/span><span data-contrast=\"auto\">a\u00a0<\/span><span data-contrast=\"auto\">partner \/\u00a0<\/span><span data-contrast=\"auto\">developer<\/span><span data-contrast=\"auto\">\u00a0<\/span><span data-contrast=\"auto\">you<\/span><span data-contrast=\"auto\">\u00a0can manage all\u00a0<\/span><span data-contrast=\"auto\">you<\/span><span data-contrast=\"auto\">r<\/span><span data-contrast=\"auto\">\u00a0<\/span><span data-contrast=\"auto\">API\u00a0<\/span><span data-contrast=\"auto\">calls and authentication in your custom API proxy provider, hiding complexity away<\/span><span data-contrast=\"auto\">.<\/span><span data-ccp-props=\"{&quot;134233279&quot;:true,&quot;201341983&quot;:0,&quot;335559685&quot;:720,&quot;335559739&quot;:160,&quot;335559740&quot;:259}\">\u00a0<\/span><\/li>\n<\/ul>\n<p><span data-contrast=\"auto\">Sounds exciting<\/span><span data-contrast=\"auto\">?\u00a0<\/span><span data-contrast=\"auto\">Let<\/span><span data-contrast=\"auto\">\u2019s<\/span><span data-contrast=\"auto\">\u00a0<\/span><span data-contrast=\"auto\">build<\/span><span data-contrast=\"auto\">\u00a0a sample on ASP.NET MVC model to easily understand this<\/span><span data-contrast=\"auto\">.<\/span><span data-ccp-props=\"{&quot;201341983&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:259}\">\u00a0<\/span><\/p>\n<h3>A guide to build proxy provider application<\/h3>\n<h4>Step 1 \u2013 Setup the development environment<\/h4>\n<p><span data-contrast=\"auto\">For tr<\/span><span data-contrast=\"auto\">ying the sample written in this blog post,\u00a0<\/span><span data-contrast=\"auto\">y<\/span><span data-contrast=\"auto\">ou will need\u00a0<\/span><span data-contrast=\"auto\">a<\/span><span data-contrast=\"auto\">\u00a0Microsoft 365 tenant where you have admin access. If you don\u2019t have one, you can\u00a0<\/span><span data-contrast=\"auto\">join Microsoft 365 Developer program.<\/span><span data-contrast=\"auto\">\u00a0<\/span><span data-contrast=\"auto\">To write and compile code, we will be using Visual Studio. If you don\u2019t have one, you can download the\u00a0<\/span><span data-contrast=\"none\">Visual Studio Community<\/span><span data-contrast=\"auto\">\u00a0edition for free.<\/span><span data-ccp-props=\"{&quot;201341983&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:259}\">\u00a0<\/span><\/p>\n<h4>Step\u00a02\u00a0\u2013 Create your application<\/h4>\n<p><span data-contrast=\"auto\">Before you can start writing you application by following the steps detailed below, if you have not done any application development using Microsoft Graph Toolkit previously, plea<\/span><span data-contrast=\"auto\">se read through the season 1 articles of\u00a0<\/span><span data-contrast=\"none\">A Lap around Microsoft Graph Toolkit<\/span><span data-contrast=\"auto\">\u00a0<\/span><span data-contrast=\"auto\">to familiarize yourself.<\/span><span data-ccp-props=\"{&quot;201341983&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:259}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">Now, you are ready to build your first application with<\/span><span data-contrast=\"auto\">\u00a0<\/span><span data-contrast=\"auto\">the<\/span><span data-contrast=\"auto\">\u00a0proxy provider.<\/span><span data-ccp-props=\"{&quot;201341983&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:259}\">\u00a0<\/span><\/p>\n<p><strong>Register\u00a0your application\u00a0<\/strong><\/p>\n<p><span data-contrast=\"auto\">To follow along\u00a0<\/span><span data-contrast=\"auto\">with the exercise\u00a0<\/span><span data-contrast=\"auto\">in this blog, you will need to create a new Azure AD web application registration in Azure Portal.<\/span><span data-ccp-props=\"{&quot;201341983&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:259}\">\u00a0<\/span><\/p>\n<ol>\n<li><span data-contrast=\"auto\">Login to <\/span><a href=\"https:\/\/portal.azure.com\/\"><span data-contrast=\"none\">Azure Portal<\/span><\/a><span data-contrast=\"auto\">\u00a0using the account you created with your developer subscription.<\/span><span data-ccp-props=\"{&quot;134233279&quot;:true,&quot;201341983&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:259}\">\u00a0<\/span><\/li>\n<\/ol>\n<p><span data-contrast=\"auto\">2. Select <\/span><b><span data-contrast=\"auto\">Azure Active Directory<\/span><\/b><span data-contrast=\"auto\">\u00a0in the left-hand navigation, then select\u00a0<\/span><b><span data-contrast=\"auto\">App registrations<\/span><\/b><span data-contrast=\"auto\">\u00a0under\u00a0<\/span><b><span data-contrast=\"auto\">Manage<\/span><\/b><span data-contrast=\"auto\">\u00a0and click\u00a0<\/span><b><span data-contrast=\"auto\">New registration<\/span><\/b><span data-contrast=\"auto\">.<\/span><span data-ccp-props=\"{&quot;134233279&quot;:true,&quot;201341983&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:259}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">3. On the register an application page, set the following values:<\/span><span data-ccp-props=\"{&quot;134233279&quot;:true,&quot;201341983&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:259}\">\u00a0<\/span><\/p>\n<ul>\n<li data-leveltext=\"%2.\" data-font=\"\" data-listid=\"15\" data-aria-posinset=\"1\" data-aria-level=\"2\"><span data-contrast=\"auto\">Set\u00a0<\/span><b><span data-contrast=\"auto\">Name<\/span><\/b><span data-contrast=\"auto\">\u00a0= MGT-<\/span><span data-contrast=\"auto\">ProxyProvider<\/span><span data-contrast=\"auto\">-App (or any name you would like for your application)<\/span><span data-ccp-props=\"{&quot;134233279&quot;:true,&quot;201341983&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:259}\">\u00a0<\/span><\/li>\n<\/ul>\n<ul>\n<li data-leveltext=\"%2.\" data-font=\"\" data-listid=\"15\" data-aria-posinset=\"2\" data-aria-level=\"2\"><span data-contrast=\"auto\">Set\u00a0<\/span><b><span data-contrast=\"auto\">Supported account types<\/span><\/b><span data-contrast=\"auto\">\u00a0=\u00a0<\/span> <b><span data-contrast=\"auto\">Accounts in any organizational directory (Any Azure AD directory &#8211; Multitenant)<\/span><\/b><span data-contrast=\"auto\">\u00a0<\/span><span data-ccp-props=\"{&quot;134233279&quot;:true,&quot;201341983&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:259}\">\u00a0<\/span><\/li>\n<\/ul>\n<ul>\n<li data-leveltext=\"%2.\" data-font=\"\" data-listid=\"15\" data-aria-posinset=\"3\" data-aria-level=\"2\"><span data-contrast=\"auto\">Under\u00a0<\/span><b><span data-contrast=\"auto\">Redirect URI<\/span><\/b><span data-contrast=\"auto\">, set the drop down to\u00a0<\/span><b><span data-contrast=\"auto\">Web<\/span><\/b><span data-contrast=\"auto\">\u00a0and set value to\u00a0<\/span><a href=\"https:\/\/localhost:44375\/\"><span data-contrast=\"none\">https:\/\/localhost:44375\/<\/span><\/a><span data-contrast=\"auto\">\u00a0(verify\u00a0<\/span><span data-contrast=\"auto\">later if you have a different URL in your project as SSL then add the new URL here).<\/span><span data-ccp-props=\"{&quot;134233279&quot;:true,&quot;201341983&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:259}\">\u00a0<\/span><\/li>\n<li data-leveltext=\"%2.\" data-font=\"\" data-listid=\"15\" data-aria-posinset=\"3\" data-aria-level=\"2\"><img decoding=\"async\" class=\"alignnone wp-image-4909 size-large\" src=\"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-content\/uploads\/sites\/73\/2020\/06\/1-App-registration-view-in-Azure-Portal-842x1024.png\" alt=\" App registration view in Azure Portal\" width=\"842\" height=\"1024\" \/><\/li>\n<\/ul>\n<p><span class=\"TextRun SCXW66465120 BCX0\" lang=\"EN-CA\" xml:lang=\"EN-CA\" data-contrast=\"auto\"><span class=\"NormalTextRun SCXW66465120 BCX0\">4. Click <\/span><\/span><span class=\"TextRun SCXW66465120 BCX0\" lang=\"EN-CA\" xml:lang=\"EN-CA\" data-contrast=\"auto\"><span class=\"NormalTextRun SCXW66465120 BCX0\">Register<\/span><\/span><span class=\"TextRun SCXW66465120 BCX0\" lang=\"EN-CA\" xml:lang=\"EN-CA\" data-contrast=\"auto\"><span class=\"NormalTextRun SCXW66465120 BCX0\">. Locate your\u00a0<\/span><\/span><span class=\"TextRun SCXW66465120 BCX0\" lang=\"EN-CA\" xml:lang=\"EN-CA\" data-contrast=\"auto\"><span class=\"NormalTextRun SCXW66465120 BCX0\">application (client) ID<\/span><\/span><span class=\"TextRun SCXW66465120 BCX0\" lang=\"EN-CA\" xml:lang=\"EN-CA\" data-contrast=\"auto\"><span class=\"NormalTextRun SCXW66465120 BCX0\">.\u00a0<\/span><\/span><span class=\"TextRun SCXW66465120 BCX0\" lang=\"EN-CA\" xml:lang=\"EN-CA\" data-contrast=\"auto\"><span class=\"NormalTextRun SCXW66465120 BCX0\">You will need to reference this later.<\/span><\/span><span class=\"EOP SCXW66465120 BCX0\" data-ccp-props=\"{&quot;134233279&quot;:true,&quot;201341983&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:259}\">\u00a0<\/span><\/p>\n<p><img decoding=\"async\" class=\"alignnone wp-image-4910 size-large\" src=\"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-content\/uploads\/sites\/73\/2020\/06\/2-Overview-page-for-AAD-app-registration-in-Azure-Portal-1024x816.png\" alt=\"Overview page for AAD app registration in Azure Portal\" width=\"1024\" height=\"816\" \/><\/p>\n<p>5. Under <strong>Manage<\/strong> on the left-hand navigation, select <strong>Authentication<\/strong>. Locate the <strong>Implicit Grant<\/strong> section and enable both <strong>Access tokens<\/strong> and <strong>ID tokens<\/strong>, then click <strong>Save<\/strong>.<\/p>\n<p><img decoding=\"async\" class=\"alignnone wp-image-4911 size-full\" src=\"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-content\/uploads\/sites\/73\/2020\/06\/3-Check-Access-tokens-and-ID-tokens-checkboxes-in-app-registration-view.png\" alt=\"Check Access tokens and ID tokens checkboxes in app registration view\" width=\"853\" height=\"681\" srcset=\"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-content\/uploads\/sites\/73\/2020\/06\/3-Check-Access-tokens-and-ID-tokens-checkboxes-in-app-registration-view.png 853w, https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-content\/uploads\/sites\/73\/2020\/06\/3-Check-Access-tokens-and-ID-tokens-checkboxes-in-app-registration-view-300x240.png 300w, https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-content\/uploads\/sites\/73\/2020\/06\/3-Check-Access-tokens-and-ID-tokens-checkboxes-in-app-registration-view-768x613.png 768w\" sizes=\"(max-width: 853px) 100vw, 853px\" \/><\/p>\n<ul>\n<li>Under <strong>Manage<\/strong> on the left-hand navigation, select <strong>Certificates &amp; Secrets<\/strong>. Under <strong>Client secrets<\/strong>, click <strong>+New client secret<\/strong>. On the <strong>Add a client secret<\/strong> pop-up, give a <strong>description<\/strong> as \u2018MGT-Proxy-Provider-App-Secret\u2019 or your own description. Select the <strong>Expires<\/strong> duration and click <strong>Add<\/strong>.<\/li>\n<li>Copy the Secret value for later use.<\/li>\n<\/ul>\n<p><strong>Start coding<\/strong><\/p>\n<p>In our application code, we will need to first setup the application to work with Azure AD based authentication and call Microsoft Graph API using user claims.<\/p>\n<p>Once you completed the module, you will have the base ready, which we will modify as shown below to add Microsoft Graph Toolkit components and our proxy provider.<\/p>\n<ol>\n<li>Under App_Start folder, add the following class. The purpose of adding this class is to make our Proxy API routed.<\/li>\n<\/ol>\n<pre class=\"lang: decode:true\">public static class WebApiConfig {\n\u00a0\u00a0\u00a0 public static void Register(HttpConfiguration config)\n\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 config.MapHttpAttributeRoutes();\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 config.Routes.MapHttpRoute(\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 name: \"DefaultApi\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \u00a0routeTemplate: \"api\/{controller}\/{id}\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 defaults: new { id = RouteParameter.Optional }\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0);\n \u00a0\u00a0\u00a0}\n}<\/pre>\n<ol start=\"2\">\n<li>Under App_Start folder, in the Startup.Auth.cs file, replace the existing function with the following function. The highlighted change is to use the CachedUser class to transpose the Microsoft Graph User object.<\/li>\n<\/ol>\n<pre class=\"lang: decode:true\">private async Task OnAuthorizationCodeReceivedAsync(AuthorizationCodeReceivedNotification notification) {\n\u00a0\u00a0\u00a0 var idClient = ConfidentialClientApplicationBuilder.Create(appId)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .WithRedirectUri(redirectUri)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .WithClientSecret(appSecret)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .Build();\n\u00a0\u00a0\u00a0 var signedInUser = new ClaimsPrincipal(notification.AuthenticationTicket.Identity);\n\u00a0\u00a0\u00a0 var tokenStore = new SessionTokenStore(idClient.UserTokenCache, HttpContext.Current, signedInUser);\n    try\u00a0\u00a0 \n    {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 string[] scopes = graphScopes.Split(' ');\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 var result = await idClient.AcquireTokenByAuthorizationCode(scopes, notification.Code).ExecuteAsync();\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 var userDetails = await GraphHelper.GetUserDetailsAsync(result.AccessToken);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 var cachedUser = new CachedUser()\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 DisplayName = userDetails.DisplayName,\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Email = string.IsNullOrEmpty(userDetails.Mail) ?\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 userDetails.UserPrincipalName : userDetails.Mail,\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Avatar = string.Empty\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 };\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 tokenStore.SaveUserDetails(cachedUser);\n\u00a0\u00a0\u00a0 }\n\u00a0\u00a0\u00a0 catch (MsalException ex)\n\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 string message = \"AcquireTokenByAuthorizationCodeAsync threw an exception\";\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 notification.HandleResponse();\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 notification.Response.Redirect($\"\/Home\/Error?message={message}&amp;debug={ex.Message}\");\n\u00a0\u00a0\u00a0 }\n\u00a0\u00a0\u00a0 catch (Microsoft.Graph.ServiceException ex)\n\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 string message = \"GetUserDetailsAsync threw an exception\";\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 notification.HandleResponse();\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 notification.Response.Redirect($\"\/Home\/Error?message={message}&amp;debug={ex.Message}\");\n\u00a0\u00a0\u00a0 }\n}<\/pre>\n<ol start=\"3\">\n<li>Under Controllers folder, update the CalendarController class as below. This is to make sure we are using only the default Microsoft Graph Toolkit component for calendar events.<\/li>\n<\/ol>\n<pre class=\"lang: decode:true\">public class CalendarController : BaseController \u00a0\u00a0 \n{\n\u00a0\u00a0\u00a0 \/\/ GET: Calendar\n\u00a0\u00a0\u00a0 [Authorize]\n\u00a0\u00a0\u00a0 public ActionResult Index()\n\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return View();\n\u00a0\u00a0\u00a0 }\n}<\/pre>\n<p>4. Under Controller folder, add the GraphProxyController class as below. This class manages all HTTP calls and perform the authentication and return the result back to calling view.<\/p>\n<pre class=\"lang: decode:true\">[RoutePrefix(\"api\/GraphProxy\")]\npublic class GraphProxyController : ApiController {\n\u00a0\u00a0\u00a0 [HttpGet]\n\u00a0\u00a0\u00a0 [Route(\"{*all}\")]\n\u00a0\u00a0\u00a0 public async Task&lt;HttpResponseMessage&gt; GetAsync(string all)\n\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return await ProcessRequestAsync(\"GET\", all, null).ConfigureAwait(false);\n\u00a0\u00a0\u00a0 }\n\n \u00a0\u00a0 private async Task&lt;HttpResponseMessage&gt; ProcessRequestAsync(string method, string all, object content)\n\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 var graphClient = GraphHelper.GetAuthenticatedClient();\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 var request = new BaseRequest(GetURL(all, graphClient), graphClient, null)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Method = method,\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 ContentType = HttpContext.Current.Request.ContentType,\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 };\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 var neededHeaders = Request.Headers.Where(h =&gt; h.Key.ToLower() == \"if-match\").ToList();\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (neededHeaders.Count() &gt; 0)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 foreach (var header in neededHeaders)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 request.Headers.Add(new HeaderOption(header.Key, string.Join(\",\", header.Value)));\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 var contentType = \"application\/json\";\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 try\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 using (var response = await request.SendRequestAsync(content, CancellationToken.None, HttpCompletionOption.ResponseContentRead).ConfigureAwait(false))\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 response.Content.Headers.TryGetValues(\"content-type\", out var contentTypes);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 contentType = contentTypes?.FirstOrDefault() ?? contentType;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 var byteArrayContent = await response.Content.ReadAsByteArrayAsync().ConfigureAwait(false);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return ReturnHttpResponseMessage(HttpStatusCode.OK, contentType, new ByteArrayContent(byteArrayContent));\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 catch (ServiceException ex)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return ReturnHttpResponseMessage(ex.StatusCode, contentType, new StringContent(ex.Error.ToString()));\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\n\u00a0\u00a0\u00a0 }\n\n\u00a0\u00a0\u00a0 private static HttpResponseMessage ReturnHttpResponseMessage(HttpStatusCode httpStatusCode, string contentType, HttpContent httpContent)\n\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 var httpResponseMessage = new HttpResponseMessage(httpStatusCode)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\n\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Content = httpContent\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 };\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 try\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 httpResponseMessage.Content.Headers.ContentType = new MediaTypeHeaderValue(contentType);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 catch\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 httpResponseMessage.Content.Headers.ContentType = new MediaTypeHeaderValue(\"application\/json\");\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return httpResponseMessage;\n\u00a0\u00a0\u00a0 }\n\n\u00a0\u00a0\u00a0 private string GetURL(string all, GraphServiceClient graphClient)\n\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 var urlStringBuilder = new StringBuilder();\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 var qs = HttpContext.Current.Request.QueryString;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (qs.Count &gt; 0)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 foreach (string key in qs.Keys)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (string.IsNullOrWhiteSpace(key)) continue;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 string[] values = qs.GetValues(key);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (values == null) continue;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 foreach (string value in values)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0urlStringBuilder.Append(urlStringBuilder.Length == 0 ? \"?\" : \"&amp;\");\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0urlStringBuilder.AppendFormat(\"{0}={1}\", Uri.EscapeDataString(key), Uri.EscapeDataString(value));\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 urlStringBuilder.Insert(0, \"?\");\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0urlStringBuilder.Insert(0, $\"{GetBaseUrlWithoutVersion(graphClient)}\/{all}\");\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return urlStringBuilder.ToString();\n\u00a0\u00a0\u00a0\u00a0}\n\n\u00a0\u00a0\u00a0 private string GetBaseUrlWithoutVersion(GraphServiceClient graphClient)\n\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 var baseUrl = graphClient.BaseUrl;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 var index = baseUrl.LastIndexOf('\/');\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return baseUrl.Substring(0, index);\n\u00a0\u00a0\u00a0 }\n}<\/pre>\n<p>5. Under Helpers folder, in the GraphHelper class to function with the following function. We are using the built-in Microsoft.Graph.User object in place of the CachedUser object. \u2013<\/p>\n<p>public static async Task&lt;Microsoft.Graph.User&gt; GetUserDetailsAsync(string accessToken)<\/p>\n<pre class=\"lang: decode:true\">{\n \u00a0\u00a0\u00a0var graphClient = new GraphServiceClient(\n\u00a0 \u00a0\u00a0\u00a0\u00a0 new DelegateAuthenticationProvider(\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0async (requestMessage) =&gt;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0{\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0    requestMessage.Headers.Authorization =\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0   new AuthenticationHeaderValue(\"Bearer\", accessToken);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}));\n\u00a0\u00a0\u00a0 return await graphClient.Me.Request().GetAsync();\n}\n<\/pre>\n<p>6. Under Models folder, delete the CachedUser.cs. We do not require the CachedUser object as model. We are using the built-in Microsoft.Graph.User object.<\/p>\n<p>7. Under TokenStorage folder, in SessionTokenStore.cs file, he following class. We will create a CachedUser class here and use it for storing the user in cache.<\/p>\n<pre class=\"lang: decode:true\">public class CachedUser {\n\u00a0\u00a0\u00a0\u00a0public string DisplayName { get; set; }\n\u00a0\u00a0\u00a0 public string Email { get; set; }\n\u00a0\u00a0\u00a0 public string Avatar { get; set; }\n}<\/pre>\n<p>So far, we have added backend code to make our Proxy API so that an MGT component can call it.<\/p>\n<p>Now, let\u2019s make changes to the UI to add a MGT component and call proxy API.<\/p>\n<p>1. Edit code file located at path as\u00a0 Views \u00e0 Calendar \u00e0 Index.cshtml, update the file content as below. This will show signed in user calendar items.<\/p>\n<pre class=\"lang: decode:true\">&lt;h1&gt;Calendar&lt;\/h1&gt;\n&lt;mgt-agenda group-by-day&gt;&lt;\/mgt-agenda&gt;<\/pre>\n<p>2. Edit code file located at path as\u00a0 Views \u00e0 Home \u00e0 Index.cshtml, update the file content as below. This will let you sign-in and allow you to do hover on each person card returned.<\/p>\n<pre class=\"lang: decode:true\">@{\n    ViewBag.Current = \"Home\";\n}\n\n&lt;div class=\"jumbotron\"&gt;\n\u00a0\u00a0\u00a0 &lt;h1&gt;ASP.NET Microsoft Graph Toolkit Tutorial&lt;\/h1&gt;\n\u00a0\u00a0\u00a0 &lt;p class=\"lead\"&gt;This sample app shows how to use the Microsoft Graph Toolkit with ASP.NET&lt;\/p&gt;\n\u00a0\u00a0\u00a0 @if (Request.IsAuthenticated)\n\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;h4&gt;Welcome @ViewBag.User.DisplayName!&lt;\/h4&gt;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;p&gt;Use the navigation bar at the top of the page to get started.&lt;\/p&gt;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;h4&gt;People&lt;\/h4&gt;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;p&gt;These are the people you work with the most&lt;\/p&gt;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;mgt-people&gt;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;template&gt;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;div data-for=\"person in people\"&gt;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;mgt-person person-details=\"{{person}}\" view=\"twolines\" fetch-image person-card=\"hover\"&gt;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;\/div&gt;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;\/template&gt;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;\/mgt-people&gt;\n\u00a0\u00a0\u00a0 }\n\u00a0\u00a0\u00a0 else\n\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 @Html.ActionLink(\"Click here to sign in\", \"SignIn\", \"Account\", new { area = \"\" }, new { @class = \"btn btn-primary btn-large\" })\n\u00a0\u00a0\u00a0 }\n&lt;\/div&gt;<\/pre>\n<p>3. And it last, we need to load the MGT JavaScript and proxy settings so that we can execute it as required. For this edit file in path as Views \u00e0 Shared \u00e0 _Layout.cshtml, we need to update file content as below \u2013<\/p>\n<ul>\n<li>In the head section, add the following script \u2013<\/li>\n<\/ul>\n<pre class=\"lang: decode:true \">&lt;script src=\"https:\/\/unpkg.com\/@Html.Raw(\"@\")microsoft\/mgt\/dist\/bundle\/mgt-loader.js\"&gt;&lt;\/script&gt;\n&lt;script&gt;\n\u00a0\u00a0\u00a0 const provider = new mgt.ProxyProvider(\"\/api\/GraphProxy\");\n\u00a0\u00a0\u00a0 provider.login = () =&gt; window.location.href = '@Url.Action(\"SignIn\", \"Account\")';\n\u00a0\u00a0\u00a0 provider.logout = () =&gt; window.location.href = '@Url.Action(\"SignOut\", \"Account\")';\n\u00a0\u00a0\u00a0 mgt.Providers.globalProvider = provider;\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\n&lt;\/script&gt;\n&lt;style&gt;\n\u00a0\u00a0\u00a0 mgt-login {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 --color: white;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 --padding: 8px;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 --background-color--hover: transparent;\n\u00a0\u00a0\u00a0 }\n&lt;\/style&gt;<\/pre>\n<ul>\n<li>Replace body section as below. This is to show the navigation items once authenticated.<\/li>\n<\/ul>\n<pre class=\"lang: decode:true\">&lt;body&gt;\n\u00a0\u00a0\u00a0 &lt;nav class=\"navbar navbar-expand-md navbar-dark fixed-top bg-dark\"&gt;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;div class=\"container\"&gt;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 @Html.ActionLink(\"ASP.NET Microsoft Graph Toolkit\", \"Index\", \"Home\", new { area = \"\" }, new { @class = \"navbar-brand\" })\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;button class=\"navbar-toggler\" type=\"button\" data-toggle=\"collapse\" data-target=\"#navbarCollapse\"\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 aria-controls=\"navbarCollapse\" aria-expanded=\"false\" aria-label=\"Toggle navigation\"&gt;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;span class=\"navbar-toggler-icon\"&gt;&lt;\/span&gt;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;\/button&gt;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;div class=\"collapse navbar-collapse\" id=\"navbarCollapse\"&gt;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;ul class=\"navbar-nav mr-auto\"&gt;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;li class=\"nav-item\"&gt;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 @Html.ActionLink(\"Home\", \"Index\", \"Home\", new { area = \"\" },\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 new { @class = ViewBag.Current == \"Home\" ? \"nav-link active\" : \"nav-link\" })\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;\/li&gt;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 @if (Request.IsAuthenticated)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;li class=\"nav-item\" data-turbolinks=\"false\"&gt;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 @Html.ActionLink(\"Calendar\", \"Index\", \"Calendar\", new { area = \"\" },\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 new { @class = ViewBag.Current == \"Calendar\" ? \"nav-link active\" : \"nav-link\" })\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;\/li&gt;\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;\/ul&gt;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;ul class=\"navbar-nav justify-content-end\"&gt;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;li class=\"nav-item\"&gt;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;a class=\"nav-link\" href=\"https:\/\/aka.ms\/mgt-docs\" target=\"_blank\"&gt;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;i class=\"fas fa-external-link-alt mr-1\"&gt;&lt;\/i&gt;Docs\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;\/a&gt;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;\/li&gt;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;li class=\"nav-item\"&gt;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;mgt-login&gt;&lt;\/mgt-login&gt;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;\/li&gt;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;\/ul&gt;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;\/div&gt;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;\/div&gt;\n\u00a0\u00a0\u00a0 &lt;\/nav&gt;\n\u00a0\u00a0\u00a0 &lt;main role=\"main\" class=\"container\"&gt;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 @foreach (var alert in alerts)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;div class=\"alert alert-danger\" role=\"alert\"&gt;\n\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;p class=\"mb-3\"&gt;@alert.Message&lt;\/p&gt;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 @if (!string.IsNullOrEmpty(alert.Debug))\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;pre class=\"alert-pre border bg-light p-2\"&gt;&lt;code&gt;@alert.Debug&lt;\/code&gt;&lt;\/pre&gt;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;\/div&gt;\n\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 @RenderBody()\n\u00a0\u00a0\u00a0 &lt;\/main&gt;\n\u00a0\u00a0\u00a0 @Scripts.Render(\"~\/bundles\/jquery\")\n\u00a0\u00a0\u00a0 @Scripts.Render(\"~\/bundles\/bootstrap\")\n\u00a0\u00a0\u00a0 @RenderSection(\"scripts\", required: false)\n&lt;\/body&gt;\n<\/pre>\n<p>Now, we will need the client\/application ID and client secret to be added in the PrivateSettings.config file.<\/p>\n<p>Once done, start the application in debug mode. For first instance, you will get the consent pop up message, once granted, you will be able to see details as below \u2013<\/p>\n<p>Default login page \u2013<\/p>\n<p><img decoding=\"async\" class=\"alignnone wp-image-4912 size-large\" src=\"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-content\/uploads\/sites\/73\/2020\/06\/4-1-1024x276.png\" alt=\"Default login page \" width=\"1024\" height=\"276\" \/><\/p>\n<p>Consent dialog \u2013<\/p>\n<p><img decoding=\"async\" class=\"size-full wp-image-5075 alignnone\" src=\"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-content\/uploads\/sites\/73\/2020\/06\/consent-dialog.jpg\" alt=\"Consent dialog box\" width=\"488\" height=\"800\" srcset=\"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-content\/uploads\/sites\/73\/2020\/06\/consent-dialog.jpg 488w, https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-content\/uploads\/sites\/73\/2020\/06\/consent-dialog-183x300.jpg 183w\" sizes=\"(max-width: 488px) 100vw, 488px\" \/><\/p>\n<p>After Login successful \u2013<\/p>\n<p><img decoding=\"async\" class=\"alignnone wp-image-4965 size-medium\" src=\"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-content\/uploads\/sites\/73\/2020\/06\/asp-tutorial-300x192.jpg\" alt=\"\" width=\"300\" height=\"192\" \/><img decoding=\"async\" class=\"size-full wp-image-5076 alignnone\" src=\"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-content\/uploads\/sites\/73\/2020\/06\/after-login-succesful.jpg\" alt=\"After login successful dialog box\" width=\"800\" height=\"514\" srcset=\"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-content\/uploads\/sites\/73\/2020\/06\/after-login-succesful.jpg 800w, https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-content\/uploads\/sites\/73\/2020\/06\/after-login-succesful-300x193.jpg 300w, https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-content\/uploads\/sites\/73\/2020\/06\/after-login-succesful-768x493.jpg 768w\" sizes=\"(max-width: 800px) 100vw, 800px\" \/><\/p>\n<p>Calendar Page \u2013<\/p>\n<p><img decoding=\"async\" class=\"alignnone wp-image-4915 size-large\" src=\"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-content\/uploads\/sites\/73\/2020\/06\/8-Calendar-page-1024x269.png\" alt=\"Calendar page\" width=\"1024\" height=\"269\" \/><\/p>\n<p>Sign-out option-<\/p>\n<p><img decoding=\"async\" class=\"alignnone wp-image-4916 size-large\" src=\"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-content\/uploads\/sites\/73\/2020\/06\/9-Sign-out-option--1024x223.png\" alt=\"ign-out option-\" width=\"1024\" height=\"223\" \/><\/p>\n<h3>Conclusion<\/h3>\n<p>It took only a few steps to build a ASP.NET MVC App to use Proxy provider for Microsoft Graph Tool kit components to call Microsoft Graph APIs, but we did it!<\/p>\n<p>When you are done with building app, you can publish it on a web server, and anyone can use your application. For ISVs or partners, you can follow application publishing over marketplace guidelines. Stay tuned as we will have some ISV using Microsoft Graph success stories for you next week!<\/p>\n<p>Hopefully, we were able to demonstrate how, by using the Proxy provider, you can build your own API and use with MGT components. This is just to present as how you can simply use your API to use with Microsoft Graph Toolkit components and with your custom service. That is the power of the Microsoft Graph Toolkit!<\/p>\n<p>You can find the source code for this sample in the <a href=\"https:\/\/github.com\/microsoftgraph\/microsoft-graph-toolkit\/tree\/master\/samples\/proxy-provider-asp-net-mvc\">MGT-Samples<\/a>. This is a MVC app based sample. If you would like to use a .NET Core based, then look at the sample <a href=\"https:\/\/github.com\/microsoftgraph\/microsoft-graph-toolkit\/tree\/master\/samples\/proxy-provider-asp-net-core\">here<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hey\u00a0devs, welcome to day 11\u00a0of the\u00a0Microsoft Graph Toolkit blog series!\u00a0Today we will explore the\u00a0Microsoft Graph Toolkit proxy provider.\u00a0Microsoft Graph Toolkit (MGT) provider enables you to use a proxy API behind the Graph Toolkit components rather than calling the Microsoft Graph API directly.<\/p>\n","protected":false},"author":69076,"featured_media":25159,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[3],"tags":[34],"class_list":["post-4908","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-microsoft-graph","tag-microsoft-graph-toolkit"],"acf":[],"blog_post_summary":"<p>Hey\u00a0devs, welcome to day 11\u00a0of the\u00a0Microsoft Graph Toolkit blog series!\u00a0Today we will explore the\u00a0Microsoft Graph Toolkit proxy provider.\u00a0Microsoft Graph Toolkit (MGT) provider enables you to use a proxy API behind the Graph Toolkit components rather than calling the Microsoft Graph API directly.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/posts\/4908","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/users\/69076"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/comments?post=4908"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/posts\/4908\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/media\/25159"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/media?parent=4908"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/categories?post=4908"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/tags?post=4908"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}