<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Waldek Mastykarz</title>
    <description>The latest articles on Forem by Waldek Mastykarz (@waldekmastykarz).</description>
    <link>https://forem.com/waldekmastykarz</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F426764%2F3a47c96e-d878-40ac-b1cc-1cbbccfaffec.jpeg</url>
      <title>Forem: Waldek Mastykarz</title>
      <link>https://forem.com/waldekmastykarz</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/waldekmastykarz"/>
    <language>en</language>
    <item>
      <title>Join us for Hack Together: Microsoft Graph and .NET</title>
      <dc:creator>Waldek Mastykarz</dc:creator>
      <pubDate>Fri, 24 Feb 2023 07:10:19 +0000</pubDate>
      <link>https://forem.com/dotnet/join-us-for-hack-together-microsoft-graph-and-net-405n</link>
      <guid>https://forem.com/dotnet/join-us-for-hack-together-microsoft-graph-and-net-405n</guid>
      <description>&lt;p&gt;&lt;strong&gt;Join us for Hack Together, our virtual hackathon to learn how to build powerful apps with Microsoft Graph and .NET&lt;/strong&gt;. If you’re a beginning coder, a student, or an expert looking for an opportunity to learn a new skill, don’t miss this opportunity! &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hack Together is a virtual hackathon to get started building apps with Microsoft Graph and .NET&lt;/strong&gt;. In this hackathon, you will kick-start learning how to build apps with Microsoft Graph – the API to access data and insights from Microsoft 365, and develop apps based on some of the most popular Microsoft Graph scenarios. You’ll also have a chance to win exciting prizes and meet Microsoft Graph and .NET Product Group Leaders, Cloud Advocates, MVPs and Student Ambassadors. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foqzd0or0xycnodktnryk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foqzd0or0xycnodktnryk.png" alt="Image of Hack Together activities" width="480" height="274"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hack Together will run online from March 1-15, 2023. Hear from our speakers – why you should join us. &lt;a href="https://aka.ms/hack-together/register" rel="noopener noreferrer"&gt;Register today&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/2NcaPnob0eU"&gt;
&lt;/iframe&gt;
 &lt;/p&gt;

&lt;h2&gt;
  
  
  🙋 Why join Hack Together and add Microsoft Graph to your skillset?
&lt;/h2&gt;

&lt;p&gt;Millions of people across the globe use Microsoft apps in their personal lives, at school, and at work. Did you know that you can also access data behind the popular Microsoft apps such as Microsoft Teams, Calendar, Outlook, To-Do, Planner, and more?   &lt;/p&gt;

&lt;p&gt;Microsoft Graph is the gateway to access data and intelligence across Microsoft 365. It exposes hundreds of datasets to developers. Not only can you access the data, but also you can build your own apps on top of Microsoft 365 by accessing the available data with the power of Microsoft Graph. Here are a few examples of apps that you could build with Microsoft Graph: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;See what your colleagues are working on &lt;/li&gt;
&lt;li&gt;Organize your day with a quick overview of upcoming meetings &lt;/li&gt;
&lt;li&gt;Get your tasks every morning at 9 am &lt;/li&gt;
&lt;li&gt;Find meeting time and schedule a meeting for multiple attendees &lt;/li&gt;
&lt;li&gt;Stay up to date with what’s going on around you through a personalized dashboard &lt;/li&gt;
&lt;li&gt;Get a summary of unread messages &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Imagine all the other scenarios you can build on the Microsoft ecosystem to boost productivity, collaboration, education, people, workplace intelligence, and more!  &lt;/p&gt;

&lt;p&gt;Learning how to build apps with Microsoft Graph is a critical skill to work across Microsoft technologies. Throughout Hack Together, we will help you upskill with Microsoft technologies and ecosystem by learning and building apps with Microsoft Graph.  &lt;/p&gt;

&lt;h2&gt;
  
  
  🦒 Prerequisites to participate in Hack Together
&lt;/h2&gt;

&lt;p&gt;During Hack Together, you’ll learn hands-on how to build .NET apps connected to Microsoft Graph. Here’s the list of a &lt;a href="https://github.com/microsoft/hack-together/tree/main#00---pre-requisites" rel="noopener noreferrer"&gt;few things you’ll need to get started&lt;/a&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  ⚙️ How does Hack Together work?
&lt;/h2&gt;

&lt;p&gt;Hack Together includes self-paced learning, connecting with experts and other participants on GitHub Discussions, and attending live sessions. &lt;/p&gt;

&lt;h3&gt;
  
  
  Live sessions 📺
&lt;/h3&gt;

&lt;p&gt;We’ll open the virtual hackathon on March 1, 2023, with a keynote by &lt;strong&gt;Yina Arenas&lt;/strong&gt;, Head of Product for Microsoft Graph and &lt;strong&gt;Scott Hanselman&lt;/strong&gt;, Partner Program Manager in Developer Division. Join us live to learn why .NET and Microsoft Graph are a great combination for building apps for work and school. &lt;/p&gt;

&lt;p&gt;Throughout Hack Together, we’ll stream more sessions by Microsoft experts and MVPs to show you what you can achieve with Microsoft Graph and .NET. We’ll close by announcing the winners of the hackathon. &lt;/p&gt;

&lt;p&gt;For the schedule and more information about the sessions, check out our &lt;a href="https://aka.ms/hack-together" rel="noopener noreferrer"&gt;GitHub repo&lt;/a&gt;. &lt;/p&gt;

&lt;h3&gt;
  
  
  Self-paced learning 📚
&lt;/h3&gt;

&lt;p&gt;If you’re just starting, Microsoft Graph and .NET might feel overwhelming. We hear you! Use our self-paced learning materials to learn about Microsoft Graph and .NET. &lt;/p&gt;

&lt;h3&gt;
  
  
  Connect with experts on GitHub Discussions 💬
&lt;/h3&gt;

&lt;p&gt;An answer is just one question away. When you need help, don’t hesitate to ask questions in the GitHub Discussion for this hack. Our experts will always be there to help you and answer your questions. &lt;/p&gt;

&lt;h2&gt;
  
  
  🦾 What’s the hack?
&lt;/h2&gt;

&lt;p&gt;During the hackathon you’ll be working on your own .NET app connected to Microsoft Graph. Any type of app qualifies as long as it’s built on .NET and connected to Microsoft Graph. If you need inspiration, check out the list of &lt;a href="https://github.com/microsoft/hack-together/blob/main/top-scenarios.md" rel="noopener noreferrer"&gt;top Microsoft Graph scenarios&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;When you’re ready, submit your app in the hackathon’s repo before March 15, 2023, so we can check it out. All hackathon participants who submit an app will receive a digital badge. On addition, the winners selected will receive the following exciting prizes (up to 4 individuals if submitting as a team, prizes for each person on the team): &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;🥇 First prize winner:

&lt;ul&gt;
&lt;li&gt;an Xbox,&lt;/li&gt;
&lt;li&gt;$200 gift card&lt;/li&gt;
&lt;li&gt;$100 Azure credit&lt;/li&gt;
&lt;li&gt;a digital Credly badge&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;🥈 Second prize winner:

&lt;ul&gt;
&lt;li&gt;$200 gift card&lt;/li&gt;
&lt;li&gt;$100 Azure credit&lt;/li&gt;
&lt;li&gt;a digital Credly badge&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;🥉 Third prize winner:

&lt;ul&gt;
&lt;li&gt;$100 Azure credit&lt;/li&gt;
&lt;li&gt;a digital Credly badge&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can participate by yourself or as a team with your colleagues!&lt;/p&gt;

&lt;p&gt;We’re so excited for you to Hack Together with us and build cool .NET apps with Microsoft Graph. Share your journey throughout the hack on social with the #HackTogether hashtag. Let us know if you have any questions. Our team is always here to help you! &lt;a href="https://twitter.com/Microsoft365Dev" rel="noopener noreferrer"&gt;Follow us on Twitter&lt;/a&gt; to stay up to date on our latest news and announcements. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://aka.ms/hack-together/register" rel="noopener noreferrer"&gt;Register today&lt;/a&gt; and we look forward to meeting you at #HackTogether!&lt;/p&gt;

</description>
      <category>fintech</category>
      <category>finance</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Will your app fail when throttled?</title>
      <dc:creator>Waldek Mastykarz</dc:creator>
      <pubDate>Mon, 12 Dec 2022 09:33:01 +0000</pubDate>
      <link>https://forem.com/waldekmastykarz/will-your-app-fail-when-throttled-2fbm</link>
      <guid>https://forem.com/waldekmastykarz/will-your-app-fail-when-throttled-2fbm</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tsXwBS3A--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.mastykarz.nl/assets/images/2022/12/banner-proxy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tsXwBS3A--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.mastykarz.nl/assets/images/2022/12/banner-proxy.png" alt="#66 Will your app fail when throttled?" width="880" height="464"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On a tenant of one, your app never fails. Calling Microsoft Graph and other APIs on Microsoft 365 &lt;em&gt;just works&lt;/em&gt;. But when it gets used at scale in production, only then you get to see if you built it correctly.&lt;/p&gt;

&lt;p&gt;When you build a great application, and it gets widely adopted, it's used a lot. Depending on the size of your organization, your app might be used by hundreds or thousands of simultaneous users, issuing even more requests to Microsoft Graph and other APIs. Microsoft Graph can handle a lot, but even it has its limits, and when you reach them, by calling Graph APIs too often, instead of a response with data, you'll get errors like &lt;code&gt;429 Too Many Requests&lt;/code&gt;. &lt;strong&gt;You're throttled&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Throttling is temporary.&lt;/strong&gt; It's a mechanism to help servers resume regular service operation. By instructing clients to back off for a bit, servers hosting cloud APIs get a chance to get back to normal operation. That's the good news. The bad news is, that, &lt;strong&gt;unless you use an SDK that does it for you, you need to handle throttling yourself.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The problem with throttling is that it's elusive. It occurs only in certain conditions. This makes it really hard to test how your app will react when throttled: &lt;strong&gt;will it back off and wait as instructed, or will it break with an exception&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;This is exactly why we built the &lt;a href="https://github.com/microsoftgraph/msgraph-developer-proxy"&gt;Microsoft Graph Developer Proxy&lt;/a&gt;: a tool to help you &lt;strong&gt;test how your apps respond to API errors&lt;/strong&gt;. Seeing is believing for a reason. With the Graph Developer Proxy, you no longer need to hope for the best. You can verify, even on your tenant of one, how your app will react when suddenly Graph APIs will return errors.&lt;/p&gt;

&lt;p&gt;🙋‍♂️ &lt;a href="https://github.com/microsoftgraph/msgraph-developer-proxy"&gt;Download the Graph Developer Proxy&lt;/a&gt;, test your apps, and I'm looking forward to hearing what you learned.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;PS. You can use Microsoft Graph Developer Proxy with any type of app: client-side apps running in the browser or back-end services running on a server.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>microsoftgraph</category>
      <category>microsoft365</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Find a meeting time and schedule a meeting on Microsoft 365</title>
      <dc:creator>Waldek Mastykarz</dc:creator>
      <pubDate>Tue, 01 Nov 2022 07:44:59 +0000</pubDate>
      <link>https://forem.com/waldekmastykarz/find-a-meeting-time-and-schedule-a-meeting-on-microsoft-365-5ci</link>
      <guid>https://forem.com/waldekmastykarz/find-a-meeting-time-and-schedule-a-meeting-on-microsoft-365-5ci</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--l7kAy9bi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.mastykarz.nl/assets/images/2022/10/find-meeting-time-banner.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--l7kAy9bi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.mastykarz.nl/assets/images/2022/10/find-meeting-time-banner.png" alt="Find a meeting time and schedule a meeting on Microsoft 365" width="880" height="616"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Many work apps need the ability to schedule a meeting with others in their organization. Here's how to do it for apps connected to Microsoft 365.&lt;/p&gt;

&lt;h2&gt;
  
  
  Work apps need work data
&lt;/h2&gt;

&lt;p&gt;Work apps serve a specific purpose: they help you track projects, follow orders or manage resources. But rarely do they contain all the information that users need to complete their work. Typically, information about people, their calendars, or communication is stored elsewhere, like in Microsoft 365. And that's a shame because completing a task requires users to switch between different apps, which is detrimental to their productivity. Unless of course, you bring work data into your work app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Find a meeting time and schedule a meeting on Microsoft 365
&lt;/h2&gt;

&lt;p&gt;A common scenario for work apps is to schedule a meeting with others in the organization. While it sounds trivial, the app must be able to access attendees' calendars, find a suitable meeting time and schedule the meeting. And that's where Microsoft Graph comes in.&lt;/p&gt;

&lt;p&gt;Recently I published an article on freeCodeCamp that shows you &lt;a href="https://www.freecodecamp.org/news/find-meeting-time-schedule-meeting-microsoft-365/"&gt;how to build an app connected to Microsoft 365 that can find a meeting time and schedule a meeting&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sWKviVdm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.mastykarz.nl/assets/images/2022/10/find-meeting-time-graph-mgt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sWKviVdm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.mastykarz.nl/assets/images/2022/10/find-meeting-time-graph-mgt.png" alt="Custom web app for finding a meeting time with attendees on Microsoft 365 and scheduling a meeting" width="880" height="969"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The app shows you how to make the best use of features available in the Microsoft Graph Toolkit and Microsoft Graph to build a UI that you could integrate with another app.&lt;/p&gt;

&lt;p&gt;Check it out, and I'm looking forward to hearing what you think!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>microsoftgraph</category>
      <category>webdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Show upcoming meetings for a Microsoft 365 user with Microsoft Graph Toolkit</title>
      <dc:creator>Waldek Mastykarz</dc:creator>
      <pubDate>Mon, 31 Oct 2022 08:58:59 +0000</pubDate>
      <link>https://forem.com/waldekmastykarz/show-upcoming-meetings-for-a-microsoft-365-user-with-microsoft-graph-toolkit-md9</link>
      <guid>https://forem.com/waldekmastykarz/show-upcoming-meetings-for-a-microsoft-365-user-with-microsoft-graph-toolkit-md9</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--N_zMWaig--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.mastykarz.nl/assets/images/2022/10/upcoming-meetings-graph-mgt-banner.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--N_zMWaig--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.mastykarz.nl/assets/images/2022/10/upcoming-meetings-graph-mgt-banner.png" alt="Show upcoming meetings for a Microsoft 365 user with Microsoft Graph Toolkit" width="880" height="585"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Recently, I showed you how you can build in under 10 minutes a simple personal assistant that shows users meetings they have left for the day. Here's an even easier way to do it using the Microsoft Graph Toolkit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Show upcoming meetings for a Microsoft 365 user
&lt;/h2&gt;

&lt;p&gt;Showing upcoming meetings is a common scenario when integrating Microsoft 365 in work applications. Using &lt;a href="https://developer.microsoft.com/graph?WT.mc_id=m365-80553-wmastyka"&gt;Microsoft Graph&lt;/a&gt;, your app can connect to Microsoft 365 and access a user's calendar. By building a specific query, you can retrieve meetings between now and the end of the day.&lt;/p&gt;

&lt;p&gt;Recently, I walked you step by step &lt;a href="https://www.freecodecamp.org/news/how-to-show-upcoming-meetings-for-a-microsoft-365-user/"&gt;how to complete this scenario&lt;/a&gt; in under 10 minutes using the Microsoft Graph JavaScript SDK. But there's an even easier way to do it using the Microsoft Graph Toolkit.&lt;/p&gt;

&lt;h2&gt;
  
  
  The easiest way to connect to Microsoft 365
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://learn.microsoft.com/graph/toolkit/overview?WT.mc_id=m365-80553-wmastyka"&gt;Microsoft Graph Toolkit&lt;/a&gt; (MGT) is a set of components and authentication providers connected to Microsoft 365. MGT takes away the complexity of implementing authentication, loading data from Microsoft Graph, and showing it in your app. And if anything goes wrong, it also properly handles exceptions. Microsoft Graph Toolkit's components are highly customizable so that you adjust them to your app.&lt;/p&gt;

&lt;h3&gt;
  
  
  A quick comparison: signing in to your app
&lt;/h3&gt;

&lt;p&gt;To understand the benefits of using Microsoft Graph Toolkit, let's have a look at an example: let users sign in to your app using their Microsoft 365 account.&lt;/p&gt;

&lt;p&gt;Typically, you'd need code similar to the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Upcoming meetings&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://alcdn.msauth.net/browser/2.28.3/js/msal-browser.min.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Upcoming meetings&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"auth"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;scopes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Calendars.Read&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;msalConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;clientId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;021aa7bb-9aaa-4185-92ad-c7b75a7fb9d2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;msalClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;msal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PublicClientApplication&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msalConfig&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;msalClient&lt;/span&gt;
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handleRedirectPromise&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;accounts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;msalClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getAllAccounts&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#auth&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;button&amp;gt;Login&amp;lt;/button&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
              &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#auth button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;login&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#auth&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;button&amp;gt;Logout&amp;lt;/button&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
              &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#auth button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;logout&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nx"&gt;msalClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loginRedirect&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="nx"&gt;scopes&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;logout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nx"&gt;msalClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logoutRedirect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;})();&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In comparison, here's the same functionality built using Microsoft Graph Toolkit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Upcoming meetings&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/@microsoft/mgt@2/dist/bundle/mgt-loader.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Upcoming meetings&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;mgt-msal2-provider&lt;/span&gt; &lt;span class="na"&gt;client-id=&lt;/span&gt;&lt;span class="s"&gt;"021aa7bb-9aaa-4185-92ad-c7b75a7fb9d2"&lt;/span&gt; &lt;span class="na"&gt;scopes=&lt;/span&gt;&lt;span class="s"&gt;"Calendars.Read"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/mgt-msal2-provider&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;mgt-login&amp;gt;&amp;lt;/mgt-login&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See the difference? And we didn't even get to the good part yet: calling Microsoft Graph!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;With Microsoft Graph Toolkit you can focus on building your app and solving problems for your customers. Microsoft Graph Toolkit takes care of the rest.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Show upcoming meetings with Microsoft Graph Toolkit
&lt;/h2&gt;

&lt;p&gt;To give you a more complete comparison, I &lt;a href="https://github.com/waldekmastykarz/graph-mgt-upcomingmeetings"&gt;rebuilt the same scenario using Microsoft Graph Toolkit&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The best way to check out the app is to run the app locally by following the instructions in the README.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NB6ZBNhE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.mastykarz.nl/assets/images/2022/10/upcoming-meetings-graph-mgt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NB6ZBNhE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.mastykarz.nl/assets/images/2022/10/upcoming-meetings-graph-mgt.png" alt="Browser window with a web page showing upcoming meetings for a user" width="880" height="678"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Because retrieving the data using MGT is so simple, I added some extra UI to differentiate between the different states of the app.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://learn.microsoft.com/graph/toolkit/components/agenda?WT.mc_id=m365-80553-wmastyka"&gt;MGT Agenda component&lt;/a&gt;, which I use to show the upcoming meetings offers different &lt;a href="https://learn.microsoft.com/graph/toolkit/components/agenda?WT.mc_id=m365-80553-wmastyka#templates"&gt;templates&lt;/a&gt; to customize the UI. When loading the data, I show a simple text message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;mgt-agenda&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;data-type=&lt;/span&gt;&lt;span class="s"&gt;"loading"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"loading"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Loading...&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- trimmed for brevity --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/mgt-agenda&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When there's no data to show, I take into account the fact that there might be no data because the user hasn't signed in to the app yet, or that the user might have no upcoming meetings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;mgt-agenda&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;data-type=&lt;/span&gt;&lt;span class="s"&gt;"loading"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"loading"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Loading...&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;data-type=&lt;/span&gt;&lt;span class="s"&gt;"no-data"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"no-data"&lt;/span&gt; &lt;span class="na"&gt;data-if=&lt;/span&gt;&lt;span class="s"&gt;"mgt.Providers.globalProvider.state === mgt.ProviderState.SignedIn"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="c"&gt;&amp;lt;!-- No upcoming meetings --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"no-data"&lt;/span&gt; &lt;span class="na"&gt;data-else&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Sign in to view your upcoming meetings&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/mgt-agenda&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I use for this the &lt;a href="https://learn.microsoft.com/graph/toolkit/customize-components/templates?WT.mc_id=m365-80553-wmastyka#conditional-rendering"&gt;conditional rendering&lt;/a&gt; capability in MGT.&lt;/p&gt;

&lt;p&gt;To show upcoming meetings, for simplicity, I use the default template provided with the Agenda component.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--flEoUYYB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://blog.mastykarz.nl/assets/images/2022/10/upcoming-meetings-mgt.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--flEoUYYB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://blog.mastykarz.nl/assets/images/2022/10/upcoming-meetings-mgt.gif" alt="Animated gif showing signing in to the app with a Microsoft 365 account and viewing upcoming meetings" width="880" height="753"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Microsoft Graph Toolkit is a great way to build apps that connect to Microsoft 365. It takes away the complexity of connecting to Microsoft 365 and provides a set of components that you can use to build your app and bring in the data and insights from Microsoft 365. Because MGT components are highly customizable, you can seamlessly integrate them in your app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/waldekmastykarz/graph-mgt-upcomingmeetings"&gt;Run the sample app locally&lt;/a&gt; and see for yourself how easy it is to build apps that connect to Microsoft 365 using Microsoft Graph Toolkit.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>microsoftgraph</category>
      <category>webdev</category>
      <category>microsoft365</category>
    </item>
    <item>
      <title>Show upcoming meetings for a Microsoft 365 user</title>
      <dc:creator>Waldek Mastykarz</dc:creator>
      <pubDate>Mon, 24 Oct 2022 09:33:00 +0000</pubDate>
      <link>https://forem.com/waldekmastykarz/show-upcoming-meetings-for-a-microsoft-365-user-3379</link>
      <guid>https://forem.com/waldekmastykarz/show-upcoming-meetings-for-a-microsoft-365-user-3379</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Pll0X3v9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.mastykarz.nl/assets/images/2022/10/upcoming-meetings-graph-banner.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Pll0X3v9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.mastykarz.nl/assets/images/2022/10/upcoming-meetings-graph-banner.png" alt="Show upcoming meetings for a Microsoft 365 user" width="880" height="550"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Learn how you can build a simple personal assistant in under 10 minutes that'll show a Microsoft 365 user the meetings they have left for the day.&lt;/p&gt;

&lt;h2&gt;
  
  
  Show upcoming meetings for a Microsoft 365 user
&lt;/h2&gt;

&lt;p&gt;Recently, I published an article on freeCodeCamp that shows you &lt;a href="https://www.freecodecamp.org/news/how-to-show-upcoming-meetings-for-a-microsoft-365-user/"&gt;how you can build in &lt;strong&gt;just 10 minutes&lt;/strong&gt; a simple personal assistant that shows upcoming meetings for the signed-in user&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YZXpnZpM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.mastykarz.nl/assets/images/2022/10/upcoming-meetings-graph.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YZXpnZpM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.mastykarz.nl/assets/images/2022/10/upcoming-meetings-graph.png" alt="Browser window with a web page showing upcoming meetings for a Microsoft 365 user" width="880" height="655"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Showing upcoming meetings is a common scenario when integrating Microsoft 365 in work applications. It shows you how to get information from the user's calendar and check their availability for a particular time slot. And it's also a great way to get started with building apps on Microsoft 365.&lt;/p&gt;

&lt;p&gt;The tutorial shows you the basics of setting up auth in a single-page app and using the Microsoft Graph JavaScript SDK to connect to the Microsoft Graph API. It also demonstrates working with calendar views and formatting dates.&lt;/p&gt;

&lt;p&gt;Give it a try, and I'm looking forward to hearing what you think.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>microsoftgraph</category>
      <category>beginners</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Reference sample: Single Page App connected to Microsoft 365</title>
      <dc:creator>Waldek Mastykarz</dc:creator>
      <pubDate>Thu, 06 Oct 2022 09:19:59 +0000</pubDate>
      <link>https://forem.com/waldekmastykarz/reference-sample-single-page-app-connected-to-microsoft-365-17mp</link>
      <guid>https://forem.com/waldekmastykarz/reference-sample-single-page-app-connected-to-microsoft-365-17mp</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RqK0OWgB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.mastykarz.nl/assets/images/2022/10/banner.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RqK0OWgB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.mastykarz.nl/assets/images/2022/10/banner.png" alt="Reference sample: Single Page App connected to Microsoft 365" width="880" height="547"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When building apps connected to Microsoft 365, before you can bring in data from Microsoft 365, you need to set up authentication. Here's a reference sample of a Single Page App that shows how to do that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Work apps need work data
&lt;/h2&gt;

&lt;p&gt;Microsoft 365 is a popular set of applications that organizations across the world use to facilitate collaboration and communications. It's also a platform that you can use to build apps for work and streamline how people work together.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RTVzKZBH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.mastykarz.nl/assets/images/2021/02/microsoft-365-types-apps.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RTVzKZBH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.mastykarz.nl/assets/images/2021/02/microsoft-365-types-apps.png" alt="Types of apps that you can build on Microsoft 365 grouped into extensions and custom apps" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These apps can show up inside Microsoft 365, bringing information from line of business systems into the apps that people use every day. They can also be standalone web-, desktop-, and mobile apps that combine data and insights from Microsoft 365 with data from other systems.&lt;/p&gt;

&lt;p&gt;No matter which type of app you choose to build, you need to start with connecting to Microsoft 365, which means you need to set up authentication.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reference sample: Single Page App connected to Microsoft 365
&lt;/h2&gt;

&lt;p&gt;Because you can build many types of apps connected to Microsoft 365, there are many ways to set up authentication. And if you're just starting building apps for Microsoft 365, it might not be quite clear for you what it is exactly you need and how to combine the different parts together.&lt;/p&gt;

&lt;p&gt;To help you get started, I built a &lt;a href="https://github.com/waldekmastykarz/js-graph-101"&gt;sample Single Page Application&lt;/a&gt; that shows you how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;setup authentication with Microsoft 365 in a Single Page Application&lt;/li&gt;
&lt;li&gt;let users sign in and -out with their Microsoft 365 accounts to your app&lt;/li&gt;
&lt;li&gt;retrieve data from Microsoft 365 using Microsoft Graph&lt;/li&gt;
&lt;li&gt;register your app with the Microsoft identity platform&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The sample app is built using plain JavaScript, which lets you reuse the code in any JavaScript framework. In the repo, you'll find the app built in two ways, using &lt;a href="https://github.com/waldekmastykarz/js-graph-101/blob/6532d217f3e33304d2e4de18f1d482987818cfd9/index.html"&gt;immediately invoked function expressions (IIFE)&lt;/a&gt; and using &lt;a href="https://github.com/waldekmastykarz/js-graph-101/blob/6532d217f3e33304d2e4de18f1d482987818cfd9/index_esm.html"&gt;ES modules (ESM)&lt;/a&gt;. It's largely a matter of preference which one you choose to use, but I wanted to show you both approaches.&lt;/p&gt;

&lt;p&gt;If you want to see how I built the app step by step, check out my &lt;a href="https://www.freecodecamp.org/news/build-microsoft-365-application-in-10-minutes/"&gt;recent article on freeCodeCamp&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>beginners</category>
      <category>microsoftgraph</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Build your first Microsoft 365 app in 10 minutes</title>
      <dc:creator>Waldek Mastykarz</dc:creator>
      <pubDate>Wed, 05 Oct 2022 09:45:36 +0000</pubDate>
      <link>https://forem.com/waldekmastykarz/build-your-first-microsoft-365-app-in-10-minutes-493i</link>
      <guid>https://forem.com/waldekmastykarz/build-your-first-microsoft-365-app-in-10-minutes-493i</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RqK0OWgB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.mastykarz.nl/assets/images/2022/10/banner.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RqK0OWgB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.mastykarz.nl/assets/images/2022/10/banner.png" alt="Build your first Microsoft 365 app in 10 minutes" width="880" height="547"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Learning something new is often daunting, especially when it's something like developing for a new platform. But that doesn't have to be the case. Let me show you, how you can build your first Microsoft 365 app in just 10 minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building for a platform
&lt;/h2&gt;

&lt;p&gt;Building for a platform isn't trivial. It comes with all kinds of specific knowledge you have to have like what tooling, SDKs, and APIs to use, how to integrate your app, and finally how to package and distribute it. And I haven't even mentioned auth.&lt;/p&gt;

&lt;p&gt;It's a lot to learn, and it's easy to get overwhelmed. The trick is though, that you don't have to learn everything about everything at once. Often, you can start simple and build up from there.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build your first Microsoft 365 app in 10 minutes
&lt;/h2&gt;

&lt;p&gt;Recently, I published an article on freeCodeCamp that shows you &lt;a href="https://www.freecodecamp.org/news/build-microsoft-365-application-in-10-minutes/"&gt;how you can build your first Microsoft 365 app in &lt;strong&gt;just 10 minutes&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--okN9u7NG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.mastykarz.nl/assets/images/2022/10/microsoft-365-app-user-profile-information.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--okN9u7NG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.mastykarz.nl/assets/images/2022/10/microsoft-365-app-user-profile-information.png" alt="Browser window with a web page showing Microsoft 365 user profile information" width="880" height="592"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sure, the app is simple and doesn't do much, but when building it, you'll learn the fundamental concepts of building apps on Microsoft 365. And after these 10 minutes, you'll have a functional app that works and retrieves data from Microsoft 365, and which you can use as a starting point for more complex apps.&lt;/p&gt;

&lt;p&gt;Give it a try, and I'm looking forward to hearing what you think.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>beginners</category>
      <category>webdev</category>
      <category>microsoftgraph</category>
    </item>
    <item>
      <title>Redirect to a custom login page when securing your Angular app with MSAL</title>
      <dc:creator>Waldek Mastykarz</dc:creator>
      <pubDate>Wed, 05 Oct 2022 09:39:53 +0000</pubDate>
      <link>https://forem.com/azure/redirect-to-a-custom-login-page-when-securing-your-angular-app-with-msal-37km</link>
      <guid>https://forem.com/azure/redirect-to-a-custom-login-page-when-securing-your-angular-app-with-msal-37km</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.mastykarz.nl%2Fassets%2Fimages%2F2022%2F01%2Fbanner-angular-aad.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.mastykarz.nl%2Fassets%2Fimages%2F2022%2F01%2Fbanner-angular-aad.png" alt="Redirect to a custom login page when securing your Angular app with MSAL"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Using MSAL Angular and &lt;code&gt;MsalGuard&lt;/code&gt; is the easiest way to secure your Angular app with the Microsoft Identity Platform. But if you want to use a custom login page rather than redirecting users directly to Azure Active Directory, there's one thing you need to consider.&lt;/p&gt;

&lt;h2&gt;
  
  
  Secure your Angular app with the Microsoft Identity Platform
&lt;/h2&gt;

&lt;p&gt;When you build Angular apps for your organization, you likely need to secure them. They shouldn't be available to just anybody, especially when they're accessible over the internet. Instead, people should sign in first, before they're allowed to access the app.&lt;/p&gt;

&lt;p&gt;While you could add a rudimentary user management system to your app, it's rarely a good idea. It has nothing to do with the problem that your app is solving and it's extremely hard to do well. You need to consider managing user accounts, dealing with expired passwords, multi-factor authentication, not to mention more complex things like conditional access. It's not trivial, and like I just mentioned, it has nothing to do with the problem that your app is solving. On top of all that, you require people to create and manage yet another account.&lt;/p&gt;

&lt;p&gt;If your organization uses Microsoft 365, you can use the Microsoft Identity Platform to secure your app. You get all of the user management features for free and your colleagues can use your app with the same account they use to access Outlook or Teams!&lt;/p&gt;

&lt;h2&gt;
  
  
  Secure your Angular app with the Microsoft Identity Platform using MSAL Angular
&lt;/h2&gt;

&lt;p&gt;The easiest way to secure Angular apps with the Microsoft Identity Platform is by using the &lt;a href="https://github.com/AzureAD/microsoft-authentication-library-for-js/tree/dev/lib/msal-angular" rel="noopener noreferrer"&gt;MSAL (Microsoft Authentication Library) Angular&lt;/a&gt; package. This package contains Angular-specific building blocks for implementing MSAL in your app.&lt;/p&gt;

&lt;p&gt;To secure your Angular app using MSAL Angular, you'll need two building blocks: &lt;code&gt;MsalGuard&lt;/code&gt; and the &lt;code&gt;MsalRedirectComponents&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You add &lt;code&gt;MsalGuard&lt;/code&gt; to your routes that require users to sign in. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Routes&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/router&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MsalGuard&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@azure/msal-angular&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app_routes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Routes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;pathMatch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;full&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;redirectTo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/customers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;customers/:id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;preload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="na"&gt;loadChildren&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./customer/customer.module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CustomerModule&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="na"&gt;canActivate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;MsalGuard&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;customers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;loadChildren&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./customers/customers.module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CustomersModule&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="na"&gt;canActivate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;MsalGuard&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;orders&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;preload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="na"&gt;loadChildren&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./orders/orders.module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OrdersModule&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="na"&gt;canActivate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;MsalGuard&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;about&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;loadChildren&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./about/about.module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AboutModule&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;**&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;pathMatch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;full&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;redirectTo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/customers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// catch any unfound routes and redirect to home page&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example all routes except &lt;code&gt;/about&lt;/code&gt; require users to sign in.&lt;/p&gt;

&lt;p&gt;Next, you need to add the &lt;code&gt;MsalRedirectComponent&lt;/code&gt; which handles redirects from the Azure AD login page back to your app. The easiest way to do it is by adding an extra route mapped to the &lt;code&gt;MsalRedirectComponent&lt;/code&gt; and not secured with &lt;code&gt;MsalGuard&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Routes&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/router&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MsalGuard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MsalRedirectComponent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@azure/msal-angular&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app_routes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Routes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;pathMatch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;full&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;redirectTo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/customers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;customers/:id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;preload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="na"&gt;loadChildren&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./customer/customer.module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CustomerModule&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="na"&gt;canActivate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;MsalGuard&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;customers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;loadChildren&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./customers/customers.module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CustomersModule&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="na"&gt;canActivate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;MsalGuard&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;orders&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;preload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="na"&gt;loadChildren&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./orders/orders.module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OrdersModule&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="na"&gt;canActivate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;MsalGuard&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;about&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;loadChildren&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./about/about.module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AboutModule&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auth&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MsalRedirectComponent&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;**&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;pathMatch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;full&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;redirectTo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/customers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// catch any unfound routes and redirect to home page&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this configuration in place, if the user didn't sign in and they try to navigate to a route with the &lt;code&gt;MsalGuard&lt;/code&gt;, &lt;code&gt;MsalGuard&lt;/code&gt; will redirect them to the Azure AD login page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.mastykarz.nl%2Fassets%2Fimages%2F2022%2F01%2Fangular-aad-msalguard.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.mastykarz.nl%2Fassets%2Fimages%2F2022%2F01%2Fangular-aad-msalguard.png" alt="Three blocks that illustrate the user flow with MsalGuard: accessing a secured route, redirecting to the Azure AD login page and redirecting page to the originally requested route"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is all you need to do to secure your Angular app. But rather than redirecting people directly to Azure AD, you might want to show them a custom page first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Redirect to a custom login page before redirecting users to Azure AD
&lt;/h2&gt;

&lt;p&gt;In the previous example, when users tried to open a route secured with the &lt;code&gt;MsalGuard&lt;/code&gt;, they were automatically redirected to the Azure AD login page. After signing in with their work account, they were redirected back to the route they requested initially. While this flow does its job, some might argue that it's not quite user-friendly. One moment people are in your app, and the other they're in Azure AD, without any additional information. To improve it, you might want to put a custom login page in between with some additional information on it and a login button that people use to start the login flow:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.mastykarz.nl%2Fassets%2Fimages%2F2022%2F01%2Fangular-aad-custom-guard.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.mastykarz.nl%2Fassets%2Fimages%2F2022%2F01%2Fangular-aad-custom-guard.png" alt="Four blocks that illustrate the user flow: accessing a secured route, redirecting to a custom login page, navigating to the Azure AD login page and redirecting page to the originally requested route"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your first idea to implement it would be to replace &lt;code&gt;MsalGuard&lt;/code&gt; with a custom guard that checks if the user is signed in and redirect to the login page if they're not:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Injectable&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ActivatedRouteSnapshot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;CanActivate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;RouterStateSnapshot&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/router&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MsalBroadcastService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MsalService&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@azure/msal-angular&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;InteractionStatus&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@azure/msal-browser&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;switchMap&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rxjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AuthService&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../services/auth.service&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;providedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CanActivateGuard&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;CanActivate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;msalService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MsalService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;authService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AuthService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;msalBroadcastService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MsalBroadcastService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;canActivate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ActivatedRouteSnapshot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;RouterStateSnapshot&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;msalBroadcastService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;inProgress$&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;InteractionStatus&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;InteractionStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;None&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="nf"&gt;switchMap&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;msalService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAllAccounts&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;

          &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;redirectUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;navigate&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The custom guard subscribes to events raised by the MSAL broadcast service and checks if a user account is available in the MSAL service, which indicates that the user has signed in.&lt;/p&gt;

&lt;p&gt;You'd update your route definitions to use your custom guard instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Routes&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/router&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;CanActivateGuard&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./core/guards/can-activate.guard&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MsalRedirectComponent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@azure/msal-angular&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app_routes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Routes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;pathMatch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;full&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;redirectTo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/customers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;customers/:id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;preload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="na"&gt;loadChildren&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./customer/customer.module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CustomerModule&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="na"&gt;canActivate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;CanActivateGuard&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;customers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;loadChildren&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./customers/customers.module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CustomersModule&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="na"&gt;canActivate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;CanActivateGuard&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;orders&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;preload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="na"&gt;loadChildren&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./orders/orders.module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OrdersModule&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="na"&gt;canActivate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;CanActivateGuard&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;about&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;loadChildren&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./about/about.module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AboutModule&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auth&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MsalRedirectComponent&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;**&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;pathMatch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;full&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;redirectTo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/customers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// catch any unfound routes and redirect to home page&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unfortunately, this setup doesn't work quite as you would've thought. If people tried to access a route that requires them to be signed in, they would get redirected to the login page as expected. After clicking the login button, they'd be redirected to the Azure AD login page. But after signing in with their work, when they're redirected back to your app, they wouldn't be signed in!&lt;/p&gt;

&lt;p&gt;The reason for that is, that it's not the &lt;code&gt;MsalRedirectComponent&lt;/code&gt; that's responsible for processing the response from Azure AD and signing the user into your app. It's the &lt;code&gt;MsalGuard&lt;/code&gt; that does that, and since we've removed it, our app considers the authentication is still in progress. So how to solve it?&lt;/p&gt;

&lt;h2&gt;
  
  
  Combine &lt;code&gt;MsalGuard&lt;/code&gt; with a custom guard
&lt;/h2&gt;

&lt;p&gt;To redirect users to a custom login page and properly handle responses from Azure AD with the &lt;strong&gt;minimal amount of code&lt;/strong&gt; , you need to use both your custom guard and the &lt;code&gt;MsalGuard&lt;/code&gt;. Your custom guard will handle redirecting users to the login page, while &lt;code&gt;MsalGuard&lt;/code&gt; will handle processing redirects from Azure AD and registering users as signed in with your app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Routes&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/router&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;CanActivateGuard&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./core/guards/can-activate.guard&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MsalGuard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MsalRedirectComponent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@azure/msal-angular&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app_routes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Routes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;pathMatch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;full&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;redirectTo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/customers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;customers/:id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;preload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="na"&gt;loadChildren&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./customer/customer.module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CustomerModule&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="na"&gt;canActivate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;CanActivateGuard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MsalGuard&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;customers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;loadChildren&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./customers/customers.module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CustomersModule&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="na"&gt;canActivate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;CanActivateGuard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MsalGuard&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;orders&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;preload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="na"&gt;loadChildren&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./orders/orders.module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OrdersModule&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="na"&gt;canActivate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;CanActivateGuard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MsalGuard&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;about&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;loadChildren&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./about/about.module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AboutModule&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auth&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MsalRedirectComponent&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;**&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;pathMatch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;full&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;redirectTo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/customers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// catch any unfound routes and redirect to home page&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With both guards in place, your Angular app will offer users a better user experience clearly managing their expectations. And you'll be able to do it without having to re-implement any code that's already a part of MSAL Angular.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Using MSAL Angular is the easiest way to secure Angular apps with the Microsoft Identity Platform. Using the &lt;code&gt;MsalGuard&lt;/code&gt; and &lt;code&gt;MsalRedirectComponent&lt;/code&gt; you can specify which routes require users to sign in. By adding a custom guard, you can improve the user experience by redirecting users to a custom login page with additional information, before redirecting them directly to the Azure AD login page.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Big thanks to my colleague &lt;a href="https://github.com/manekinekko" rel="noopener noreferrer"&gt;Wassim Chegham&lt;/a&gt; for helping me figure it out. The code in this article is from a &lt;a href="https://github.com/waldekmastykarz/Angular-JumpStart/tree/identity" rel="noopener noreferrer"&gt;sample app&lt;/a&gt; built by my other colleague &lt;a href="https://github.com/DanWahlin" rel="noopener noreferrer"&gt;Dan Wahlin&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>angular</category>
      <category>javascript</category>
      <category>security</category>
      <category>microsoft</category>
    </item>
    <item>
      <title>Work apps need work data</title>
      <dc:creator>Waldek Mastykarz</dc:creator>
      <pubDate>Fri, 19 Aug 2022 16:15:35 +0000</pubDate>
      <link>https://forem.com/waldekmastykarz/work-apps-need-work-data-4nnp</link>
      <guid>https://forem.com/waldekmastykarz/work-apps-need-work-data-4nnp</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BNzmk0Xy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.mastykarz.nl/assets/images/2022/08/banner.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BNzmk0Xy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.mastykarz.nl/assets/images/2022/08/banner.png" alt="Work apps need work data" width="489" height="354"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you use apps for work, they rarely show you all the data that you need to get the full context of your work. And that's a shame because that information is often readily available to you, and could be integrated into your app.&lt;/p&gt;

&lt;h2&gt;
  
  
  It's all about the context
&lt;/h2&gt;

&lt;p&gt;Say you're asked to build an app to manage projects for your organization. You build a web app, and host it in the cloud. Using the app you can store information about projects, customers, and project teams. Your organization uses another app for communication, and another for storing files, so rather than duplicate the functionality you point to existing apps for easy access.&lt;/p&gt;

&lt;p&gt;Your app works, but is it convenient to use? Way too often you see your colleagues switch back and forth between your app, and other apps to get the full context of their work: information about the project, recent emails to the customer, project team communication, project files, and people who work on the project. What could you have done differently?&lt;/p&gt;

&lt;h2&gt;
  
  
  Bring work data into your app
&lt;/h2&gt;

&lt;p&gt;Say, your organization uses Microsoft 365. The project information is stored in your app. To communicate with the project team, they need to go to Teams. To get the project files, they need to go to SharePoint. Communication with the customer is in email in Outlook, and information about people is accessible via Teams, Outlook, or SharePoint, depending on where they are at the moment. Instead of switching between all these different apps, why not bring the relevant data to your app?&lt;/p&gt;

&lt;p&gt;Work apps need work data. Even though your app has a specific purpose, like managing projects, people using it will need more information to get the full context of their work. Projects are commissioned by a customer and run by a project team. While you work on projects, you create files, and communicate about them. The same goes for managing orders, or any other business scenario. So why should that work context be fragmented? Why not offer your colleagues all the information they need right where they need it: &lt;strong&gt;in your app&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;If you use Microsoft 365, information about people, and files is readily available to you, and accessible using &lt;a href="https://developer.microsoft.com/graph/rest-api"&gt;Microsoft Graph&lt;/a&gt; - the API for Microsoft 365. Instead of requiring your users to jump between the different apps, you can use Graph to bring contextually relevant information to your app. You can bring in emails sent to, and received from the customer. You can bring in project files that the project team has recently worked on. You can show information about the project team members, their location, and time zones right in your app. You can have all this information, and more available in the context of your app so that your colleagues spend more time working, and less time switching contexts.&lt;/p&gt;

&lt;p&gt;The great thing about using Microsoft Graph is that it allows you to tap into data, and insights that are stored in Microsoft 365. You get to benefit from all functionality from Microsoft 365, such as storage, access management, or disaster recovery, and at the same time, can integrate it in a contextually relevant way with your app.&lt;/p&gt;

&lt;p&gt;Bringing work data to your app doesn't need to come at the cost of a lot of extra work. If you're on Microsoft 365, use Microsoft Graph, and tap into organizational data, and insights stored in Microsoft 365 that are relevant to your app. Check out what's possible using &lt;a href="https://developer.microsoft.com/graph/rest-api"&gt;Microsoft Graph&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>beginners</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Get notified in Microsoft Teams</title>
      <dc:creator>Waldek Mastykarz</dc:creator>
      <pubDate>Tue, 12 Jul 2022 09:08:04 +0000</pubDate>
      <link>https://forem.com/waldekmastykarz/get-notified-in-teams-338d</link>
      <guid>https://forem.com/waldekmastykarz/get-notified-in-teams-338d</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HchHG234--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.mastykarz.nl/assets/images/2022/07/banner.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HchHG234--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.mastykarz.nl/assets/images/2022/07/banner.png" alt="Get notified in Teams" width="880" height="510"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How many different apps do you use at work? How hard is it for you to stay up-to-date on what's going on in all of them? I bet the answers are &lt;em&gt;a lot&lt;/em&gt; and &lt;em&gt;hard&lt;/em&gt;. If your organization is on Microsoft 365, there's a better way, though. Hear me out.&lt;/p&gt;

&lt;p&gt;If your organization is on Microsoft 365, you're probably using Microsoft Teams. Most likely you use it for chat and video calls. Probably you use it to communicate with your colleagues and work together on files. Did you know though, that you can extend Teams with custom apps? Did you know, that these apps can help you stay up-to-date on what's going on in your organization?&lt;/p&gt;

&lt;p&gt;Since you're already using Microsoft Teams for work, why not turn it into a personal HQ and have it deliver all important updates to you? The easiest way to do it is using &lt;strong&gt;notification bots&lt;/strong&gt;. Notification bots are nothing more than a piece of code running in the cloud. They communicate with services that you want to monitor and send you a message to Teams when there's something that you should know. Because notification bots are registered with Microsoft Teams, they can send you &lt;a href="https://adaptivecards.io/"&gt;Adaptive Cards&lt;/a&gt; that communicate updates in a user-friendly way and go way beyond plain text.&lt;/p&gt;

&lt;p&gt;Building notification bots isn't hard. Especially, if you're using the recently released Teams Toolkit. Teams Toolkit offers you a template to build a notification bot. All you have to do is add the code to monitor changes and send a message to Teams. Teams Toolkit will help you test the bot and deploy it, and you'll be able to do all that in minutes.&lt;/p&gt;

&lt;p&gt;My colleague, Garry Trinder, made a video that shows you how to create a notification bot using Teams Toolkit step by step.&lt;/p&gt;

&lt;p&gt;Have a look at it and give it a try yourself. Even if you might not need it right now, it's totally worth the few minutes you'll spend and show it to your colleagues.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Check out Garry's video&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/microsoftteams/platform/sbs-gs-notificationbot?tabs=vscode"&gt;Build a notification bot using Teams Toolkit&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When you're done, leave a comment and let me know how it went. Looking forward to hearing from you.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>programming</category>
      <category>microsoft365</category>
    </item>
    <item>
      <title>Easily show files as cards using Microsoft Graph Toolkit and hTWOo</title>
      <dc:creator>Waldek Mastykarz</dc:creator>
      <pubDate>Wed, 05 Jan 2022 08:28:31 +0000</pubDate>
      <link>https://forem.com/waldekmastykarz/easily-show-files-as-cards-using-microsoft-graph-toolkit-and-htwoo-na5</link>
      <guid>https://forem.com/waldekmastykarz/easily-show-files-as-cards-using-microsoft-graph-toolkit-and-htwoo-na5</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2031wYC1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.mastykarz.nl/assets/images/2021/06/mgt-htwoo-banner.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2031wYC1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.mastykarz.nl/assets/images/2021/06/mgt-htwoo-banner.png" alt="Easily show files as cards using Microsoft Graph Toolkit and hTWOo" width="880" height="513"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With a recent update to Microsoft Graph Toolkit, showing your files as cards became even easier. Check it out.&lt;/p&gt;

&lt;h2&gt;
  
  
  Show files as cards using Microsoft Graph Toolkit and hTWOo
&lt;/h2&gt;

&lt;p&gt;Recently, I showed you &lt;a href="https://dev.to/show-files-cards-microsoft-graph-toolkit-htwoo/"&gt;how you can use the Microsoft Graph Toolkit to show files stored in Microsoft 365 as cards&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bnbq3Rjt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.mastykarz.nl/assets/images/2021/06/mgt-htwoo-cards-thumb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bnbq3Rjt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.mastykarz.nl/assets/images/2021/06/mgt-htwoo-cards-thumb.png" alt="List of files displayed as document cards in the browser. Cards are showing the file's thumbnail, location and the avatar of the person who last modified the file" width="880" height="922"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Using just a few lines of code, we built a simple Single-Page App secured with Azure Active Directory, added auth, to let users sign in with their Microsoft 365 account and retrieve their files. We did it using &lt;a href="https://docs.microsoft.com/graph/toolkit/overview?WT.mc_id=m365-53122-wmastyka"&gt;Microsoft Graph Toolkit&lt;/a&gt;, which is &lt;em&gt;the easiest way to connect your app to Microsoft 365&lt;/em&gt;. Its &lt;a href="https://docs.microsoft.com/graph/toolkit/overview?WT.mc_id=m365-53122-wmastyka"&gt;authentication providers&lt;/a&gt; abstract away all of the auth code to a single line. And thanks to its &lt;a href="https://docs.microsoft.com/graph/toolkit/overview?WT.mc_id=m365-53122-wmastyka"&gt;components&lt;/a&gt;, you can easily show data from Microsoft 365 in your app.&lt;/p&gt;

&lt;p&gt;To show files as cards, we used &lt;a href="https://lab.n8d.studio/htwoo/"&gt;hTWOo&lt;/a&gt;, which is a community-driven implementation of the Fluent UI design language.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The complete sample app used in this article is &lt;a href="https://github.com/waldekmastykarz/mgt-htwoo-files/"&gt;available on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Inconvenient showing file details
&lt;/h2&gt;

&lt;p&gt;Each card we show in our app contains information about the file, such as its thumbnail, location, name, author and picture, and when the file was last modified. Not all of this information is available to us readily, which is why in our original solution, we had to add quite some JavaScript code to load the necessary information from Microsoft Graph. And this is where things got complicated.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--otJrT_KD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.mastykarz.nl/assets/images/2022/01/javascript-code.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--otJrT_KD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.mastykarz.nl/assets/images/2022/01/javascript-code.png" alt="Screenshot of JavaScript code calling Microsoft Graph" width="880" height="1194"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Microsoft Graph Toolkit gives you simplicity. Instead of building requests, parsing responses, and handling errors, you add ready-to-use components that do all of that for you and allow you to focus on building your app. But you don't benefit much if you still need to write requests because you can't get all the data that you need, do you?&lt;/p&gt;

&lt;h2&gt;
  
  
  Easily show files as cards with Microsoft Graph Toolkit
&lt;/h2&gt;

&lt;p&gt;Recently, Microsoft Graph Toolkit got updated, and if you were to build an app that shows files from Microsoft 365 as cards, you'd no longer need to write custom JavaScript. Here's the code you'd need instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/@microsoft/mgt/dist/bundle/mgt-loader.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/@n8d/htwoo-core/dist/css/htwoo.min.css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"styles.css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;mgt-msal2-provider&lt;/span&gt; &lt;span class="na"&gt;client-id=&lt;/span&gt;&lt;span class="s"&gt;"d43f076b-c6a6-4805-97be-f9ef969241c0"&lt;/span&gt; &lt;span class="na"&gt;authority=&lt;/span&gt;&lt;span class="s"&gt;"https://login.microsoftonline.com/M365x61791022.onmicrosoft.com"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/mgt-msal2-provider&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;mgt-login&amp;gt;&amp;lt;/mgt-login&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;mgt-file-list&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;template&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;My files&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"hoo-cardgrid"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;data-for=&lt;/span&gt;&lt;span class="s"&gt;"file in files"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"hoo-doccard"&lt;/span&gt; &lt;span class="na"&gt;data-props=&lt;/span&gt;&lt;span class="s"&gt;"{{@click: openFile}}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"hoo-cardimage"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;data-if=&lt;/span&gt;&lt;span class="s"&gt;"file.folder"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"./folder.jpg"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;mgt-get&lt;/span&gt; &lt;span class="na"&gt;data-if=&lt;/span&gt;&lt;span class="s"&gt;"!file.folder"&lt;/span&gt; &lt;span class="na"&gt;resource=&lt;/span&gt;&lt;span class="s"&gt;"/drives/{{file.parentReference.driveId}}/items/{{file.id}}/thumbnails/0/c320x180_crop/content"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"image"&lt;/span&gt; &lt;span class="na"&gt;cache-enabled=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;data-type=&lt;/span&gt;&lt;span class="s"&gt;"loading"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"hoo-ph-squared"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;data-type=&lt;/span&gt;&lt;span class="s"&gt;"error"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"./otter.jpg"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;data-type=&lt;/span&gt;&lt;span class="s"&gt;"no-data"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"./otter.jpg"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;data-type=&lt;/span&gt;&lt;span class="s"&gt;"default"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"{{image}}"&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"320"&lt;/span&gt; &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"180"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/mgt-get&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"hoo-cardlocation"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;mgt-get&lt;/span&gt; &lt;span class="na"&gt;resource=&lt;/span&gt;&lt;span class="s"&gt;"/drives/{{file.parentReference.driveId}}"&lt;/span&gt; &lt;span class="na"&gt;cache-enabled=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;data-type=&lt;/span&gt;&lt;span class="s"&gt;"loading"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"hoo-ph-row"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;data-type=&lt;/span&gt;&lt;span class="s"&gt;"error"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"hoo-ph-row"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;data-type=&lt;/span&gt;&lt;span class="s"&gt;"default"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                {{name}}
              &lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/mgt-get&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"hoo-cardtitle"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{file.name}}&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"hoo-cardfooter"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"hoo-avatar"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;mgt-get&lt;/span&gt; &lt;span class="na"&gt;resource=&lt;/span&gt;&lt;span class="s"&gt;"/users/{{file.lastModifiedBy.user.id}}/photo/$value"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"image"&lt;/span&gt; &lt;span class="na"&gt;cache-enabled=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;data-type=&lt;/span&gt;&lt;span class="s"&gt;"loading"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"hoo-ph-circle"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;data-type=&lt;/span&gt;&lt;span class="s"&gt;"no-data"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"hoo-ph-circle hoo-avatar-img"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;data-type=&lt;/span&gt;&lt;span class="s"&gt;"default"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"{{image}}"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"hoo-avatar-img"&lt;/span&gt; &lt;span class="na"&gt;loading=&lt;/span&gt;&lt;span class="s"&gt;"lazy"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;/mgt-get&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"hoo-cardfooter-data"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"hoo-cardfooter-name"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{file.lastModifiedBy.user.displayName}}&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"hoo-cardfooter-modified"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{formatDate(file.lastModifiedDateTime)}}&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"hoo-button-primary"&lt;/span&gt; &lt;span class="na"&gt;data-props=&lt;/span&gt;&lt;span class="s"&gt;"{{@click: loadMore}}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"hoo-button-label"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Load more&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/mgt-file-list&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"script.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's what's changed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Load document thumbnail using mgt-get
&lt;/h3&gt;

&lt;p&gt;Originally, we'd use custom JavaScript to load the document thumbnail from Microsoft Graph and add it to the template. Starting from Microsoft Graph Toolkit v2.3.1, we can load images using the &lt;a href="https://docs.microsoft.com/graph/toolkit/components/get?WT.mc_id=m365-53122-wmastyka"&gt;Get component&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;mgt-get&lt;/span&gt; &lt;span class="na"&gt;data-if=&lt;/span&gt;&lt;span class="s"&gt;"!file.folder"&lt;/span&gt; &lt;span class="na"&gt;resource=&lt;/span&gt;&lt;span class="s"&gt;"/drives/{{file.parentReference.driveId}}/items/{{file.id}}/thumbnails/0/c320x180_crop/content"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"image"&lt;/span&gt; &lt;span class="na"&gt;cache-enabled=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;data-type=&lt;/span&gt;&lt;span class="s"&gt;"loading"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"hoo-ph-squared"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;data-type=&lt;/span&gt;&lt;span class="s"&gt;"error"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"./otter.jpg"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;data-type=&lt;/span&gt;&lt;span class="s"&gt;"no-data"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"./otter.jpg"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;data-type=&lt;/span&gt;&lt;span class="s"&gt;"default"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"{{image}}"&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"320"&lt;/span&gt; &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"180"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/mgt-get&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the component, we're using 4 templates:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;loading&lt;/code&gt;, which is rendered while the Get component is waiting on a response from Microsoft Graph&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;error&lt;/code&gt;, in case Microsoft Graph returned an error&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;no-data&lt;/code&gt;, this is a new template added to the Get component in Microsoft Graph Toolkit v2.3.1 which is rendered when the request returned no data. When you request an image, it's also rendered when the request returns a 404.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;default&lt;/code&gt;, which is rendered when retrieving data succeeded&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We can now use the Get component, not only to load the document's preview but also the avatar of the user who modified the file most recently.&lt;/p&gt;

&lt;h3&gt;
  
  
  Load file location
&lt;/h3&gt;

&lt;p&gt;Another request for which we originally wrote custom JavaScript, was to retrieve the location where the file is stored. In this version, we replaced that code with another instance of the Get component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;mgt-get&lt;/span&gt; &lt;span class="na"&gt;resource=&lt;/span&gt;&lt;span class="s"&gt;"/drives/{{file.parentReference.driveId}}"&lt;/span&gt; &lt;span class="na"&gt;cache-enabled=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;data-type=&lt;/span&gt;&lt;span class="s"&gt;"loading"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"hoo-ph-row"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;data-type=&lt;/span&gt;&lt;span class="s"&gt;"error"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"hoo-ph-row"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;data-type=&lt;/span&gt;&lt;span class="s"&gt;"default"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    {{name}}
  &lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/mgt-get&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While the data is loading, we show a shimmer - an animated placeholder that communicates to users that content is loading. After we retrieved the file's location from Microsoft Graph, we show it instead.&lt;/p&gt;

&lt;p&gt;With these modifications, the only piece of JavaScript that's left is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mgt-file-list&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;templateContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;formatDate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;date&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toLocaleString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;openFile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;webUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;_blank&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;loadMore&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parentNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;renderNextPage&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We use these custom functions to format the file modified date, open the select file in a new tab, and load more files. Notice, that we no longer need to manually call Microsoft Graph to retrieve data, process responses, and handle errors!&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Microsoft Graph Toolkit is the easiest way to connect your app to Microsoft 365. Because it takes care of authentication and retrieving and showing the data in your app, you can focus on building your app. With a recent change to Microsoft Graph Toolkit, you can build even richer visualizations without having to write custom JavaScript and manually call Microsoft Graph.&lt;/p&gt;

&lt;p&gt;If you're new to Microsoft Graph Toolkit, the best place to start is to follow the &lt;a href="https://docs.microsoft.com/learn/paths/m365-msgraph-toolkit/?WT.mc_id=m365-53122-wmastyka"&gt;Microsoft Graph Toolkit learning path&lt;/a&gt; on MS Learn.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>microsoftgraph</category>
      <category>microsoft365</category>
    </item>
    <item>
      <title>Extend Microsoft Viva Connections with your existing web development skills</title>
      <dc:creator>Waldek Mastykarz</dc:creator>
      <pubDate>Wed, 03 Nov 2021 00:00:00 +0000</pubDate>
      <link>https://forem.com/waldekmastykarz/extend-microsoft-viva-connections-with-your-existing-web-development-skills-2f2f</link>
      <guid>https://forem.com/waldekmastykarz/extend-microsoft-viva-connections-with-your-existing-web-development-skills-2f2f</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--B0pNrnGH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.mastykarz.nl/assets/images/2021/11/banner-viva-connections.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--B0pNrnGH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.mastykarz.nl/assets/images/2021/11/banner-viva-connections.png" alt="Microsoft Viva Connections" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.microsoft.com/viva"&gt;Microsoft Viva Connections&lt;/a&gt; is the gateway to the modern employee experience. As more and more organizations started working remotely/hybrid, they realized they need a better way to engage with their employees and keep them up-to-date. This is where Viva Connections comes in. It's a turn-key solution that's a part of Microsoft 365 and which aggregates information from different sources and puts them in front of employees on desktop and mobile.&lt;/p&gt;

&lt;p&gt;Many organizations are very interested in Microsoft Viva and Viva Connections. Not only do they want to start using it, but also extend it to their needs to make it even more relevant to their employees. And as a developer that's a great opportunity that you should take advantage of.&lt;/p&gt;

&lt;p&gt;You can use your existing web development skills and extend Viva Connections with custom functionality. Using Microsoft Graph you can bring data and insights from Microsoft 365 to people's fingertips. And by connecting to your custom APIs, you can bring in your line of business data as well!&lt;/p&gt;

&lt;p&gt;To show you what's possible and how to get started, Microsoft created a &lt;a href="https://aka.ms/extend-viva-connections"&gt;learning path on MS Learn&lt;/a&gt;. It takes you step by step through the basics of Viva Connections, how you can extend it and how to get stared. If you like web development, this is perfect opportunity to do more with your skills. You can try it all for free with a &lt;a href="https://developer.microsoft.com/microsoft-365/dev-program"&gt;Microsoft 365 developer tenant&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>programming</category>
      <category>microsoft365</category>
    </item>
  </channel>
</rss>
