<?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>DEV Community: Alejandro Brozzo</title>
    <description>The latest articles on DEV Community by Alejandro Brozzo (@alebrozzo).</description>
    <link>https://dev.to/alebrozzo</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%2F133817%2Fd5d664ac-4b23-48d1-a223-55e4b01252eb.png</url>
      <title>DEV Community: Alejandro Brozzo</title>
      <link>https://dev.to/alebrozzo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alebrozzo"/>
    <language>en</language>
    <item>
      <title>My trip to learning some deployment tools</title>
      <dc:creator>Alejandro Brozzo</dc:creator>
      <pubDate>Mon, 23 Oct 2023 08:31:47 +0000</pubDate>
      <link>https://dev.to/alebrozzo/my-trip-to-learning-some-deployment-tools-4163</link>
      <guid>https://dev.to/alebrozzo/my-trip-to-learning-some-deployment-tools-4163</guid>
      <description>&lt;h2&gt;
  
  
  The application used for learning
&lt;/h2&gt;

&lt;p&gt;You know how when you want to play a board game, you set everything up only to find out that you lost one of the three dice it needs? Or you want to play Dungeons and Dragons but you can't find your 20 faced die? Heck, the kids broke the spinning wheel of Game of Life, should you throw the whole game to the trash? Fear not, I've got you covered.&lt;/p&gt;

&lt;h3&gt;
  
  
  Enter Timba
&lt;/h3&gt;

&lt;p&gt;Timba is a web application that lets you create a set of virtual dice with as many dies and with as many faces as you need. You want a single 6 faces die for your board game? easy pease. Oh you need two of those? No problem, edit the die count or just create a new set. You remembered a game you knew when you were little where you needed 5 dies? same thing. A full blown D&amp;amp;D set? just define as many die types with as many faces as you need. Game of&lt;br&gt;
Life wheel broke? New 10 faces die and you are all set. Also, what is a coin if not a 2 faced die?&lt;/p&gt;

&lt;p&gt;Creating the dice set is the first step, you can then, of course, roll the dice. Timba will keep track of all the rolls of each die so you can go back and revisit the results. When you are done or want to start over you just reset the rolls.&lt;/p&gt;

&lt;p&gt;This was the initial scope of the application, no Auth, no long term saving of the data, nothing fancy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tech stack (initial)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Svelte&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I wanted to take the chance to learn a bit about Svelte, since I see it getting more and more steam on the web. So instead of using good ol' React or just plain JS I went with that.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Firestore&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As a way to store dice sets I initially used LocalStorage and that worked well, but there is no deploy needed if I just want to use the app in my own computer. I also never had used Firestore nor Supabase so I went ahead and implemented them both. The main difference between them is that Supabase offers a PostgreSQL database while Firestore gives you a NoSQL database. I felt Supabase's client was not good enough for an actual application (lack of transactions being a big negative point) but also for Timba's needs a NoSQL database was a better fit. This and the fact that I have a vast experience in SQL and very little in NoSQL made me decant for Firestore. The more I could learn in one go, the better (not true but it sounds nice).&lt;/p&gt;

&lt;h2&gt;
  
  
  Deployment learnings
&lt;/h2&gt;

&lt;p&gt;Once the app reached a point where it made sense to deploy - mainly being able to CRUD dice sets and roll them - I started looking for deployment options. Now here is the thing: I wasn't sure my application was static or dynamic. I've always found these terms vague... simple on the surface but confusing in the edge cases.&lt;/p&gt;

&lt;p&gt;Timba has a database, although for now it is the same data for every user. But the database is online, I wouldn't hit an API of my own to get the data, I would just use the Firebase client to get it. So is it static or dynamic? I don't know.&lt;/p&gt;

&lt;p&gt;Besides that, Svelte can do SSR automatically (and it was doing so), that hinted me to call it dynamic... or, if the pages could be all pre-rendered, would it then be static? I mean, if the build step would visit all the links (the database is queried only once at the load of the application) it could probably generate all the pages. Do build steps do that? do they execute client or API calls? could Timba be pre-rendered? I don't know.&lt;/p&gt;

&lt;h3&gt;
  
  
  First attempt: Google Cloud Platform
&lt;/h3&gt;

&lt;p&gt;Since I had opted for using Firestore as Timba's database, and Firestore is a product of GCP, I decided to give this platform a first try. I went to the site and took a look around. The platform's design was nice but I couldn't understand a word of what I was reading. And since you don't know what you don't know, I quickly gave up this approach of going into a cloud provider and looking around.&lt;/p&gt;

&lt;h3&gt;
  
  
  Second attempt: AWS (Amplify)
&lt;/h3&gt;

&lt;p&gt;I googled for information on hosting, asked a few people, and in the end somehow I ended up with I should either use AWS S3 or EC2. How is a newbie supposed to really know what to look for with those names? Anyway, apparently static sites would use S3 and dynamic sites would use EC2. Please refer to my previous rant regarding what even static and dynamic mean.&lt;br&gt;
In my mind, right or wrong, I have the idea that I just want to put the result of building the web app that requires no own API in a service that just exposes said files. I was hoping any of these cloud providers would have a service that would do just that. Almost like a good old FTP, drop your files here. It seems that is not cool anymore.&lt;/p&gt;

&lt;p&gt;Anyway searching for more info on which of those (S3 or EC2) I should use, something called Amplify showed up. It allows you to deploy straight from your github (or any other git provider). I gave it a try: selected my github project, tweaked the base directory, and hit deploy. It didn't work. I mean, it said it deployed, but the url showed me nothing. Stack overflow had fixes for when the page was blank, which was not my case. So I tried trying to figure out stuff... it did seem like I would need to use something called &lt;code&gt;adapter-static&lt;/code&gt; for my site to work, and I had decided I would try to treat Timba as a static site until proven otherwise. So I made that change knowing that would not fix my problem, and guess what... I was right, it didn't fix it. Not only that, I was not able to see what the impact of my change was. So I started thinking harder about what could be wrong. I realized that my output folder (`sveltekit/output) didn't have an index file (this I have to thank those adapter-static posts explaining how to use it) and after a couple of hours trying to figure out why, it hit me. Remember at the beginning of this paragraph when I said that I had selected my github project and tweaked the base directory? well, I shouldn't have done that second step. The original base directory setting was correct. So I changed the value to the original one and was ready to hit deploy again to try it out... except there was no "deploy with new settings" button. I read online that people were complaining that they needed to do a bogus change (not even an empty commit) for the deploy to re-trigger. I didn't want to do that just yet, so navigating a pretty but confusing UI I found a "Redeploy this version" button. I clicked it and after redeploying, contrary to my expectations, it did take the new settings into account. Not only that but also I could see my site. It was not working, but it was definitely my site, I recognized the "roulette mat green" color I had picked for a background.&lt;/p&gt;

&lt;p&gt;So I then went back to my site generation. My gut feeling (and i have a big gut so the feeling was big too) was that since Svelte does SSR automatically and I was in fact querying the firestore db on a ".server.ts" page, I should try changing that. So I indicated no ssr and removed the ".server" part of my layout file, updated the types (as I am using typescript) and deployed again. Sure enough, Timba was ready in all its splendor and casino colors. I really should change all the UI styles, but I am very bad at design so I probably won't.&lt;/p&gt;

&lt;h3&gt;
  
  
  Third attempt: Azure (App Services)
&lt;/h3&gt;

&lt;p&gt;Being all built up and proud of my success I decided to try my luck with Azure next. I had used App Services before and while I didn't really understand what I was doing then, I was only scratching the surface of an existing deploy. I can't remember what I was doing anyway, but I do remember being confused. I didn't remember a feeling of "this is hard", it was more of "I don't know what all these words are supposed to mean".&lt;/p&gt;

&lt;p&gt;So there I went, created a new account with my free $200 credit for a month, and headed to App Services. Creating that account ended up being the hardest part of the task. In a similar manner to what I had done with AWS Amplify, I just clicked on Create new static site, pointed to my github account, and clicked "create". After a few seconds I got the url of my app (it doesn't say Timba anywhere) and navigating to it just opened a working application. Was this easier than Amplify? probably not, it's just that when I deployed using Amplify I needed to learn what I was doing and change my app to actually support being served as static.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;So this has been the first "I am learning how to deploy to the cloud" step. I want Timba to have many more features, for starters some sort of user creation to allow for each user to have their own private sets. I have the feeling that if I can use firestore's auth abilities I would still be able to get away with a static site, but eventually I will need to make it all dynamic. Even if not necessary, I want to learn different alternatives of application deployment, Timba is just an excuse, or rather, a carrot for this donkey.&lt;/p&gt;

</description>
      <category>serverless</category>
      <category>deploy</category>
      <category>selflearn</category>
    </item>
    <item>
      <title>My trip to learning some deployment tools</title>
      <dc:creator>Alejandro Brozzo</dc:creator>
      <pubDate>Mon, 23 Oct 2023 08:19:47 +0000</pubDate>
      <link>https://dev.to/alebrozzo/my-trip-to-learning-some-deployment-tools-51ko</link>
      <guid>https://dev.to/alebrozzo/my-trip-to-learning-some-deployment-tools-51ko</guid>
      <description>&lt;h2&gt;
  
  
  The application used for learning
&lt;/h2&gt;

&lt;p&gt;You know how when you want to play a board game, you set everything up only to find out that you lost one of the three dice it needs? Or you want to play Dungeons and Dragons but you can't find your 20 faced die? Heck, the kids broke the spinning wheel of Game of Life, should you throw the whole game to the trash? Fear not, I've got you covered.&lt;/p&gt;

&lt;h3&gt;
  
  
  Enter Timba
&lt;/h3&gt;

&lt;p&gt;Timba is a web application that lets you create a set of virtual dice with as many dies and with as many faces as you need. You want a single 6 faces die for your board game? easy pease. Oh you need two of those? No problem, edit the die count or just create a new set. You remembered a game you knew when you were little where you needed 5 dies? same thing. A full blown D&amp;amp;D set? just define as many die types with as many faces as you need. Game of&lt;br&gt;
Life wheel broke? New 10 faces die and you are all set. Also, what is a coin if not a 2 faced die?&lt;/p&gt;

&lt;p&gt;Creating the dice set is the first step, you can then, of course, roll the dice. Timba will keep track of all the rolls of each die so you can go back and revisit the results. When you are done or want to start over you just reset the rolls.&lt;/p&gt;

&lt;p&gt;This was the initial scope of the application, no Auth, no long term saving of the data, nothing fancy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tech stack (initial)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Svelte&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I wanted to take the chance to learn a bit about Svelte, since I see it getting more and more steam on the web. So instead of using good ol' React or just plain JS I went with that.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Firestore&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As a way to store dice sets I initially used LocalStorage and that worked well, but there is no deploy needed if I just want to use the app in my own computer. I also never had used Firestore nor Supabase so I went ahead and implemented them both. The main difference between them is that Supabase offers a PostgreSQL database while Firestore gives you a NoSQL database. I felt Supabase's client was not good enough for an actual application (lack of transactions being a big negative point) but also for Timba's needs a NoSQL database was a better fit. This and the fact that I have a vast experience in SQL and very little in NoSQL made me decant for Firestore. The more I could learn in one go, the better (not true but it sounds nice).&lt;/p&gt;

&lt;h2&gt;
  
  
  Deployment learnings
&lt;/h2&gt;

&lt;p&gt;Once the app reached a point where it made sense to deploy - mainly being able to CRUD dice sets and roll them - I started looking for deployment options. Now here is the thing: I wasn't sure my application was static or dynamic. I've always found these terms vague... simple on the surface but confusing in the edge cases.&lt;/p&gt;

&lt;p&gt;Timba has a database, although for now it is the same data for every user. But the database is online, I wouldn't hit an API of my own to get the data, I would just use the Firebase client to get it. So is it static or dynamic? I don't know.&lt;/p&gt;

&lt;p&gt;Besides that, Svelte can do SSR automatically (and it was doing so), that hinted me to call it dynamic... or, if the pages could be all pre-rendered, would it then be static? I mean, if the build step would visit all the links (the database is queried only once at the load of the application) it could probably generate all the pages. Do build steps do that? do they execute client or API calls? could Timba be pre-rendered? I don't know.&lt;/p&gt;

&lt;h3&gt;
  
  
  First attempt: Google Cloud Platform
&lt;/h3&gt;

&lt;p&gt;Since I had opted for using Firestore as Timba's database, and Firestore is a product of GCP, I decided to give this platform a first try. I went to the site and took a look around. The platform's design was nice but I couldn't understand a word of what I was reading. And since you don't know what you don't know, I quickly gave up this approach of going into a cloud provider and looking around.&lt;/p&gt;

&lt;h3&gt;
  
  
  Second attempt: AWS (Amplify)
&lt;/h3&gt;

&lt;p&gt;I googled for information on hosting, asked a few people, and in the end somehow I ended up with I should either use AWS S3 or EC2. How is a newbie supposed to really know what to look for with those names? Anyway, apparently static sites would use S3 and dynamic sites would use EC2. Please refer to my previous rant regarding what even static and dynamic mean.&lt;br&gt;
In my mind, right or wrong, I have the idea that I just want to put the result of building the web app that requires no own API in a service that just exposes said files. I was hoping any of these cloud providers would have a service that would do just that. Almost like a good old FTP, drop your files here. It seems that is not cool anymore.&lt;/p&gt;

&lt;p&gt;Anyway searching for more info on which of those (S3 or EC2) I should use, something called Amplify showed up. It allows you to deploy straight from your github (or any other git provider). I gave it a try: selected my github project, tweaked the base directory, and hit deploy. It didn't work. I mean, it said it deployed, but the url showed me nothing. Stack overflow had fixes for when the page was blank, which was not my case. So I tried trying to figure out stuff... it did seem like I would need to use something called &lt;code&gt;adapter-static&lt;/code&gt; for my site to work, and I had decided I would try to treat Timba as a static site until proven otherwise. So I made that change knowing that would not fix my problem, and guess what... I was right, it didn't fix it. Not only that, I was not able to see what the impact of my change was. So I started thinking harder about what could be wrong. I realized that my output folder (`sveltekit/output) didn't have an index file (this I have to thank those adapter-static posts explaining how to use it) and after a couple of hours trying to figure out why, it hit me. Remember at the beginning of this paragraph when I said that I had selected my github project and tweaked the base directory? well, I shouldn't have done that second step. The original base directory setting was correct. So I changed the value to the original one and was ready to hit deploy again to try it out... except there was no "deploy with new settings" button. I read online that people were complaining that they needed to do a bogus change (not even an empty commit) for the deploy to re-trigger. I didn't want to do that just yet, so navigating a pretty but confusing UI I found a "Redeploy this version" button. I clicked it and after redeploying, contrary to my expectations, it did take the new settings into account. Not only that but also I could see my site. It was not working, but it was definitely my site, I recognized the "roulette mat green" color I had picked for a background.&lt;/p&gt;

&lt;p&gt;So I then went back to my site generation. My gut feeling (and i have a big gut so the feeling was big too) was that since Svelte does SSR automatically and I was in fact querying the firestore db on a ".server.ts" page, I should try changing that. So I indicated no ssr and removed the ".server" part of my layout file, updated the types (as I am using typescript) and deployed again. Sure enough, Timba was ready in all its splendor and casino colors. I really should change all the UI styles, but I am very bad at design so I probably won't.&lt;/p&gt;

&lt;h3&gt;
  
  
  Third attempt: Azure (App Services)
&lt;/h3&gt;

&lt;p&gt;Being all built up and proud of my success I decided to try my luck with Azure next. I had used App Services before and while I didn't really understand what I was doing then, I was only scratching the surface of an existing deploy. I can't remember what I was doing anyway, but I do remember being confused. I didn't remember a feeling of "this is hard", it was more of "I don't know what all these words are supposed to mean".&lt;/p&gt;

&lt;p&gt;So there I went, created a new account with my free $200 credit for a month, and headed to App Services. Creating that account ended up being the hardest part of the task. In a similar manner to what I had done with AWS Amplify, I just clicked on Create new static site, pointed to my github account, and clicked "create". After a few seconds I got the url of my app (it doesn't say Timba anywhere) and navigating to it just opened a working application. Was this easier than Amplify? probably not, it's just that when I deployed using Amplify I needed to learn what I was doing and change my app to actually support being served as static.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;So this has been the first "I am learning how to deploy to the cloud" step. I want Timba to have many more features, for starters some sort of user creation to allow for each user to have their own private sets. I have the feeling that if I can use firestore's auth abilities I would still be able to get away with a static site, but eventually I will need to make it all dynamic. Even if not necessary, I want to learn different alternatives of application deployment, Timba is just an excuse, or rather, a carrot for this donkey.&lt;/p&gt;

</description>
      <category>deploy</category>
      <category>serverless</category>
      <category>selflearn</category>
    </item>
    <item>
      <title>WebAPI to WebAPI calls authenticated by Azure</title>
      <dc:creator>Alejandro Brozzo</dc:creator>
      <pubDate>Mon, 23 Nov 2020 05:28:49 +0000</pubDate>
      <link>https://dev.to/alebrozzo/webapi-to-webapi-calls-authenticated-by-azure-2plg</link>
      <guid>https://dev.to/alebrozzo/webapi-to-webapi-calls-authenticated-by-azure-2plg</guid>
      <description>&lt;h2&gt;
  
  
  The motivation
&lt;/h2&gt;

&lt;p&gt;Have you ever needed to have a web API call a second web API, but not on behalf of the logged user but as the web API itself? Usually this happens for daemon applications (apps that run on the background instead of under the control of an interactive user, you can find a better &lt;a href="https://en.wikipedia.org/wiki/Daemon_(computing)"&gt;definition of daemon apps on wikipedia&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;At work we are adding a process to our existing web application that requires a lot of CPU usage. We think that it is a good idea to have a separate processing module to do these tasks, as they can spike CPU usage to 100% and we don't want the rest of the users to suffer from this. We decided to place this module on an Azure environment, and I was assigned the task to set up a mock API to evaluate different implementation methods and authorization requirements. I do not have much experience using Azure (nor any other cloud services provider) so I suspected it would take me some time. I was right. The pushing of the API was simple, but the authorization using Azure Active Directory took me a while to figure out…, so I decided to write my experience to try and help other people in a similar position.&lt;/p&gt;

&lt;h2&gt;
  
  
  The setup
&lt;/h2&gt;

&lt;p&gt;In order for a web API to call another web API there must be two web APIs (duh). For reference, I will call the API that you need to call (in my case the processing, CPU hogging API) the "called API". The calling API I shall name "client API". "Client" is a standard name given to an app that needs to call another app and is the &lt;em&gt;OAuth&lt;/em&gt; grant flow name, so it is quite appropriate.&lt;/p&gt;

&lt;p&gt;Let's start this then (knuckle sound).&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: register both apps
&lt;/h3&gt;

&lt;p&gt;The first thing you need to know is that you must register both APIs in Azure AD, regardless of where you are going to host them. In fact, you may be using your local IIS to run them both. Azure AD will be used by the called API to grant access permission to the client API.&lt;/p&gt;

&lt;p&gt;Go to Azure and select &lt;em&gt;Azure Active Directory&lt;/em&gt;, but be sure to be on a directory that you have admin grants to… or at least that you can ask the admin for granting permissions. If you do not have admin grants in your current directory, you may be able to create a new one and you will be admin on that one (this was exactly my case). You use the "Create tenant" button for that but I won't explain how to do so.&lt;/p&gt;

&lt;p&gt;Now that you know that you are an admin and have selected your directory, you can go the menu option "App registrations" and select "New Registration". Give it a name and choose the supported account type that fits you best. You can leave the Redirect URI empty. You don't need it although depending on how you are creating the registration you may be forced to add one. Repeat for the other API.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Give your client API a secret
&lt;/h3&gt;

&lt;p&gt;Select the registration of your client API (the caller) and select the menu option "Certificates &amp;amp; secrets". There select "New client secret" and fill the fields. Remember to copy the assigned secret as you will never be able to see it again.&lt;/p&gt;

&lt;p&gt;What you have just done is give your client application a unique key that will be used when telling Azure AD who the app is. Think about it as a passport number of sorts. Keep in mind that for a production app, you should use Certificates rather than Secrets, but the configuration itself is pretty much the same.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Expose the called API
&lt;/h3&gt;

&lt;p&gt;Now go back to your app registration list and select your called API, and then select the menu option "Expose an API". There, you need to first "Add a scope". A scope is a confusing name for a set of permissions, as defined by the OAuth standard. This will be used by your client API's controllers to indicate the roles a requesting party needs to execute the code. I am kind of assuming you already know this, so I won't go any deeper than that. I will mention though that you will be asked to set the "App ID URI", which should be globally unique and is basically a prefix of all scopes for this API. The default is "api://(clientId)" but you can change it to something a little clearer.&lt;/p&gt;

&lt;p&gt;Ok, now that you have defined a scope, you also need to authorize the client applications that can use your API, so on the very same screen where you added the scope you should see a "Add a client application" button. Click on it and you shall be presented with a two-field form. On the Client ID field, enter the client API's secret that you generated on step 2. And on the Authorized scopes field, tick the scope we just created earlier on this step.&lt;/p&gt;

&lt;p&gt;What we just did is letting Azure AD know which client apps have rights to reach the called API, and what scope to give them. If we wanted to expose the API to other clients, then we would repeat steps 1 and 2 as many times as client APIs we had, and add all of the generated secrets here (each app will have a different secret) with the scope assigned to them. Of course, you could add more scopes and assign different ones to each client API.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Create an app role on the called API
&lt;/h3&gt;

&lt;p&gt;We will now create an app role on the called API. Any client API that attempts to use this API will need that role assigned, it is not enough to have the secret and scope assigned. Go ahead and click on "Create app role" and fill the fields on the presented form. The name and values will be used by the called API on the code you write yourself, so enter whatever you want. However, on the allowed member types, be sure to select Applications (or Both) as it will be an application and not a user that will be consuming the API.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Add a permission to the client API
&lt;/h3&gt;

&lt;p&gt;Go back to your API registrations and select your client API. On the menu select API permissions and then click on "Add a permission". On the popping screen you will have to choose between "Microsoft APIs", "APIs my organization uses" and "My APIs". Either of the last two options should include your called API, select it. Now it will ask you what type of permission it requires: Delegated (i.e., logged as a user) or Application. If you are following closely you should have guessed that we need Application permissions, so select that and you should be able to see the permission we just created on our previous step. Select it and confirm.&lt;/p&gt;

&lt;p&gt;Once the permission appears on the list, you'll notice it will have a warning status as you need to grant admin consent. Next to the "Add permission" button there should be another button that says "Grant admin consent for [your directory name]". If it is disabled, then you are not an admin and cannot do it yourself (I told you so earlier, but did you listen?). Grant that consent or ask someone with power to do so.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 6: Include the required settings on both your APIs' code
&lt;/h3&gt;

&lt;p&gt;Congratulations! You have successfully configured Azure AD with a client flow to allow the client API to access your called API. In hindsight, "called API" wasn't such a great name, but I couldn't think of anything better.&lt;/p&gt;

&lt;p&gt;But do not uncork that champagne (or sparkling wine if your organization is not that big) just yet. You still need to code logic or at least put some setting in both your APIs, otherwise all those settings will only block you but not allow to use them.&lt;/p&gt;

&lt;h4&gt;
  
  
  Called API
&lt;/h4&gt;

&lt;p&gt;Let's start with the called API. I am using a .NET 5.0 API because I am cool and use al the latest tech. If you are using any version of .Net Core I am sure (guessing, actually) it is the same code. For a .NET 4.8 or earlier, or for other language… I dunno, figure it out, blog about it, and then let me know, I'll add a link to your post.&lt;/p&gt;

&lt;p&gt;As I was saying, on your called API you will need to add code and settings. Let's start with the "appsettings.json" file that you should have gotten when you created the project (what? You have not created a project yet? Then create one as ASP.NET Core Web Application, then select API. No auth is OK since we will add this manually, but you may choose an auth scheme for simplicity).&lt;/p&gt;

&lt;p&gt;On "appsettings.json" you need to add the settings to talk to Azure AD. Something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"AzureAd": {
  "Instance":   "https://login.microsoftonline.com/",
  "Domain":   "yourazuredirectorydomain.onmicrosoft.com",
  "TenantId": "abcdef12-3456-7890-abcd-001122334455",
  "ClientId": " fedcba21-0123-blaf-9876-667788990011"
},
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Please use your own Tenant (directory) Id and Application (client) Id that you are shown when selecting your called API on the App Registrations list.&lt;/p&gt;

&lt;p&gt;Then on Startup.cs you will need the following code, which use the nuget packages &lt;em&gt;Microsoft.Identity.Web&lt;/em&gt; and &lt;em&gt;Microsoft.AspNetCore.Authentication.JwtBearer&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public void ConfigureServices(IServiceCollection services)
{
  services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
  .AddMicrosoftIdentityWebApi(Configuration.GetSection("AzureAd"));
services.AddControllers();
  … // the rest of your configuration here
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that the "AzureAd" json key matches the parameter on GetSection.&lt;/p&gt;

&lt;p&gt;Also on the same file you need this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
  …
  app.UseHttpsRedirection();
  app.UseRouting();
  app.UseAuthentication();
  app.UseAuthorization();
  app.UseEndpoints(endpoints =\&amp;amp;gt; { endpoints.MapControllers(); });
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The thing you should be looking at is app.UseAuthentication and app.UseAuthorization. You need both of these.&lt;/p&gt;

&lt;p&gt;Then you are ready to add the "[Authorize]" attribute to either your controllers or a method within a controller. This ensures that in order to access your controller or method, the client API must have a valid token.&lt;/p&gt;

&lt;h4&gt;
  
  
  Client API
&lt;/h4&gt;

&lt;p&gt;Finally, the code needed on the client API. This has a similar "appsettings.json" configuration that needs to be set, but with a couple extra entries:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"AuthInfoAzureAd": {
  "Instance": "https://login.microsoftonline.com/{0}",
  "Domain": "yourazuredirectorydomain.onmicrosoft.com",
  "TenantId": "12345678-9012-3456-abcd-ef1230456789",
  "ClientId": "22554433-abcd-7890-3210-abcdef012345",
  "ClientSecret": "hush-hush-generated-by-AzureAd",
  "BaseAddress": "https://localhost:44340",
  "Scope": "api://your-called-api-url/.default"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few more things to note here:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;This info &lt;em&gt;will not&lt;/em&gt; be used on your ConfigureServices method, but rather when calling the downstream API.&lt;/li&gt;
&lt;li&gt;Instance has a "{0}" at the end that will be used to concatenate there the tenant id&lt;/li&gt;
&lt;li&gt;In my case the Domain and TenantId match on both projects. Not sure if this is necessary. In any case, your app registration has this info&lt;/li&gt;
&lt;li&gt;We are now adding a ClientSecret entry. This is the client Id that you generated on step 2&lt;/li&gt;
&lt;li&gt;The base address is where your API is hosted. Here is just localhost, and that works fine.&lt;/li&gt;
&lt;li&gt;The Scope is the one that you generated on step 3. If you don't remember what it was named, you can go to the Expose API menu under your &lt;em&gt;called API&lt;/em&gt;, there is a handy "copy to clipboard" button there.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now for the meat of the code you need, the client API code (requires &lt;em&gt;Microsoft.Identity.Client&lt;/em&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;IConfidentialClientApplication app = ConfidentialClientApplicationBuilder.Create(config.ClientId)
  .WithClientSecret(config.ClientSecret)
  .WithAuthority(new Uri(config.Authority))
  .Build();

string[] scopes = new string[] { config.Scope };

// get a token to access your called API
AuthenticationResult result = await app.AcquireTokenForClient(scopes).ExecuteAsync();
if (result != null)
{
  var httpClient = new HttpClient();
  var apiCaller = new ProtectedApiCallHelper(httpClient);
  var defaultRequestHeaders = httpClient.DefaultRequestHeaders;
  if (defaultRequestHeaders.Accept == null || !defaultRequestHeaders.Accept.Any(m =\&amp;amp;gt; m.MediaType == "application/json"))
  {
    httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
  }
  defaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", result.AccessToken);
  // call the API endpoint
  HttpResponseMessage response = await httpClient.GetAsync($"{config.BaseAddress}/the-secured-endpoint/you-are-trying-to-access");
  string returnValue = string.Empty;
  if (response.IsSuccessStatusCode)
  {
    returnValue = await response.Content.ReadAsStringAsync();
  }
  else
  {
    returnValue = response.StatusCode.ToString();
    string content = await response.Content.ReadAsStringAsync();
    // Note that if you got reponse.Code == 403 and reponse.content.code == "Authorization\_RequestDenied"
    // this is because the tenant admin has not granted consent for the application to call the Web API
    this.logger.LogError($"Content: {content}");
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And this is pretty much it. Do handle errors and all that jazz, this is not production ready code.&lt;/p&gt;

&lt;p&gt;As a caveat, I did a lot of reading and trial and error, so maaaybe there might be a missing step somewhere. Let me know if so and I'll try to remember what that was and add it for the next lost developer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Useful links
&lt;/h2&gt;

&lt;p&gt;I'll paste here a bunch of links where I read stuff from, in no particular order. Included is a GitHub repo with some code that you will recognize, especially the client API part.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/active-directory/develop/scenario-protected-web-api-overview"&gt;https://docs.microsoft.com/en-us/azure/active-directory/develop/scenario-protected-web-api-overview&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-configure-app-access-web-apis"&gt;https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-configure-app-access-web-apis&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/active-directory/develop/scenario-web-api-call-api-app-configuration?tabs=aspnetcore"&gt;https://docs.microsoft.com/en-us/azure/active-directory/develop/scenario-web-api-call-api-app-configuration?tabs=aspnetcore&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/active-directory/develop/scenario-daemon-overview"&gt;https://docs.microsoft.com/en-us/azure/active-directory/develop/scenario-daemon-overview&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-v2-netcore-daemon"&gt;https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-v2-netcore-daemon&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow"&gt;https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/active-directory/develop/howto-add-app-roles-in-azure-ad-apps"&gt;https://docs.microsoft.com/en-us/azure/active-directory/develop/howto-add-app-roles-in-azure-ad-apps&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Azure-Samples/active-directory-dotnetcore-daemon-v2/tree/master/2-Call-OwnApi"&gt;https://github.com/Azure-Samples/active-directory-dotnetcore-daemon-v2/tree/master/2-Call-OwnApi&lt;/a&gt;&lt;/p&gt;

</description>
      <category>azure</category>
      <category>activedirectory</category>
      <category>webapi</category>
    </item>
  </channel>
</rss>
