<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[cmatskas]]></title><description><![CDATA[Cloud, Security, Programming and Fitness]]></description><link>https://cmatskas.com/</link><image><url>https://cmatskas.com/favicon.png</url><title>cmatskas</title><link>https://cmatskas.com/</link></image><generator>Ghost 4.44</generator><lastBuildDate>Sun, 05 Apr 2026 01:03:14 GMT</lastBuildDate><atom:link href="https://cmatskas.com/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Fix "Cannot connect to the Docker daemon. Is the docker daemon running?" error]]></title><description><![CDATA[<p>I spent a good couple of hours trying to fix this error message. I have the latest version of Docker installed on my Mac M1 Max running Sonoma 14.3.1.</p><p>Every time I run a command that had to connect to the deamon, I was getting the same exact</p>]]></description><link>https://cmatskas.com/fix-cannot-connect-to-the-docker-daemon/</link><guid isPermaLink="false">65dfe402297b54274796d5a9</guid><category><![CDATA[docker]]></category><category><![CDATA[containers]]></category><category><![CDATA[troubleshooting]]></category><dc:creator><![CDATA[Christos Matskas]]></dc:creator><pubDate>Thu, 29 Feb 2024 02:58:11 GMT</pubDate><content:encoded><![CDATA[<p>I spent a good couple of hours trying to fix this error message. I have the latest version of Docker installed on my Mac M1 Max running Sonoma 14.3.1.</p><p>Every time I run a command that had to connect to the deamon, I was getting the same exact error:</p><pre><code class="language-bash">docker: Cannot connect to the Docker daemon at unix://Users/&lt;user&gt;/.docker/run/docker.sock. Is the docker daemon running?.
See &apos;docker run --help&apos;.</code></pre><p>This was not fun. But after a bit of googling (yes, ChatGPT etc couldn&apos;t help), I stumbled across the solution on this <a href="https://stackoverflow.com/a/74148162">StackOverflow post</a> </p><p>The cause of the problem is that at some point, Docker removed the <code>/var/run/docker.sock</code> symlink in default behavior. If you&apos;re curions, you can find more details about this in the Docker release notes <a href="https://docs.docker.com/desktop/release-notes/#docker-desktop-4130" rel="noreferrer">here</a> or you can skip straight to the fix</p><h3 id="the-fix">The fix</h3><p>We have to manually add a symlink You have to follow the steps below to fix the issue on your MacOS</p><ol><li>Quit the Docker Desktop app</li><li>Open your terminal, copy-paste the following and press Enter</li></ol><pre><code>sudo ln -s ~/Library/Containers/com.docker.docker/Data/docker.raw.sock /var/run/docker.sock</code></pre><p>3. Restart Docker Desktop<br>4. Run the following command to ensure that the symlink works</p><pre><code>DOCKER_HOST=unix:///var/run/docker.sock docker ps</code></pre><p>If everything worked as expected, the output should look similar to this: <br><code>CONTAINER ID &#xA0; IMAGE &#xA0; &#xA0; COMMAND &#xA0; CREATED &#xA0; STATUS &#xA0; &#xA0;PORTS &#xA0; &#xA0; NAMES</code></p><p>5. (optional) if you use <code>zsh</code> then you also need to update your <code>.zshrc</code> file and add the following setting:</p><pre><code>export DOCKER_HOST=unix:///Users/$USER/Library/Containers/com.docker.docker/Data/docker.raw.sock</code></pre><p>And that&apos; all there is to it. Now, you&apos;re good to start interacting with your Docker deamon</p>]]></content:encoded></item><item><title><![CDATA[Unleashing the power of Text to Voice using Amazon Polly and Python]]></title><description><![CDATA[<p>I recently had to come up with a solution to quickly turn text to voice and make it available as an MP3 file. Of course, being an AWS person, I knew exactly what to do! <a href="https://aws.amazon.com/polly/">Amazon Polly</a> to the rescue. Amazon Polly, is a simple to use service and, in</p>]]></description><link>https://cmatskas.com/getting-started-with-text-to-voice-using-amazon-polly/</link><guid isPermaLink="false">655408e1297b54274796d52d</guid><dc:creator><![CDATA[Christos Matskas]]></dc:creator><pubDate>Wed, 15 Nov 2023 00:21:10 GMT</pubDate><content:encoded><![CDATA[<p>I recently had to come up with a solution to quickly turn text to voice and make it available as an MP3 file. Of course, being an AWS person, I knew exactly what to do! <a href="https://aws.amazon.com/polly/">Amazon Polly</a> to the rescue. Amazon Polly, is a simple to use service and, in this blog post, I&apos;ll show you how to get started with using it in Python.</p><h2 id="what-is-amazon-polly">What is Amazon Polly?</h2><p>Amazon Polly is a text-to-speech service that uses advanced deep learning technologies to convert written text into lifelike speech. It comes with dozens of high-quality, natural-sounding voices in various languages. You can quickly test and find the one that meets your requirments and specific user case <a href="https://aws.amazon.com/polly/features/">here</a></p><p>The Polly is extremely simple and allows developers to quickly create applications that can interact with a human-like voice. Polly supports a wide range of use cases, from enhancing accessibility in applications to creating engaging voiceovers for multimedia content.</p><h2 id="getting-started-with-amazon-polly-in-python">Getting Started with Amazon Polly in Python:</h2><h3 id="step-1-set-up-your-aws-account">Step 1: Set Up Your AWS Account</h3><p>Before diving into Amazon Polly, ensure you have an AWS account. Set up an IAM (Identity and Access Management) user with the necessary permissions to interact with Polly. The best policy that allows all actions except deleting of Lexicons is shown below:</p><pre><code>{
   &quot;Version&quot;: &quot;2012-10-17&quot;,
   &quot;Statement&quot;: [{
      &quot;Sid&quot;: &quot;AllowAllActions-DenyDelete&quot;,
      &quot;Effect&quot;: &quot;Allow&quot;,
      &quot;Action&quot;: [
         &quot;polly:DescribeVoices&quot;,
         &quot;polly:GetLexicon&quot;,
         &quot;polly:PutLexicon&quot;,
         &quot;polly:SynthesizeSpeech&quot;,
         &quot;polly:ListLexicons&quot;],
      &quot;Resource&quot;: &quot;*&quot;
      }
      {
      &quot;Sid&quot;: &quot;DenyDeleteLexicon&quot;,
      &quot;Effect&quot;: &quot;Deny&quot;,
      &quot;Action&quot;: [
         &quot;polly:DeleteLexicon&quot;],
      &quot;Resource&quot;: &quot;*&quot;
      }
   ]
}</code></pre><h3 id="step-2-install-boto3">Step 2: Install Boto3</h3><p>Boto3 is the AWS SDK for Python, and you&apos;ll need it to interact with Polly. Install it using the following command:</p><pre><code class="language-bash">pip install boto3
</code></pre><h3 id="step-3-create-a-polly-client">Step 3: Create a Polly Client</h3><p>In your Python script, create a Polly client using the Boto3 library:</p><pre><code class="language-python">import boto3

# Create a Polly client
polly_client = boto3.client(&apos;polly&apos;, region_name=&apos;your-region&apos;)
</code></pre><h3 id="step-4-synthesize-speech">Step 4: Synthesize Speech</h3><p>Now, you can use Polly to synthesize speech from text:</p><pre><code class="language-python">audiofile= &apos;voicefile.mp3&apos;

response = polly_client.synthesize_speech(
    Text=&apos;Hello, you are now using Amazon Polly!&apos;,
    VoiceId=&apos;Joanna&apos;,
    OutputFormat=&apos;mp3&apos;
)

# Save the audio file
file = open(audiofile, &apos;wb&apos;)
file.write(response[&apos;AudioStream&apos;].read())
file.close()
</code></pre><p>Putting it all together, including the ability to output the audio file using your system&apos;s audio device can be found in this gist</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://gist.github.com/cmatskas/bbe15a32f91d57418e5d04f9a1a820fd"><div class="kg-bookmark-content"><div class="kg-bookmark-title">amazon_polly_python</div><div class="kg-bookmark-description">amazon_polly_python. GitHub Gist: instantly share code, notes, and snippets.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://gist.github.com/fluidicon.png" alt><span class="kg-bookmark-author">Gist</span><span class="kg-bookmark-publisher">262588213843476</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://github.githubassets.com/assets/gist-og-image-54fd7dc0713e.png" alt></div></a></figure><h2 id="conclusion">Conclusion</h2><p>Amazon Polly, coupled with the versatility of Python, provides an easy, low friction, and affordable way to integrate text-to-speech capabilities into your applications. Whether you&apos;re building a voice-driven application, adding accessibility features, or creating engaging multimedia content, Amazon Polly is the service for you :)</p>]]></content:encoded></item><item><title><![CDATA[Secretless Python Apps with AWS Secrets Manager]]></title><description><![CDATA[<p>The <a href="https://aws.amazon.com/secrets-manager/">AWS Secrets Manager</a> is a service that allows users to securely store and manage secrets, such as database credentials and API keys. This is necessary when building any type of application that needs to interact with other services, regardless if you&apos;re using Python or any other language.</p>]]></description><link>https://cmatskas.com/secretless-python-apps-with-aws-secrets-manager/</link><guid isPermaLink="false">63939021297b54274796d4d5</guid><dc:creator><![CDATA[Christos Matskas]]></dc:creator><pubDate>Fri, 09 Dec 2022 20:03:09 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1614064641938-3bbee52942c7?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDZ8fGxvY2t8ZW58MHx8fHwxNjcwNjE2MjQx&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1614064641938-3bbee52942c7?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDZ8fGxvY2t8ZW58MHx8fHwxNjcwNjE2MjQx&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="Secretless Python Apps with AWS Secrets Manager"><p>The <a href="https://aws.amazon.com/secrets-manager/">AWS Secrets Manager</a> is a service that allows users to securely store and manage secrets, such as database credentials and API keys. This is necessary when building any type of application that needs to interact with other services, regardless if you&apos;re using Python or any other language. By keeping sensitive information out of your codebase and in Secret Manager, you reduce the risk of it being exposed and allows for central management of all secrets, including auditing, auto-rotation and fine-tuned access controls...</p><p>To use the Secrets Manager with Python, you will first need to create a secret that contains the sensitive information you want to store. This can be done through the AWS Management Console, the AWS CLI, or the AWS Secrets Manager API. In this instance, we&apos;ll use the AWS CLI to create a secret:</p><pre><code class="language-bash">aws secretsmanager put-secret-value \
    --secret-id &quot;my-secret&quot; \
    --secret-string &quot;my-secret-value&quot; \
    --region &quot;us-east-1&quot;</code></pre><p>Once you have created a secret, you can retrieve its value using the AWS Secrets Manager Python client. To do this, you will need to install the <code>boto3</code> library, which is the official Python library for AWS. Why <code>boto3</code> and not a more descriptive, meaningful name, is beyond me. Next, we need to import the <code>client</code> class from the <code>boto3.secretsmanager</code> module.</p><pre><code class="language-python"># Create an instance of the client class
secrets_manager_client = client()

# Retrieve the secret&apos;s value
secret_value = secrets_manager_client.get_secret_value(SecretId=&quot;my-secret&quot;)</code></pre><p>Once you have retrieved the secret&apos;s value, you can use it in your Python code as needed. For example, if the secret contains a database password, you could use it to connect to the database using the <code>psycopg2</code> library.</p><pre><code class="language-python"># Import the connect() function from the psycopg2 library
from psycopg2 import connect

# Connect to the database using the secret value
database_connection = connect(
    host=&quot;database-host&quot;,
    database=&quot;database-name&quot;,
    user=&quot;database-user&quot;,
    password=secret_value[&quot;SecretString&quot;]
)</code></pre><h2 id="improve-the-security-posture-of-your-app">Improve the security posture of your app</h2><p>To further improve the security posture of your app, it&apos;s highly recommended to use a specific AWS account and a locked down IAM policy. To create an AWS IAM read-only policy for a secret called &quot;my-secret&quot; in Secrets Manager, you can use the following policy statement:</p><pre><code class="language-json">{
    &quot;Version&quot;: &quot;2012-10-17&quot;,
    &quot;Statement&quot;: [
        {
            &quot;Sid&quot;: &quot;AllowReadingOfMySecret&quot;,
            &quot;Effect&quot;: &quot;Allow&quot;,
            &quot;Action&quot;: [
                &quot;secretsmanager:GetSecretValue&quot;
            ],
            &quot;Resource&quot;: [
                &quot;arn:aws:secretsmanager:&lt;region&gt;:&lt;account-id&gt;:secret:my-secret-*&quot;
            ]
        }
    ]
}</code></pre><p>This policy allows the IAM user or role to which it is attached to only read the value of the secret with the identifier &quot;my-secret&quot; using the <code>GetSecretValue</code> action. It also allows the user or role to list the versions of the secret using the <code>ListSecretVersionIds</code> action.</p><p>Make sure to replace <code>&lt;region&gt;</code> and <code>&lt;account-id&gt;</code> with the appropriate values for your AWS account. You can also customize the policy by adding or removing actions and resources (like more secrets that are used by your app) as needed.</p>]]></content:encoded></item><item><title><![CDATA[Deploying a Ghost blog to AWS Lightsail]]></title><description><![CDATA[<p>It was about time to try a new hosting option for my blog. For the past few years I was running my blog on Azure WebApps Container service. It was OK but the setup was pretty complex and once it was deployed I totally forgot how to replicate the setup</p>]]></description><link>https://cmatskas.com/deploy-ghost-blog-to-aws-lightsail/</link><guid isPermaLink="false">631b7ddd4e615c07ca3eb17a</guid><dc:creator><![CDATA[Christos Matskas]]></dc:creator><pubDate>Mon, 12 Sep 2022 19:27:46 GMT</pubDate><content:encoded><![CDATA[<p>It was about time to try a new hosting option for my blog. For the past few years I was running my blog on Azure WebApps Container service. It was OK but the setup was pretty complex and once it was deployed I totally forgot how to replicate the setup - maybe I should have blogged about it.</p><p>Since I moved to AWS I&apos;ve been looking into the various services and <a href="https://aws.amazon.com/lightsail/">Lightsail</a> seemed very promising for my needs. Lightsail is a lightweight, low cost (pun intended) but truly capable service for hosting web apps. It comes with a number of integrations, called <strong>blueprints </strong>and supports both Linux and Windows OS with Windows being slightly more expensive. One of the Blueprints supported is Ghost, albeit still on version 4.4.x at the time of writing this blog .</p><h2 id="create-a-ghost-instance">Create a Ghost Instance</h2><p>Let&apos;s see what it takes to spin up an instance to run a Ghost blog! In the AWS Console, select Lightsail. This will actually open a new tab on your browser. We need to follow 4 basic steps to spin up our instance:</p><ol><li>Select the OS flavor</li></ol><figure class="kg-card kg-image-card kg-width-wide"><img src="https://cmatskas.com/content/images/2022/09/2022-09-12_15-51-37.png" class="kg-image" alt loading="lazy" width="1285" height="608" srcset="https://cmatskas.com/content/images/size/w600/2022/09/2022-09-12_15-51-37.png 600w, https://cmatskas.com/content/images/size/w1000/2022/09/2022-09-12_15-51-37.png 1000w, https://cmatskas.com/content/images/2022/09/2022-09-12_15-51-37.png 1285w" sizes="(min-width: 1200px) 1200px"></figure><p>2. Select the Blueprint you want - in this instance Ghost</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://cmatskas.com/content/images/2022/09/2022-09-12_15-52-36.png" class="kg-image" alt loading="lazy" width="1043" height="840" srcset="https://cmatskas.com/content/images/size/w600/2022/09/2022-09-12_15-52-36.png 600w, https://cmatskas.com/content/images/size/w1000/2022/09/2022-09-12_15-52-36.png 1000w, https://cmatskas.com/content/images/2022/09/2022-09-12_15-52-36.png 1043w"></figure><p>3. Choose the instance size - it&apos;s an EC2 instance under the hood anyway</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://cmatskas.com/content/images/2022/09/image.png" class="kg-image" alt loading="lazy" width="1197" height="663" srcset="https://cmatskas.com/content/images/size/w600/2022/09/image.png 600w, https://cmatskas.com/content/images/size/w1000/2022/09/image.png 1000w, https://cmatskas.com/content/images/2022/09/image.png 1197w"></figure><p>4. Give it a meaningful name</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://cmatskas.com/content/images/2022/09/image-1.png" class="kg-image" alt loading="lazy" width="1256" height="703" srcset="https://cmatskas.com/content/images/size/w600/2022/09/image-1.png 600w, https://cmatskas.com/content/images/size/w1000/2022/09/image-1.png 1000w, https://cmatskas.com/content/images/2022/09/image-1.png 1256w" sizes="(min-width: 1200px) 1200px"></figure><p>Wait for a few minutes and you should have your Ghost instance up and running.</p><h2 id="add-a-static-ip-address">Add a static IP address</h2><p>Once your instance is available, you&apos;ll need to add a static IP address to make it available to internal or external DNS providers. My DNS service is Cloudflare and I already own a domain, so a static IP address is needed to map my domain to my blog running in Lightsail. </p><p>Back at the Lightsail home, select the <strong>Networking </strong>and press the <strong>Create Static IP</strong> button</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://cmatskas.com/content/images/2022/09/image-2.png" class="kg-image" alt loading="lazy" width="1103" height="1093" srcset="https://cmatskas.com/content/images/size/w600/2022/09/image-2.png 600w, https://cmatskas.com/content/images/size/w1000/2022/09/image-2.png 1000w, https://cmatskas.com/content/images/2022/09/image-2.png 1103w"></figure><p>See it in action below:</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2022/09/2022-09-09_16-24-07--1-.gif" class="kg-image" alt loading="lazy" width="720" height="612"></figure><h2 id="weird-things-i-had-to-do">Weird things I had to do</h2><p>Since this was a migration and not a straight up new blog site, I was imported my content, via the old exported json file, to the new blog just fine. However, I had over 10 years worth of images that couldn&apos;t be uploaded via the Ghost admin portal.</p><p>For that, I had to use SFT with SSH. Filezila connected fine to the remote instance but the <code>bitnami</code> account lacked the appropriate permissions to create folders and upload files. </p><p>I had to spin up an SSH session and use the following commands to give the <code>bitnami</code> account the <code>write</code> permissions to the <strong>images </strong>folder:</p><pre><code>sudo chown bitnami &lt;your folder name&gt;
sudo chmod +w &lt;your folder name&gt;</code></pre><p>Note that the username is <code>bitnami</code> and the SSH private key you can acquire</p><p>The second issue I encountered is that all the image URLs were resolving to <code>http://localhost/....</code>. I knew that this was a configuration issue somewhere. First I looked for any weird hardcoded values, since I was editing and developing the blog locally prior to uploading the updated template. However, I quickly ruled out the hardcoded values and I worked out that the images where using the https://cmatskas.com variable which gets populated from the <code>config.production.json</code> file. </p><p>Back in my SSH session, this is what I had to do:</p><ol><li>Open the file in VI with: <code>sudo vi config.production.json</code></li><li>Update the URL with the right domain name, i.e <code>https://cmatskas.com</code> - note that the old value was the original public IP address of the Lightsail instance which didn&apos;t resolve to anything since I configured a static IP address</li><li>Restart both Ghost and Apache with the following commands:</li></ol><pre><code>sudo /opt/bitnami/ctlscript.sh restart ghost
sudo /opt/bitnami/ctlscript.sh restart apache</code></pre><h2 id="custom-domain">Custom domain</h2><p>Configuring a custom domain is really straightforward. I use Cloudflare both for SSL termination and for domain name management. Since <code>cmatskas.com</code> is already registered with Cloudflare, what I needed to do was remove the old DNS mappings, some A and CNAME records and add two new A records to point to my Lighsail instance. </p><p>In Cloudflare, navigate to your DNS section and add an A Record &#xA0;for the root and www versions of your website that point to the static IP address configured on your Lightsail instance. This is what mine looks like:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://cmatskas.com/content/images/2022/09/2022-09-12_15-24-27-2.png" class="kg-image" alt loading="lazy" width="1355" height="415" srcset="https://cmatskas.com/content/images/size/w600/2022/09/2022-09-12_15-24-27-2.png 600w, https://cmatskas.com/content/images/size/w1000/2022/09/2022-09-12_15-24-27-2.png 1000w, https://cmatskas.com/content/images/2022/09/2022-09-12_15-24-27-2.png 1355w" sizes="(min-width: 1200px) 1200px"></figure><p>Job done....</p><h3 id="lingering-issues">Lingering issues</h3><p>I still need to work out why <code>http</code> requests to my domain don&apos;t resolve properly and end up in 127.0.0.1. If you&apos;re a DNS wizard and can help out with that, please do let me know what I&apos;ve done wrong, because as we all know... IT&apos;S ALWAYS DNS!!!</p>]]></content:encoded></item><item><title><![CDATA[Random notes of a new Triathlete]]></title><description><![CDATA[<p>What craziness could have possibly possessed me to start training for a triathlon at the age of 43? If you know me then you know that I&#x2019;ve been a fitness fanatic for many years. While younger I preferred to play team sports (football (soccer), basketball etc) as I</p>]]></description><link>https://cmatskas.com/random-notes-of-a-triathlete/</link><guid isPermaLink="false">631b77ad4e615c07ca3eacf1</guid><category><![CDATA[sports]]></category><category><![CDATA[fitness]]></category><category><![CDATA[triathlon]]></category><category><![CDATA[training]]></category><dc:creator><![CDATA[Christos Matskas]]></dc:creator><pubDate>Tue, 12 Jul 2022 19:02:46 GMT</pubDate><content:encoded><![CDATA[<p>What craziness could have possibly possessed me to start training for a triathlon at the age of 43? If you know me then you know that I&#x2019;ve been a fitness fanatic for many years. While younger I preferred to play team sports (football (soccer), basketball etc) as I grew older I started focusing more on weight training and doing things on my own. I like the freedom and control of what, when and where. I&#x2019;m a master of my own fate, with all the flaws and issues that come with it.</p><p>Over the past few years, I built a decent home gym that contains most of the equipment I need to be train. Squat rack, bars and plates, dumbbells, platforms, pull up bars etc. Training has been good with a steady progress and I&#x2019;ve managed to hit some good numbers across most of the major lift. Nonetheless, there is only so much you can achieve with training for 1hr, 3-4 days a week. My goal has always been to be fit and healthy to enjoy life. I&#x2019;ve never idolized size or the strength that comes with it. Functional strength and flexibility do real-world activities without running out of breath is nice. Also, working out allowed me to be more liberal with my diet and eat &#x201C;unhealthy&#x201D; &#xA0;sometimes - as to enjoy life. I mean, I&#x2019;d love visible abs and a 6-pack like everyone else but</p><ul><li>Sustaining a &lt; 10% body fat in real world is hard / unreasonable</li><li>I like my food</li><li>I have too much hair to even show a six pack, LOL</li></ul><p>Ok.. enough with weight training, although if you are curious and want to discuss, hit me up</p><h3 id="why-triathlons-then">Why triathlons then?</h3><p>Back to my original question&#x2026; how did I get here? Last summer (Jul &#x2019;21) in the middle of the COVID pandemic I picked up David Goggin&#x2019;s book - Can&#x2019;t Hurt Me. David is an insane person and his book is definitely worth the read. He&#x2019;s incredibly motivational and inspiring although some (many) of his methods are extreme and dangerous (please seek advice from your physician and trainer if you&#x2019;re going to embark in David-style training - seriously). Regardless of methodology, the book offer some great gems of wisdom and it spoke to me. So much so that before I even finished the book, I signed up for a triathlon!!! At least I talked myself out of an IronMan because that would have been crazy :) A triathlon was something totally out of my comfort zone. I&#x2019;ve done weight training for the past 15 years with very little cardio, apart from the occasional weighted HIIT. So this was an opportunity to reinvent myself, find my limits and push past them. I chose something that was within my grasp yet far enough and challenging to make me (and my family) question my life choices - LOL</p><h3 id="what-is-a-triathlon">What is a triathlon</h3><p>A triathlon (as the name indicates - if you&#x2019;re Greek then you know what I&#x2019;m talking about) is 3 sports in one all happening sequentially on the same day:</p><ol><li>Swimming</li><li>Cycling</li><li>Running</li></ol><p>Depending on the event, the distance for each differs. And if you&#x2019;re ready for a bigger challenge, then you can graduate to a half or full IronMan.</p><p>Did I mention that I hate(d) all of the above sports? Yes, I hate running with a vengeance and yet if you ask me today to go for an 8mi run, I can do it without an issue. I also sucked at swimming because I didn&#x2019;t know how to swim. Swim lessons are your friend no matter your ability. Swimming is absolutely awesome once you&#x2019;re comfortable in the water. I went from barely being able to do one length in the pool without running out of breath and feeling like I did a 100m sprint to being able to swim 2500m in open water unbroken or racing for 1mi. Cycling - I hadn&#x2019;t been on a bike since 2007 and I didn&#x2019;t even own a bike before starting triathlon training. I can now put 50-60mi where I can average 20-22mph and still be able to go for a run right after it.</p><h3 id="training-coaching">Training / Coaching</h3><p>I made the best decision of my life to hire a coach - my coach is Paul Rakness and he&apos;s simply awesome. I wanted a certified and successful coach to guide me through the experience. Yes, I could have done it myself. There are plenty of programs available online but for me my coach has been invaluable on this journey. Besides scheduling everything for me and touching base regularly on how I&#x2019;m doing, we continuously adjust and adapt my program to fit my work and family needs. So if I&#x2019;m too busy with work one day or I have to skip a workout due to traveling or illness, he adjust my schedule so that I can hit my milestones. Paul is a fantastic coach not so much for the programming (although he&#x2019;s ace at that too) but because he takes the uttermost care to keep me healthy and fit to continue my training. This is vitally important because it&#x2019;s easy to go too hard and too fast and injure yourself, especially if you&#x2019;re old like me. At 43 I&#x2019;m feeling that my recovery has slowed down and progress is slower. In the past 10 months, despite Paul&#x2019;s best efforts, I did hit a few health snags that required an MRI, two specialist visits and multiple physiotherapist sessions to nurture me back to health. This meant that Paul had to work around my physical limitation and keep me on track despite the fact that I couldn&#x2019;t run for an extended period of time. It&#x2019;s also worth mentioning that Paul really &#x201C;hates&#x201D; me and sometime I can tell based on my workouts. Like - this guy really wants to kill me!!! If you&#x2019;ve done an FTP, then you know what I&#x2019;m talking about. Joking aside, he&#x2019;s helped me push myself while being supporting and encouraging every step of the way :D</p><p>My coach has also been an important advisor when it comes to nutrition and equipment - because both can be expensive if you don&#x2019;t know what you&#x2019;re doing. More on this in a bit. In any case, if you plan on starting Triathlon training (or any other sport) get a qualified coach, it will be the best money you spend.</p><p>In addition, paying for training creates accountability which itself enforces consistency. Finally, there is a second element of accountability: reporting. Everything I do gets recorded and reviewed by Paul. Therefore, if I miss a session there better be a good excuse!! More than money, knowing that Paul expects me to hit certain goals means forces me to stay on track. It sounds funny but I don&#x2019;t want to disappoint my coach or myself and this is a great incentive&#x2026;</p><p>Paul, when you read this, now that I&#x2019;m extremely grateful for having you by my side along the way and for helping me get closer to my true potential. I would&#x2019;t be here without you!</p><h3 id="equipment">Equipment</h3><p>No matter what sport you choose to participate in, you have to spend some money. Now imagine signing up for 3 sports at once! I&#x2019;m lucky my wife hasn&#x2019;t divorced me yet with all the new equipment I had to buy. I will explain my approach below but everyone&#x2019;s different. At minimum you need a bike (any bike - although a good bike does make a difference), running shoes and a swim suit. Let&#x2019;s break it down:</p><p><strong>Cycling</strong></p><p>I bought a second hand Specialized gravel bike for my triathlons. I then put some intermediate tubeless tires (big mistake) and power pedals. Before spending serious time on the bike, I also got a bike fit. There are specific shops that can fit the bike to your body type and needs. I spent nearly 4hrs finding the right saddle as well as repositioning everything to fit my body and style of cycling. Again, if you are serious about this, I would highly recommend getting your bike fitted. Solid advise from Paul. I also bought a <a href="https://www.wahoofitness.com/devices/bike-computers/elemnt-bolt">Wahoo Element</a> bike computer to track my cycling when outdoors. However, 90% of my training has been indoors, spent on a bike trainer, the <a href="https://www.wahoofitness.com/devices/indoor-cycling/bike-trainers/kickr">Wahoo Kickr</a>. Why? Because I live in the PNW where the weather is awful for the majority of the year and having a trainer allows me to be more flexible with my schedule. I can wake up at 5.30am and hit my workout from the comfort of my garage. No rain, no cold, no special lights, no danger getting hit by cars etc etc. A trainer also allows me to work off the raw power output (Watts) and target my workouts on specific targets to build stamina and strength. Without power pedals (which I had to hold off buying for nearly 9 moths) a trainer is perfect. It is a costly investment but totally worth it, especially if you don&#x2019;t get nice weather or have nice bike tracks where you live. There is an associated cost for Zwift which is the app that allows you to virtually cycle anywhere in the world and connects with the bike trainer to adjust resistance based on altitude etc. Again, I happily pay for this for the convenience and safety that it offers. Finally you need clothes. You know, the cycling, lycra type ones that are super tight and less flattering. But they come with padding and help with absorbing sweat with clever pockets to put phones and nutrition so, highly worth the investment. There is a price range and you need to find the ones that fit you best and make you feel comfortable on the bike. And let&#x2019;s not forget the shoes - the ones that clip on the pedals. I tried several pairs and since I have wide feet it took a bit of research. I spent the first 9 months with numb feet on the bike. I pushed through it thinking it&#x2019;s fine until my first race T-run ( a transition run from the bike to the run) where I could barely run because I couldn&#x2019;t feel my feet. Stupidity comes at a price. I exchanged them the next day for a pair that actually fits my feet.</p><p><strong>Running</strong></p><p>Running is much easier. All you need is a good pair of shoes and some comfortable clothing. But you also need something to track your runs and your fitness. My shoes are Nike. I&#x2019;m a Nike person and no matter what else I try, I always come back to Nike because I&#x2019;m either used to them or they fit me the best. In any case, I run best on Nikes. For tracking my runs and fitness, I went with the <a href="https://www.wahoofitness.com/devices/sport-watches/elemnt-rival">Wahoo Rival</a> watch. I finally ditched my Apple Watch after 5 years of dutiful service. The Wahoo watch is great. Price wise comes at mid-range (when compared to the high-end Garmin ones for example) at $329 and can track Triathlon activities, including races. And even though it&#x2019;s optimized for Triathlons it works for most other sports as well and has a great companion phone app. It provides enough smart elements to allow me to stay connected with my phone as well through txt messages and phone calls - which is really all I want from my watch anyway. I also picked up the <a href="https://www.wahoofitness.com/devices/heart-rate-monitors/tickr-x-buy">Wahoo Tickr</a> HR monitor from Wahoo as the watch is not perfect at tracking my HR and when I&#x2019;m on the bike trainer I don&#x2019;t use my watch (double tracking) so I needed a way to reliably and consistently track my HR. I also sweat a lot so I got a head band (like Rambo) to keep the sweat from getting into my eyes. I look silly but I don&#x2019;t really care about appearances anyway :) For longer runs, I have a water bladder in a backpack to keep me hydrated as I run hot and I need water and electrolytes</p><p><strong>Swimming</strong></p><p>Swimsuit, googles and a gym with a pool (or your own pool if you&#x2019;re wealthy). Speedo seems to be the de facto one for swimsuits so I got that. For goggles, I started with off the shelf stuff but I now love my Magic5 which are built around your face. I just ordered a second pair since I lost mine after my last race :( . Most of my workouts take place in the pool, either solo or with my team. However, endless hours in the pool cannot replace OWS (open water swims). I hated swimming and I hated deep water. I had a fear of the unknown and not being able to see what&#x2019;s below me. I grew up swimming in Greece where most of the beaches have crystal clear water. As soon as I lose that I literally panic and swim back to the safety of the clear water. Fear of the unknown is also accentuated by the lack of skill. I mean, if I can barely do a length (25m) in the pool without running out of breath, how the hell can I feel comfortable swimming in open water - ALONE??? </p><p>My first open water experience was 1 month into my training with my coach. We were supposed to do 400m in one of the nearby lakes in early October. I accepted the invite because there is no way I can say NO to Paul! We arrived at 8am, I put my wetsuit on and got in the (cold) water. The wet suit, which I was wearing for the first time in my life BTW, did a great job job in keeping me from going hypothermic but, on the inside, I was freaking out. As soon as I got submerged, I started hyperventilating, I couldn&#x2019;t see a foot ahead of me, it was dark, rainy and cold. Further more, I didn&#x2019;t know how to do sighting (watch where you&apos;re going) and I could barely swim. As you can imagine, this went great!!! LOL Fast forward 7 months and I can now jump in any lake (yes any lake) and swim a mile comfortably on my own. I do have an inflatable buoy with I attach to my waste and drag behind me, in case I get a cramp or I need a break. For reference, I&#x2019;ve only used it once to stop and adjust my goggle. A 1500m OWS is now pretty standard and I feel that I can hit much longer distances with ease. I&#x2019;m still working on improving my form and getting better and more efficient but based on my last two races, apparently the swim is my strongest suit even at this shitty, less efficient form. Back to the equipment bit, you need a wetsuit (I was lucky to get a good second hand one) and a buoy if you plan on doing OWS regularly on your own.</p><h3 id="joining-an-imtriathlon-team">Joining an IM/Triathlon team</h3><p>Initially I wasn&apos;t convinced but after a bit of persuasion from my coach, I decided to join my local team (PR Performance). The team consists of some amazing coaches and athletes all focused on similar goals so it&#x2019;s a great place to be. The team does many activities together, including organized swims and running track workouts. When time permits it, I try to join these as I get invaluable advice and new challenges to help me improve my fitness level and form in these sports. In addition, as a team we get discounts for gear from major IM brands so every little helps. Finally, it&#x2019;s not uncommon for many team mates to show up at the same event which I find nice as I have a familiar face to talk to. After being with the team for 10months, I could recommend that you join a team as well, if that&#x2019;s something available to you. Optional, but highly beneficial.</p><h3 id="nutrition-and-diet">Nutrition and diet</h3><p>An average workout burns about 1000 calories! I haven&#x2019;t been extremely careful with my diet. I haven&#x2019;t counted calories, micro or macro nutrients and yet, it&#x2019;s the first time in my life I feel and look better. My weight has dropped down a bit (and could drop even further if I focused on my diet) but at the same time, I haven&#x2019;t had to sacrifice anything and I can eat whatever the rest of the family eats. Carbs are super important and has been a big focus during my training and races. This is great because every other diet hates carbs and overindexes on protein and fats. For the past 10 months even been eating normally and I feel great. During training, I have to consume carbs so energy gels, bananas and bars are always in my fitness pantry. The problem is that it gets expensive quickly so you have to find the stuff that works for you and buy in bulk to save money. &#xA0;Another important thing you need in your diet is electrolytes and salt (tablets). Drinking plain water won&#x2019;t cut it so you need to also invest in decent electrolytes and salt tablets to ensure that you stay at peak performance throughout the workout or the race. Talking about racing, nutrition is a bit of a thorny subject for me since I cannot intake all the food I need. Pre-race I only have some light solid carbs to get my digestive system working and ensure I have a #2 before I leave the house. This works great. But once at the race ground and during the race, I struggle to intake enough food as I&#x2019;m so focused on the race and my stomach can&#x2019;t tolerate much food especially since everything is SO SWEET. I need something with blunt taste that I can down easily and I&#x2019;m still searching for it! This is something I definitely need to work on.</p><h3 id="competing">Competing</h3><p>I signed up for a Tri race without knowing what to expect. Lake Whatcom did not disappoint! After putting the work for 10 months, I was able to complete my first Olympic Triathlon in 3hrs and 11mins based on my watch and I&#x2019;m still waiting on the official race results. I went from not being able to do any of the 3 sports well (or at all) to competing with 100s of other people, but mostly competing against myself. I didn&#x2019;t finish top at the event or my age group this time around, but it was a major accomplishment to be able to race without suffering any major injuries or a DNF (Did Not Finish). I learned some important lessons about what we need to do in my training going forward to improve overall and I had a lot of fun pushing myself. Taking inspiration for David Goggins (what started all this) I was able to overcome physical and mental obstacles to finish strong! This was my 2nd Triathlon, with Lake Wilderness being my first, albeit a Sprint one and the 3 competitive event overall. I did run my very first half-marathon in March. A lot of firsts this year. A lot of opportunities to learn, grow and improve.</p><h3 id="general-notes">General notes</h3><p>Triathlons are very different! In comparison to my weight lifting training, I always feel great after my triathlon workouts. I rarely feel in pain (unless injured) and I can spend the rest of my day being productive instead of having sore, broken muscles from lifting heavy things. After 10 months of consistent training, I have to admit that I enjoy this type of workout over anything else - to the point that I&#x2019;m selling off all my old gym equipment. If you&#x2019;re near Sammamish, WA and want to do a local pickup, let me know and I can send you a list of all my immaculate gym equipment that is sitting idle in my garage feeling unloved :D. This was the &#x201C;little&#x201D; bit. It takes a lot of consistency and effort. This is the first time in my life that I&#x2019;ve been training 6 days a week for 10 months non stop. OK, Paul will say that Training Peaks says otherwise and I will agree that I have been known to miss a day here and there, but for the majority of time I try really hard to stick to my schedule, with all the changes and tweaks that real life dictates.</p><p>I need to get better at working out early in the morning. Early mornings during the summer are easier but getting up at 5.30am on a cold winter&#x2019;s day is somehow infinitely more challenging. I would say that for the majority of my workouts, I manage to do them before 5pm and I rarely workout after 8pm as it&#x2019;s not good for my body. Running and cycling are easier as I can do them at home or near my house but driving to the pool is what kills me. I think I need a pool in my back yard&#x2026;.LOL</p><p>I&apos;m always wet!! I sweat too much during my workouts, I&#x2019;m in the water swimming or I&apos;m taking yet another shower &#xA0;- some days have double workouts. There are gym clothes hanging to dry ALL THE TIME, but at least I don&#x2019;t burden my wife with this task. She&#x2019;s already tolerating too much of me and my hobbies</p><p>It&#x2019;s an expensive sport, despite my coach claiming I have spent the least amount of money of anyone that he knows in this sport. If you&#x2019;re clever you can save some money by getting second half stuff but certain things you need to buy new. Like a decent bike etc etc. Start small and build up. This is what I&#x2019;ve been doing in the past year but I would say overall I&#x2019;ve spent around $5-6k so far. Next year I&#x2019;ll probably spend more as I need to get a better bike</p><p>Family support is extremely important. It&#x2019;s hard enough to have to fight with yourself for motivation. It&#x2019;s much harder having to fight with family for the time needed for all this. Training for a triathlon requires a lot of hours away from family. This is another reason why early morning workouts are great - you don&#x2019;t have to sacrifice time with family. &#xA0;</p><p>I wouldn&#x2019;t have been able to get where I am today without the unending support and understanding of my family. My wife, beyond not complaining about all the new gear I had to buy, has been incredibly supportive of my goals and has been there with me every step of the way. If there is something I look forward to at every race is seeing my wife and kids waiting for me at the finish line. No medals or recognition can beat that - a massive thank you and all my love to my wife and kids for believing in me!</p><p>Looking into the future, I definitely want to get better at competing in Triathlons and eventually move up to a half-Ironman, assuming my body is aligned to my plans. If you&apos;ve made it this far, I hope you enjoyed reading this and that it will inspire you to pick your own challenges (mental or physical) to get you out of your comfort zone and push you beyond what you thought was ever possible. And don&apos;t forget to have fun while doing it!</p>]]></content:encoded></item><item><title><![CDATA[Windows Terminal - from a developer for developers]]></title><description><![CDATA[<p>If you&apos;re like me, then I&apos;m sure that you want to ensure that your tools are tweaked and customized to look exactly like you want. Because nice tools make us more productive, right, RIGHT?</p><p>In this blog post, we&apos;ll see how to take our</p>]]></description><link>https://cmatskas.com/windows-terminal-from-a-developer-for-developers/</link><guid isPermaLink="false">631b77ad4e615c07ca3eacee</guid><dc:creator><![CDATA[Christos Matskas]]></dc:creator><pubDate>Thu, 17 Mar 2022 00:25:03 GMT</pubDate><content:encoded><![CDATA[<p>If you&apos;re like me, then I&apos;m sure that you want to ensure that your tools are tweaked and customized to look exactly like you want. Because nice tools make us more productive, right, RIGHT?</p><p>In this blog post, we&apos;ll see how to take our Windows Terminal with PowerShell Core to the next level :)</p><h2 id="what-we-need-to-install">What we need to install</h2><ul><li>Windows Terminal Icons</li><li>Custom Fonts</li><li>Posh-Git</li><li>Oh My Posh</li></ul><p>Most of these are straight downloads and installs with PoSh - using PoSH to make PoSH nice!</p><h2 id="install-the-windows-terminal-icons">Install the Windows Terminal Icons</h2><p>Open Terminal and run the following command:</p><pre><code class="language-PowerShell">Install-Module -Name Terminal-Icons -Repository PSGallery</code></pre><p>Then edit your <code>$Profile</code> using your favorite editor - I&apos;ll use VS Code, so it will be <code>code $profile</code></p><p>Add this line at the top: <code>Import-Module -Name Terminal-Icons</code></p><p>Restart your Terminal for this to take effect and you should see something similar to this:</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2022/03/image-1.png" class="kg-image" alt loading="lazy" width="1924" height="765" srcset="https://cmatskas.com/content/images/size/w600/2022/03/image-1.png 600w, https://cmatskas.com/content/images/size/w1000/2022/03/image-1.png 1000w, https://cmatskas.com/content/images/size/w1600/2022/03/image-1.png 1600w, https://cmatskas.com/content/images/2022/03/image-1.png 1924w" sizes="(min-width: 720px) 720px"></figure><h2 id="install-custom-fonts">Install Custom Fonts</h2><p>Most developers prefer clean, easy to read and work with fonts with ligatures. There are many fonts out there but few that meet all these requirements. Luckily, [NerdFonts](<a href="https://www.nerdfonts.com/font-downloads">Nerd Fonts - Iconic font aggregator, glyphs/icons collection, &amp; fonts patcher</a>) have done a fantastic job in aggregating and listing some awesome, developer-friendly fonts. Find the ones you like and download them. Now, the tricky bit is to install them as you have to go through many many *.ttf or *.otf files. But don&apos;t worry, I got you covered! Unzip the font(s) to a folder and navigate into it and run the following script:</p><!--kg-card-begin: html--><script src="https://gist.github.com/cmatskas/341726cba7c1678d8ae83d15e582ecb7.js"></script><!--kg-card-end: html--><p>Ok! Fonts covered..</p><h2 id="install-posh-git-and-oh-my-posh">Install Posh-Git and Oh My Posh</h2><p>As a developer you&apos;ll most likely have to work with Git so having the ability to quickly understand where things are, is very important. [Posh-Git](<a href="https://github.com/dahlbyk/posh-git">dahlbyk/posh-git: A PowerShell environment for Git (github.com)</a>) is a fantastic tool that adds this capability to your PowerShell terminal:</p><pre><code class="language-PowerShell">Install-Module posh-git -Scope CurrentUser -Force</code></pre><p>Then we want to install <a href="https://ohmyposh.dev/">Oh My Posh</a>, a PowerShell equivalent to OhMyZsh, that provides customization and theming for our editors. </p><pre><code>Install-Module oh-my-posh -Scope CurrentUser</code></pre><p>Ensure that you update your <code>$Profile</code> accordingly. Open it with your favorite editor and add these two lines at the top:</p><pre><code>Import-Module posh-git
Import-Module oh-my-posh</code></pre><p>With installation done, the next step is customization</p><h2 id="fancy-progress-bars-in-terminal">Fancy progress bars in Terminal </h2><p>If you use <code>winget</code> then you&apos;ve seen the boring, monotone progress bars that are displayed during downloads or updates. Who likes that? WinGet now <a href="https://github.com/microsoft/winget-cli/blob/master/doc/Settings.md">winget settings</a> via a file so that you can customize it to an extent. Execute <code>winget settings</code> in the terminal. This will open the <code>settings.json</code> file which you can edit. I added the following to get the rainbow effect in the progress bar</p><pre><code class="language-json"> {
    &quot;$schema&quot;: &quot;https://aka.ms/winget-settings.schema.json&quot;,
    &quot;visual&quot;: {
        &quot;progressBar&quot;: &quot;rainbow&quot;
    }
}</code></pre><h2 id="select-a-theme">Select a theme</h2><p>Selecting a theme is a big decision. I know people that have spent hours tweaking the look and feel, colors and contrast of their themes. I&apos;m lazy and I rely on the themes that the awesome open source community has built. Oh My Posh comes with way too many themes so if you want to have a quick demo how they would look in your terminal run the following command. This will apply each available theme to help you decide:</p><pre><code class="language-PowerShell">Get-PoshThemes</code></pre><p>However, I recently fell in love with Nick Craver&apos;s (of the StackOverflow fame) theme: Craver. Make sure to update your Oh My Posh (if you&apos;re not new to this) and follow the Nick&apos;s instructions here: <a href="https://gist.github.com/NickCraver/2d661e24e315e7e94a1aad88dadfadf3">Craver&apos;s oh-my-posh profile</a>.</p><p>Edit your <code>$profile</code> file to include your theme as per the example below:</p><pre><code class="language-PowerShell">Import-Module posh-git
Import-Module oh-my-posh
Import-Module -Name Terminal-Icons
Set-PoshPrompt -Theme Craver</code></pre><h2 id="configure-windows-terminal">Configure Windows Terminal</h2><p>Lastly, you want to configure Windows Terminal with your favorite fonts and tweak. You can now do this in the UI or via the settings.json file - whatever makes you happy :)</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2022/03/image-3.png" class="kg-image" alt loading="lazy" width="1603" height="1316" srcset="https://cmatskas.com/content/images/size/w600/2022/03/image-3.png 600w, https://cmatskas.com/content/images/size/w1000/2022/03/image-3.png 1000w, https://cmatskas.com/content/images/size/w1600/2022/03/image-3.png 1600w, https://cmatskas.com/content/images/2022/03/image-3.png 1603w" sizes="(min-width: 720px) 720px"></figure><p> After all this, my Terminal looks like this: </p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2022/03/image-2.png" class="kg-image" alt loading="lazy" width="2000" height="1238" srcset="https://cmatskas.com/content/images/size/w600/2022/03/image-2.png 600w, https://cmatskas.com/content/images/size/w1000/2022/03/image-2.png 1000w, https://cmatskas.com/content/images/size/w1600/2022/03/image-2.png 1600w, https://cmatskas.com/content/images/2022/03/image-2.png 2108w" sizes="(min-width: 720px) 720px"></figure><p>Let me know if you want me to publish my Terminal <code>settings json file</code> if you feel it will help you with your setup :)</p><blockquote>NOTE: this is only the tip of the iceberg! Windows Terminal is extremely configurable so I would encourage you to look around and customize it even further</blockquote><h2 id="summary">Summary</h2><p>In any case, I&apos;m really excited to see all the innovation and customization that has gone into Windows Terminal. I have been an avid user since the early preview/beta stages. Windows has always been behind MacOs and Linux in the terminal space and I always wanted to somehow have the equivalent of my iTerm2 with ZSH and OhMyZsh. These days it&apos;s the other way around where I want Windows Terminal on my Mac! But for now I&apos;ll compromise with what&apos;s available. </p><p>So, go ahead and tweak your Terminal to your liking - you can. Don&apos;t forget to tweet a picture of your terminal and tag me and Kayla Cinnamon @cinnamon_msft (the PM of Windows Terminal). We would love to see what you achieve!</p><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[Install Go on WSL Ubuntu from the command line]]></title><description><![CDATA[<p>With Go 1.18 just out and in GA, I was curious to give Go &quot;a go&quot; (pun intended) and play around a bit with Generics - a highly anticipated feature in Go! but first I had to install it. I chose to go with WSL 2 and</p>]]></description><link>https://cmatskas.com/install-go-on-wsl-ubuntu-from-the-command-line/</link><guid isPermaLink="false">631b77ad4e615c07ca3eacef</guid><dc:creator><![CDATA[Christos Matskas]]></dc:creator><pubDate>Wed, 16 Mar 2022 17:46:12 GMT</pubDate><content:encoded><![CDATA[<p>With Go 1.18 just out and in GA, I was curious to give Go &quot;a go&quot; (pun intended) and play around a bit with Generics - a highly anticipated feature in Go! but first I had to install it. I chose to go with WSL 2 and use Ubuntu for my new playground but I also wanted to install everything from the command line. Let&apos;s go!</p><h3 id="is-there-a-video">Is there a video?</h3><p>Funny you ask? I&apos;ve also recorded a 4min video that takes you through the process if you are a visual person. Check it out:</p><!--kg-card-begin: html--><iframe width="560" height="315" src="https://www.youtube.com/embed/Ow9mLwMsW8g" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe><!--kg-card-end: html--><h3 id="installation">Installation</h3><p>First we want to remove old versions of Go. Run the following command in WSL Ubuntu:</p><pre><code class="language-bash">sudo rm -rf /usr/local/go* &amp;&amp; sudo rm -rf /usr/local/go	</code></pre><p>Then we want to download the latest version (currently 1.18). The commands for this are:</p><pre><code class="language-bash">wget https://go.dev/dl/go1.18.linux-amd64.tar.gz
tar -xvf go1.18.linux-amd64.tar.gz
mv go go-1.18
sudo mv go-1.18 /usr/local</code></pre><p>Next we need to add Go to our environment profile so that it can get picked up by our command line. Open <code>~/.bashrc</code> with VS Code or your favorite editor: <code>code ~/.bashrc</code></p><p>Update the settings are per below:</p><pre><code class="language-bash">export GOROOT=/usr/local/go-1.18
export GOPATH=$HOME/go
export PATH=$GOPATH/bin:$GOROOT/bin:$PATH</code></pre><p>Restart your command line/terminal and verify that the latest version has been installed correctly by typing <code>go version</code></p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2022/03/image.png" class="kg-image" alt loading="lazy" width="603" height="154" srcset="https://cmatskas.com/content/images/size/w600/2022/03/image.png 600w, https://cmatskas.com/content/images/2022/03/image.png 603w"></figure><p>Job done! Happy coding with Go(lang)</p>]]></content:encoded></item><item><title><![CDATA[Setting up Managed Identities for  ASP.NET Core web app running on Azure App Service]]></title><description><![CDATA[<p>A few weeks ago I wrote about <a href="https://cmatskas.com/secure-app-development-with-azure-ad-key-vault-and-managed-identities">Secure application development with Key Vault and Azure Managed Identities</a> which are managed, behind the scenes, by Azure Active Directory.</p><p>At the end of that blog post, I promised to show you how to take your app from local development to production seamlessly,</p>]]></description><link>https://cmatskas.com/setting-up-managed-identities-for-asp-net-core-web-app-running-on-azure-app-service/</link><guid isPermaLink="false">631b77ad4e615c07ca3eacec</guid><category><![CDATA[ASP.NET Core]]></category><category><![CDATA[Azure Managed Identity]]></category><category><![CDATA[security]]></category><category><![CDATA[Azure]]></category><category><![CDATA[Azure AD]]></category><dc:creator><![CDATA[Christos Matskas]]></dc:creator><pubDate>Wed, 01 Jul 2020 22:59:15 GMT</pubDate><content:encoded><![CDATA[<p>A few weeks ago I wrote about <a href="https://cmatskas.com/secure-app-development-with-azure-ad-key-vault-and-managed-identities">Secure application development with Key Vault and Azure Managed Identities</a> which are managed, behind the scenes, by Azure Active Directory.</p><p>At the end of that blog post, I promised to show you how to take your app from local development to production seamlessly, leveraging Managed Identities on the Azure App Service.</p><h3 id="what-does-the-app-currently-do">What does the app currently do</h3><p>Before setting things up on Azure, let&apos;s remind ourselves quickly what the application does and where Azure Managed Identities and Key Vault fit. The Razor Web App retrieves two secrets from Key Vault without having to configure any connection strings for accessing Key Vault. Visual Studio uses the currently logged in account to retrieve the secrets by leveraging a couple of libraries - as explained on the original post. Now I want to publish and run this .NET Core 3.1 app in Azure without changing any code. Let&apos;s do this</p><h3 id="deploying-to-azure">Deploying to Azure</h3><p>There are many different ways to deploy your apps to Azure, Azure DevOps and GitHub actions highly recommended, but I will be <s>lazy</s> efficient and use the Right-Click Publish feature in Visual Studio. Once the publication is successful, I navigate to the Azure Portal to check my app. Since the code is configured to pull information from Key Vault at startup, my app is going to fail miserably the first time I try to run it since I haven&apos;t configured the Managed Identity yet. If you are presented with the following error message, it&apos;s perfectly normal and expected:</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/07/image.png" class="kg-image" alt loading="lazy" width="777" height="463" srcset="https://cmatskas.com/content/images/size/w600/2020/07/image.png 600w, https://cmatskas.com/content/images/2020/07/image.png 777w" sizes="(min-width: 720px) 720px"></figure><p>Ouch... let&apos;s fix this :)</p><h3 id="using-system-assigned-managed-identities">Using System Assigned Managed Identities</h3><p>As soon as we deploy our web app to Azure, a system assigned Managed Identity is provisioned to our app. You can check this by navigating to the <strong>Identity</strong> tab in our App Service. This is great as it saves me a few steps. However, this account doesn&apos;t have any permissions to any of my Azure Resources. </p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/07/image-1.png" class="kg-image" alt loading="lazy" width="991" height="687" srcset="https://cmatskas.com/content/images/size/w600/2020/07/image-1.png 600w, https://cmatskas.com/content/images/2020/07/image-1.png 991w" sizes="(min-width: 720px) 720px"></figure><p>If you want to find more details about this identity, head over to your Azure Active Directory -&gt; Enterprise Application where you can search by application name. The name of the Manage Identity matches the name of the App Service we deployed our app to:</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/07/image-2.png" class="kg-image" alt loading="lazy" width="1478" height="420" srcset="https://cmatskas.com/content/images/size/w600/2020/07/image-2.png 600w, https://cmatskas.com/content/images/size/w1000/2020/07/image-2.png 1000w, https://cmatskas.com/content/images/2020/07/image-2.png 1478w" sizes="(min-width: 720px) 720px"></figure><p>I can now go to my Key Vault and assigned the necessary permissions so that my application can retrieve the secrets using the system assigned Managed Identity. In the Azure Portal, navigate to your designated Key Vault and open the <strong>Access Policies</strong> tab. Next, press on the <strong>Add Access Policy</strong> link</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/07/image-3.png" class="kg-image" alt loading="lazy" width="1148" height="659" srcset="https://cmatskas.com/content/images/size/w600/2020/07/image-3.png 600w, https://cmatskas.com/content/images/size/w1000/2020/07/image-3.png 1000w, https://cmatskas.com/content/images/2020/07/image-3.png 1148w" sizes="(min-width: 720px) 720px"></figure><p>Since our web app only needs to retrieve secrets from Key Vault, we want to allocate the bare minimum permissions to the Managed Identity to reduce the risk that could come from a compromise. So, in this instance, we only need to assign List and Get permissions.</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/07/image-4.png" class="kg-image" alt loading="lazy" width="693" height="596" srcset="https://cmatskas.com/content/images/size/w600/2020/07/image-4.png 600w, https://cmatskas.com/content/images/2020/07/image-4.png 693w"></figure><p>Next, we need to find the right principal. Again, you can search by name or object id, and select it.</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/07/image-6.png" class="kg-image" alt loading="lazy" width="1232" height="669" srcset="https://cmatskas.com/content/images/size/w600/2020/07/image-6.png 600w, https://cmatskas.com/content/images/size/w1000/2020/07/image-6.png 1000w, https://cmatskas.com/content/images/2020/07/image-6.png 1232w" sizes="(min-width: 720px) 720px"></figure><p>Back in the <strong>Access Policies</strong> tab, we should now be able to see our Managed Identity with its two Secrets Permissions. Make sure to press <strong>Save</strong> to persist the changes. Back to our Web App, we need to do a restart to ensure that the new permissions are picked up. Run the app and.... what a glorious sight!</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/07/image-7.png" class="kg-image" alt loading="lazy" width="838" height="238" srcset="https://cmatskas.com/content/images/size/w600/2020/07/image-7.png 600w, https://cmatskas.com/content/images/2020/07/image-7.png 838w" sizes="(min-width: 720px) 720px"></figure><p>This all works out of the box with no code changes and minor modifications to our Key Vault.</p><h3 id="using-user-assigned-managed-identities">Using User Assigned Managed Identities</h3><p>As we mentioned earlier Managed Identities come in two flavors. The default, system-assigned is created automatically for us. But these MSIs are bound to the resource and can&apos;t be reused. User defined MSIs, on the other hand, are not bound to any resources and can be reused across multiple ones. In addition, a resource can have multiple user-assigned MSIs! This means that if we want to use user-assigned MSIs, we need to do some code changes. More specifically, we need to configure the <code>AzureServiceTokenProvider</code> with the identity we want to use. You can find more details about Service-to-Service authentication with MSI in the <a href="https://docs.microsoft.com/en-us/azure/key-vault/general/service-to-service-authentication#connection-string-support">docs</a>.</p><p>First, we need to define a new parameter in our <code>appsettings.json</code> file. The new parameter, we&apos;ll name it <code>UserDefinedId</code> will be used to store the <code>clientId</code> of our user-defined MSI. If you need to find the client id, run the following command in the Azure CLI</p><pre><code class="language-az">az identity list</code></pre><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/07/image-14.png" class="kg-image" alt loading="lazy" width="928" height="420" srcset="https://cmatskas.com/content/images/size/w600/2020/07/image-14.png 600w, https://cmatskas.com/content/images/2020/07/image-14.png 928w" sizes="(min-width: 720px) 720px"></figure><p>If you need to first create a new identity, you can run the following command</p><p><code>az identity create --name &lt;any unique name&gt; --resource-group &lt;resourceGroupName&gt;</code></p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/07/image-9.png" class="kg-image" alt loading="lazy" width="1504" height="280" srcset="https://cmatskas.com/content/images/size/w600/2020/07/image-9.png 600w, https://cmatskas.com/content/images/size/w1000/2020/07/image-9.png 1000w, https://cmatskas.com/content/images/2020/07/image-9.png 1504w" sizes="(min-width: 720px) 720px"></figure><p>You can&apos;t use the ClientId in development as the code is not running in the context of Azure and it will throw and exception. However, we can update the code to handle both scenarios :)</p><p>Open the <code>Program.cs</code> class and update the code with the following:</p><!--kg-card-begin: html--><script src="https://gist.github.com/cmatskas/86aa07728bc3cc7a81d7b75cc1185f37.js"></script><!--kg-card-end: html--><p>The code here does a few things. First, it checks to see if the app is going to use a user-assigned or a system-assigned MSI based on the value of the <code>UserAssignedId</code> parameter in the <code>appsettings.json</code>. If the value is empty, then we assume that the app is either running locally (you can&apos;t use user-assigned MSI in dev) or it&apos;s using a system-assigned MSI with the default constructor for the <code>AzureServiceTokenProvider</code>. If, however, the paramater value is set, then the code knows that we&apos;re using a user-assigned MSI and instantiates the <code>AzureServiceTokenProvider</code> with the appropriate connection string. This is code is clever enough to work it out but I&apos;m sure there are other ways we can implement this</p><p>Back in the Azure Portal, in the Identity tab on our Web App, we need to configure the User Assigned MSI</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/07/image-10.png" class="kg-image" alt loading="lazy" width="1195" height="699" srcset="https://cmatskas.com/content/images/size/w600/2020/07/image-10.png 600w, https://cmatskas.com/content/images/size/w1000/2020/07/image-10.png 1000w, https://cmatskas.com/content/images/2020/07/image-10.png 1195w" sizes="(min-width: 720px) 720px"></figure><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/07/image-11.png" class="kg-image" alt loading="lazy" width="1134" height="310" srcset="https://cmatskas.com/content/images/size/w600/2020/07/image-11.png 600w, https://cmatskas.com/content/images/size/w1000/2020/07/image-11.png 1000w, https://cmatskas.com/content/images/2020/07/image-11.png 1134w" sizes="(min-width: 720px) 720px"></figure><p>At this point, you also want to ensure that the System Assigned MSI is turned off</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/07/image-12.png" class="kg-image" alt loading="lazy" width="752" height="283" srcset="https://cmatskas.com/content/images/size/w600/2020/07/image-12.png 600w, https://cmatskas.com/content/images/2020/07/image-12.png 752w" sizes="(min-width: 720px) 720px"></figure><p>We also need to add a new App Setting for the <code>UserAssignedId</code>. In the <strong>Configuration</strong> tab on our Web App, we need to add a new <strong>Application Setting</strong> with:</p><ul><li>name: UserAssignedId</li><li>Value: &lt;The ClientID of our user-assigned identity&gt;</li></ul><p>Make sure to press Save to persist the changes. This will also restart the web app (for good measure, lol)</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/07/image-15.png" class="kg-image" alt loading="lazy" width="969" height="347" srcset="https://cmatskas.com/content/images/size/w600/2020/07/image-15.png 600w, https://cmatskas.com/content/images/2020/07/image-15.png 969w" sizes="(min-width: 720px) 720px"></figure><p>Finally, we need to ensure that our user-assignd MSI &#xA0;has the appropriate permissions to access our Key Vault. Remember that we only need to configure the minimum permissions (i.e GET and LIST on the Secrets) and save the changes.</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/07/image-13.png" class="kg-image" alt loading="lazy" width="1210" height="546" srcset="https://cmatskas.com/content/images/size/w600/2020/07/image-13.png 600w, https://cmatskas.com/content/images/size/w1000/2020/07/image-13.png 1000w, https://cmatskas.com/content/images/2020/07/image-13.png 1210w" sizes="(min-width: 720px) 720px"></figure><p>We can now test our web app and check that everything is working as expected!</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/07/image-16.png" class="kg-image" alt loading="lazy" width="890" height="345" srcset="https://cmatskas.com/content/images/size/w600/2020/07/image-16.png 600w, https://cmatskas.com/content/images/2020/07/image-16.png 890w" sizes="(min-width: 720px) 720px"></figure><h3 id="summary">Summary</h3><p>Managed Identities are an invaluable tool for helping you create more secure solutions by removing the need to store keys, secrets, passwords or anything else that can be used to compromize your infrastructure. And with MSI being designed is a way to support this end to end, from development to production, you should be making sure to use this wherever it&apos;s supported. </p><p>The repo with a working example is on <a href="https://github.com/cmatskas/MSIWithASPNET">GitHub </a>and you can always reach out to me if you have any questions!</p>]]></content:encoded></item><item><title><![CDATA[Working with Azure EasyAuth (Azure App Service Authentication) and .NET Core 3.1]]></title><description><![CDATA[<p>Working with authentication in your apps can sometimes be tricky and every app has its own constraints. But the Azure platform provides developers and organizations with many options when it comes to implementing authentication and authorization, from fully customized, coded solutions to turn-key authentication with little to no code changes.</p>]]></description><link>https://cmatskas.com/working-with-easyauth-app-service-authentication-and-net-core-3-1/</link><guid isPermaLink="false">631b77ad4e615c07ca3eaceb</guid><category><![CDATA[ASP.NET Core]]></category><category><![CDATA[Azure AD]]></category><category><![CDATA[Authentication]]></category><category><![CDATA[security]]></category><dc:creator><![CDATA[Christos Matskas]]></dc:creator><pubDate>Tue, 16 Jun 2020 00:08:53 GMT</pubDate><content:encoded><![CDATA[<p>Working with authentication in your apps can sometimes be tricky and every app has its own constraints. But the Azure platform provides developers and organizations with many options when it comes to implementing authentication and authorization, from fully customized, coded solutions to turn-key authentication with little to no code changes.</p><p>Imagine the scenario where you already have an app that was coded without authentication. This could be an app that was developer to run internally but now it needs to be moved to Azure. To secure access to the app, you have 2 options:</p><ul><li>Add authentication in code so that users can log in with their enterprise credentials</li><li>Use the Azure App Service Authentication option</li></ul><p>The first one is more involved. You need to write code, test it and then push the new solution to Azure. It gives you a lot more control but requires code changes. The second option is instant. A few settings within the App Service environment and you&apos;re good to go. </p><p>At this point, you may wonder why do we need a blog post for App Service Authentication if it works so well. It works great, but it&apos;s not perfect for .NET Core 3.1 (yet!). Although the authentication works as expected, due to the differences between .NET and .NET Core, in ASP.NET Core apps the claims principal object doesn&apos;t get populated out of the box. That what we have in the <a href="https://docs.microsoft.com/en-us/azure/app-service/overview-authentication-authorization">official authentication</a>:</p><p><em>At this time, ASP.NET Core does not currently support populating the current user with the Authentication/Authorization feature.</em></p><p>The user authenticates and gets access to the app but my app/code doesn&apos;t know who that user user is or what permissions (claims) the user has. A small setback - i know - but this is what I set out to fix with this blog post. </p><h3 id="prerequisites">Prerequisites</h3><ul><li>An Azure Subscription (get your&apos;s <a href="https://azure.microsot.com/free">FREE here</a>)</li><li>.NET Core 3.1</li></ul><p>The ASP.NET Core 3.1 app</p><p>I mentioned before that we don&apos;t have to do anything to our app to leverage the turn-key Azure App Service Authentication feature. But if we want to use the authenticated user identity to do custom checks, then using the code in this blog will allow you to do so. For this example I&apos;m using Razor Pages but the code should apply to any ASP.NET Core web app.</p><p>The main changes in the app are:</p><ol><li>A custom middleware to retrieve the user identity and claims based on the auth header</li><li>A &#xA0;partial page to display a logout option</li><li>A new page to display all the user claims - this is to prove that we have access to the full user object</li></ol><p>ASP.NET Core provides a straightforward way to work with its middleware unlike the <em>&apos;olden days&apos;</em> when OWIN was our only option. With ASP.NET Core, anyone can implement (even me) custom middleware following some basic rules to ensure that the whole pipeline executes as expected. We don&apos;t want our middleware to break things. The <a href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/middleware/?view=aspnetcore-3.1">ASP.NET Core docs</a> do a great job explain how and what we need to implement in our middleware as well as some gotchas.</p><p>With that in mind, let&apos;s build our middleware that will take the information from the HTTP headers and check if there is an authenticated user before reaching out to Azure AD to grab the user properties</p><p>First, lets create a brand new .NET Core Razor pages app using the CLI. Open the shell of your choice and type the following:</p><pre><code class="language-shell">dotnet new webapp</code></pre><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/06/image-27.png" class="kg-image" alt loading="lazy"></figure><p>Now that we have the app barebones, we can add our custom middlware. You don&apos;t really have to, as you can stick your code directly into the <code>Configure()</code> method in <code>Startup.cs</code> but this can clatter the code and make it hard to read. Therefore, it is preferable to create a separate class for your middlware code. Let&apos;s name it <code>EasyAuthUserValidationMiddleware.cs</code> and add the following code:</p><!--kg-card-begin: html--><script src="https://gist.github.com/cmatskas/7db27cb4e36a2b4ff3033aca5ebfe3c5.js"></script><!--kg-card-end: html--><p>The code looks at the headers, grabs the appropriate information, makes an HTTP call to Azure AD ( to grab the user claims and adds the user to the context so the <code>Context.Current.User</code> object is populated.</p><p>We now need a way to be able to wire up our middleware to the rest of the ASP.NET Core pipeline. For that, we need a few lines of code to expose our middleware and the code below shows how to do it. Create a new class called <code>EasyAuthUserValidationMiddlewareExtensions.cs</code> and add the following code:</p><!--kg-card-begin: html--><script src="https://gist.github.com/cmatskas/bed11246d07dc636c2c88b744c66b129.js"></script><!--kg-card-end: html--><p>The final step is to configure our app to use our middleware. Open the <code>Startup.cs</code> class, go to the <code>Configure()</code> method and add the following line:</p><pre><code class="language-C#">app.UseEasyAuthUserValidation();</code></pre><p>That&apos;s all we need. It&apos;s concise and neat and... OK, it should be part of the framework and shouldn&apos;t require any extra work on your part but we&apos;re working on this. In the meantime, we have a working solution. So let&apos;s put our solution to practice.</p><h3 id="enumerate-the-logged-in-user-claims-in-the-app">Enumerate the logged in user claims in the app</h3><p>Up until this point I didn&apos;t have to write any code to implement the authentication. In fact, my app would happily run as is. But I wanted to do a bit more in this example and actually interact with the user object. For this reason, will add a new Razor page, called <code>Claims</code> where I can enumerate, you guessed it, the user claims - only to show that my middleware is working as expected :)</p><p>In the <code>Claims.cshmtl.cs</code> class, I added the following code to grab the Claims and send them to the view:</p><pre><code class="language-C#">public IEnumerable&lt;Claim&gt; UserClaims { get; set; }
public void OnGet()
{
	UserClaims = HttpContext.User.Claims;
}</code></pre><p>And the in the <code>Claims.cshtml</code> I added the following code to check if the user is logged in (should always be) and enumerate the user claims on the page:</p><!--kg-card-begin: html--><script src="https://gist.github.com/cmatskas/87cf3d59ca54201cf5705c2f06d07d6e.js"></script><!--kg-card-end: html--><p>Running the app locally shouldn&apos;t break anything and only show this when going to the Claims page:</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/06/image-28.png" class="kg-image" alt loading="lazy"></figure><p>Next, we&apos;re going to deploy our app to Azure Web Apps and see what happens. Use the method that works best for you: Azure DevOps, GitHub Actions or right-click publish straight from Visual Studio - there I said it :)</p><h3 id="configure-authentication-on-the-azure-web-app-">Configure Authentication on the Azure Web App.</h3><p>On the Azure portal, navigate to your web app and open the Authentication tab and flick the switch to On</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/06/image-29.png" class="kg-image" alt loading="lazy"></figure><p>We will be using Azure AD to configure authentication but as you can see we support a large number of additional providers such as Google, Microsoft Account etc</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/06/image-30.png" class="kg-image" alt loading="lazy"></figure><p>Select <strong>Azure Active Directory</strong> and proceed to use the <strong>Express </strong>settings to set things up. The <strong>Create App</strong> option will set up an Azure AD App Registration automatically for you when using the Express mode. </p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/06/image-31.png" class="kg-image" alt loading="lazy"></figure><p>If you already have an App Registration that you want to use instead, you can configure this using the <strong>Advance </strong>mode. Pressing <strong>OK </strong>will configure the App Registration. There is one more step left to ensure that only logged in users can access our web app. Back in the Authentication tab, we need to select the right option from the drop down (you option will differ based on the Identity Provider you choose)</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/06/image-32.png" class="kg-image" alt loading="lazy"></figure><p>Since we chose to authenticate with Azure AD, we need to select the <strong>Log in with Azure Active Directory</strong> option and press <strong>Save</strong> to apply our changes. </p><h3 id="testing-our-authentication">Testing our authentication</h3><p>You can see our code and Authentication setup in action on the gif below:</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/06/AA8BDD01-9664-456C-9779-BC375BDB1FB7.GIF" class="kg-image" alt loading="lazy"></figure><h3 id="other-options">Other options</h3><p>I agree that this may be too involved for your tasting and you may be looking for a simpler solution. How about if I told you there is a Nuget package that can do more or less the same as what I&apos;ve shown you above. If you&apos;re interested, check out Maxime Rouiller&apos;s (Microsft CDA and great coder) <a href="https://blog.maximerouiller.com/post/using-easyauth-appservice-authentication-with-aspnet-core/">blog post </a>that explains how his library works and how to get it.</p><p>The main difference between mine and Maxime&apos;s code is that I check for the authorized user on every request whereas Maxime&apos;s library only executes on pages/controllers that have the <code>[Authorize(AuthenticationSchemes = &quot;EasyAuth&quot;)]</code> attribute applied. And maybe his code is nicer :)</p><h3 id="conclusion">Conclusion</h3><p>Adding authentication doesn&apos;t have to be complicated. If you have legacy apps or code that you don&apos;t want to update, the Azure App Service offers turn-key authentication using EasyAuth. In this blog post we covered how to set your Azure Web app to Authenticate user and then implement a custom middleware in our ASP.NET Core 3.1 Razor pages web app to retrieve and populate the user object. </p><p>I hope this is useful to you and as always, ping me on Twitter if you have any questions!</p>]]></content:encoded></item><item><title><![CDATA[Create sample data for Cosmos DB with .NET Core]]></title><description><![CDATA[<p>Aren&apos;t you bored of stockmarket ticker and ToDo sample apps and data? Do you long for some more realistic data to build great app samples around it? Well, guess what? Problem solved? How do you feel about Volcanos? If you love them (and fear them) like I do,</p>]]></description><link>https://cmatskas.com/create-sample-data-for-cosmos-db/</link><guid isPermaLink="false">631b77ad4e615c07ca3eacea</guid><category><![CDATA[.NET Core]]></category><category><![CDATA[CosmosDB]]></category><dc:creator><![CDATA[Christos Matskas]]></dc:creator><pubDate>Wed, 03 Jun 2020 21:58:47 GMT</pubDate><content:encoded><![CDATA[<p>Aren&apos;t you bored of stockmarket ticker and ToDo sample apps and data? Do you long for some more realistic data to build great app samples around it? Well, guess what? Problem solved? How do you feel about Volcanos? If you love them (and fear them) like I do, then this is the blog for you. below I&apos;ll show you how to create a small console app that generates sample data and then populates a Cosmos DB database with it.</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/06/image-25.png" class="kg-image" alt loading="lazy"></figure><h3 id="prerequisites">Prerequisites</h3><p>Since Cosmos DB is an Azure service, you&apos;ll need and Azure Subscription. Grab one for FREE <a href="https://azure.microsoft.com/free">here</a>! For this example we will also be using .NET Core 3.1 so make sure to download it <a href="https://dotnet.microsoft.com/download/dotnet-core/3.1">here</a>. Finally, you are free to use the IDE/tool of your choice - I&apos;m using Visual Studio 2019 Preview this time around.</p><h3 id="components">Components</h3><ul><li>.NET Core 3.1</li><li>Bogus NuGet package( <a href="https://cmatskas.com/creating-net-fakes-using-bogus-2">create fake/sample data with Bogus and .NET</a>)</li><li>Cosmos DB NuGet package</li></ul><h3 id="create-a-cosmos-db-resource">Create a Cosmos DB resource</h3><p>If you already have a Cosmos DB resource, you can skip to the next section. If not, keep going. I will be using the Azure CLI with CloudShell to create the Cosmos DB instance. If you&apos;re using the latest Windows Terminal, CloudShell is already a shell option :) If not, you can use the CloudShell instance on the azure portal or navigate to <a href="shell.azure.com">shell.azure.com</a> to fire up a new instance! You can find the necessary CLI command documentation <a href="https://docs.microsoft.com/en-us/cli/azure/cosmosdb?view=azure-cli-latest">here</a>.</p><p>The script necessary to create a new Cosmos DB instance is:</p><pre><code>az login
az account set --subscription &lt;SubscriptionName or Guid&gt;
az cosmosdb create --resource-group &lt;ResourceGroupName&gt; --subscription &apos;&lt;SubscriptionName&gt;&apos; --name &lt;CosmosDBName&gt;</code></pre><p>We can now grab the connection string so that we can use it later in our console app</p><pre><code>az cosmosdb list-connection-strings --name &lt;yourCosmosDBName&gt; --resource-group &lt;ResourceGroupName&gt;</code></pre><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/06/image-26.png" class="kg-image" alt loading="lazy"></figure><p>We&apos;ve now completed our DB setup :)</p><h3 id="create-the-console-app">Create the console app</h3><p>As I started down this path, I was lucky to find some existing sample data in this <a href="https://github.com/Azure-Samples/azure-cosmos-db-sample-data">Azure Samples repository</a>. However, there were a couple of issues. 1. There were spaces in a couple of JSON properties and 2. I wanted richer data. So I downloaded the json file locally, did a quick search and replace to remove the spaces and then I started writing the necessary code to to enrich and push the data to my Cosmos DB database. </p><p>Next, we will use the <code>dotnet</code> CLI to create a new console app and add the necessary NuGet packages.</p><pre><code>dotnet new console
dotnet add project &lt;ProjectName&gt; package Microsoft.Azure.Cosmos
dotnet add project &lt;ProjectName&gt; package Microsoft.Extensions.Configuration.UserSecrets
dotnet add project &lt;ProjetName&gt; package Bogus
dotnet add project &lt;ProjetName&gt; package Newtonsoft.Json
</code></pre><p>I also copied my sampleData.json file into the project folder and added the following into my *.csproj file so that it be copied to the bin folder:</p><pre><code class="language-json"> &lt;ItemGroup&gt;
    &lt;None Update=&quot;sampleData.json&quot;&gt;
      &lt;CopyToOutputDirectory&gt;Always&lt;/CopyToOutputDirectory&gt;
    &lt;/None&gt;
  &lt;/ItemGroup&gt;</code></pre><p>Finally, from the command line, I executed the following command to initialize the secrets file so that I can store my Cosmos DB connection string outside my source code :)</p><pre><code>dotnet user-secrets init
dotnet user-secrets set CosmosDBConnection &quot;&lt;one of the connections retrieved earlier&quot;</code></pre><p>And now the code in all its glory</p><!--kg-card-begin: html--><script src="https://gist.github.com/cmatskas/9a259f6267bbd43f35659846bfd86d90.js"></script><!--kg-card-end: html--><p>There are a couple of helper methods here to set things up:</p><p>The <code>BootstrapConfiguration()</code> method returns an <code>IConfiguration</code> object with all the secrets (well, just one for our example). The <code>PopulateMeasurementData()</code> takes the JSON data we loaded from file and adds some extra measurement data using Bogus. The <code>GetJsonDataAsync()</code> loads the data from file and deserializes it into strongly typed objects. Finally, the <code>BulkUploadDataToCosmosDB()</code> takes our enriched data and bulk uploads it to Cosmos DB. The <code>Main()</code> method ties everything together and adds a bit of logging. </p><p>If you want to create sample data on the fly, you are welcome to fork the <a href="https://github.com/cmatskas/CosmosDBSampleData">GitHub repo</a>, add your Cosmos DB connection string and run the app to get some sweet, realistic Volcano data for your app :)</p>]]></content:encoded></item><item><title><![CDATA[Create an Azure AD protected API that calls into Cosmos DB with Azure Functions and .NET Core 3.1]]></title><description><![CDATA[<p>In today&apos;s post we will see how we can create an Azure AD protected API using Azure Functions. The API will use Cosmos DB as a backend and authorized users will be able to interact with the Cosmos DB data based on their permissions. We will be using</p>]]></description><link>https://cmatskas.com/create-an-azure-ad-protected-api-that-calls-into-cosmosdb-with-azure-functions-and-net-core-3-1/</link><guid isPermaLink="false">631b77ad4e615c07ca3eace9</guid><dc:creator><![CDATA[Christos Matskas]]></dc:creator><pubDate>Wed, 03 Jun 2020 05:24:37 GMT</pubDate><content:encoded><![CDATA[<p>In today&apos;s post we will see how we can create an Azure AD protected API using Azure Functions. The API will use Cosmos DB as a backend and authorized users will be able to interact with the Cosmos DB data based on their permissions. We will be using .NET Core 3.1 and C# to put all this together. There are 3 main components here</p><ol><li>Azure AD to for token validation and authorization</li><li>The Function App</li><li>The Cosmos DB database</li></ol><p>First, we will need to create and populate our Cosmos DB with some data. If you already have sample data then that&apos;s awesome, you can skip this step. Then we need to register two apps in Azure AD and configure application roles for our users. Finally, we will implement the appropriate code in our Functions to validate user tokens and then perform the appropriate CRUD operation in CosmosDB</p><h3 id="create-and-populate-the-cosmos-db-database">Create and populate the Cosmos DB database</h3><p>Head over to the <a href="https://cmatskas.com/p/25927026-4136-4ce4-b5b4-8c8d5deb966c/portal.azure.com">Azure portal</a> and create a new Cosmos DB database. Provide the subscription, resource group and a name for your Cosmos Account. If you want to simply test Cosmos DB and save some money, you can choose the Free Tier Discount. Please note that there are limitations to the free tier.</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/06/image.png" class="kg-image" alt loading="lazy"></figure><p>Press <strong>Review and Create</strong> if you wish to omit Networking or Encryption settings. Once our Cosmos DB instance is ready, we can create a new empty collection by navigating to the Data Explorer tab and selecting <strong>New Collection:</strong></p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/06/image-1.png" class="kg-image" alt loading="lazy"></figure><p>Since we will be working with the Volcano <a href="https://github.com/Azure-Samples/azure-cosmos-db-sample-data/blob/master/SampleData/VolcanoData.json">sample dataset</a>, we will be using the <code>id</code> field as the <code>Partition Key</code>. To upload the sample data, we need to expand the Volcano Collection, click on the <code>Items</code> node and select the <strong>Upload Item </strong>option from the menu:</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/06/image-2.png" class="kg-image" alt loading="lazy"></figure><p>The import should be instantaneous, so refreshing the query results on the page should result to this:</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/06/image-4.png" class="kg-image" alt loading="lazy"></figure><p>One last thing we need to do is make a note of the connection string as we will need to configure our Azure Functions with it. Head to the <strong>Keys</strong> tab and grab the connection string (either the primary or secondary will work):</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/06/image-5.png" class="kg-image" alt loading="lazy"></figure><p>At this stage we have a Cosmos DB instance we can use with our Functions. Next, Azure AD.</p><h3 id="configure-azure-ad-for-authentication-and-authorization">Configure Azure AD for authentication and authorization</h3><p>We will need to create 2 separate application registrations in Azure AD. One for our (Functions) API and one for the API client. You could have multiple API clients (mobile app, web, desktop) all with different scopes as well but for now we will keep it simple. </p><h4 id="create-the-api-app-registration">Create the API App Registration</h4><p>First, the Function API app registration. In the Azure Portal, navigate to Azure AD select the App Registrations tab and create a new registration. Give it a meaningful name, select Single Tenant and leave the Redirect URI empty:</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/06/image-6.png" class="kg-image" alt loading="lazy"></figure><p>Next, navigate to the API Permissions tab and delete any existing Permissions (should be only one for Graph -&gt; User.Read). Since this is an API that we want to expose to the world, we need to navigate to the <strong>Expose an API </strong>tab to configure our settings. First we need to add a scope so, press the <strong>Add a scope</strong> button:</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/06/image-7.png" class="kg-image" alt loading="lazy"></figure><p>Add a scope name, in this instance <code>access_as_user</code>, and the appropriate messages for admins and users. Make sure to press <strong>Add scope</strong> in the end:</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/06/image-8.png" class="kg-image" alt loading="lazy"></figure><p>If you want to change the Application ID URI, you can do so:</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/06/image-9.png" class="kg-image" alt loading="lazy"></figure><p>Finally, we need to add the Roles to our application. Unfortunately there is no UI to do this yet so we have to edit the json in the application <code>Manifest</code> directly. </p><blockquote>We may not have an easy way to add Roles to an app via the UI for now but we do have a way to do all this using the Graph API. At /build we announce the GA availability for Applications which means that you can now programmatically create and configure app registrations via the Graph SDK</blockquote><p>Open the Manifest tab and edit the <code>appRoles</code> section. Interesting side-note: Emojis are fully supported, though you may want to approach this with some caution :) We will be adding two roles: a) <code>Data.Read</code> and b) <code>Data.ReadWrite</code> like below:</p><pre><code>&quot;appRoles&quot;: [
{
	&quot;allowedMemberTypes&quot;: [
		&quot;User&quot;
	],
	&quot;description&quot;: &quot;Read-Write access to CosmosDB data&quot;,
	&quot;displayName&quot;: &quot;&#x1F602;&#x1F602;&#x1F44F;&#x270C;Data.ReadWrite&quot;,
	&quot;id&quot;: &quot;0e13539f-f5d6-4b94-a349-4b178f677759&quot;,
	&quot;isEnabled&quot;: true,
	&quot;origin&quot;: &quot;Application&quot;,
	&quot;value&quot;: &quot;Data.ReadWrite&quot;
},
{
	&quot;allowedMemberTypes&quot;: [
    	&quot;User&quot;
    ],
    &quot;description&quot;: &quot;Read access to CosmosDB data&quot;,
    &quot;displayName&quot;: &quot;Data.Read&quot;,
    &quot;id&quot;: &quot;caf1baec-8df5-4358-9703-6a5adc9a6a82&quot;,
    &quot;isEnabled&quot;: true,
    &quot;origin&quot;: &quot;Application&quot;,
    &quot;value&quot;: &quot;Data.Read&quot;
}],</code></pre><p>You&apos;ll also need to update the <code>AccessTokenAcceptedVersion</code> to 2 (i.e. AAD v2) or otherwise the token validation process will fail later in our Functions code.</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/06/image-21.png" class="kg-image" alt loading="lazy"></figure><p>Make sure to press the <strong>Save </strong>button to persist the changes. At this point, we&apos;re done configuring the API app</p><h4 id="create-the-client-api-app-registration">Create the client API app registration</h4><p>There could be many different clients that consume our API. In this instance, we will use Postman to emulate the front end but the important bit here is that each client app registration could come with different scopes and hence different access levels or restrictions. Our Functions code will be responsible for checking and validating both the access tokens and the user claims. </p><p>We have to create a new single-tenant app registration, but this time we need to provide a Redirect URI so that Postman can receive the JWT token (like PIN number - I know). The right Redirect URI for Postman is <a href="https://www.postman.com/oauth2/callback"><code>https://www.postman.com/oauth2/callback</code></a>. We don&apos;t have to select Access or ID tokens in the configuration. Since we&apos;re using Postman, we also need a client secret, however depending on your front-end stack, you may not need one (see web app etc). We can create a new secret in the <strong>Certificates &amp; secrets</strong> tab. Make sure to make a note of the secret as you won&apos;t be able to get it back once you leave this tab - you can, however, recreate it as they are cheap and easy to generate :)</p><p>Next, and final step, we need to configure the <strong>API Permissions</strong> for our app. Press the <strong>Add a permissio</strong>n button and select <strong>My APIs. </strong>We should be able to see the FunctionAPI app registration we created in the previous step.</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/06/image-10.png" class="kg-image" alt loading="lazy"></figure><p>Select the API Permission (scope) we configured for our FunctionAPI app and press <strong>Add Permissions</strong></p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/06/image-11.png" class="kg-image" alt loading="lazy"></figure><p>As a final step here, we need to <strong>Grant admin consent</strong> </p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/06/image-12.png" class="kg-image" alt loading="lazy"></figure><p>Almost done. The very last step is to assign users to the application roles. This is done in the <strong>Enterprise Applications</strong> tab in Azure AD. Find the FunctionAPI app we registered in step one and select <strong>Assign users and groups. </strong></p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/06/image-13.png" class="kg-image" alt loading="lazy"></figure><p>Select Users and then assign them the appropriate roles:</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/06/image-14.png" class="kg-image" alt loading="lazy"></figure><p>You can assign multiple users and multiple roles simultaneously to speed things up as well :) Now, I know I shouldn&apos;t but I couldn&apos;t resist adding some emojis to our Role Permissions, which, surprisingly, showed up in the role selection window! Who said Identity and Azure AD can&apos;t be fun?</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/06/image-15.png" class="kg-image" alt loading="lazy"></figure><p>Our Azure AD configuration is now complete. 2 out of 3 tasks done. Now on to write some fun code!!!</p><h3 id="create-a-protected-api-using-azure-functions-and-azure-ad">Create a protected API using Azure Functions and Azure AD</h3><p>We can use the Azure Functions Core Tools (CLI), the Azure Functions extension in VS Code or Visual Studio to create a new Function App and the following 3 HttpTrigger Functions:</p><ul><li>GetVolcano (GET,POST)</li><li>GetAllVolcanoes (GET, POST)</li><li>UpdateVolcane (POST)</li></ul><p>For this example I will be using the Core Tools so the commands to create all these are:</p><pre><code>func init
func function create -&gt; HttpTrigger -&gt; GetAllVolcanoes
func function create -&gt; HttpTrigger -&gt; GetVolcano
func function create -&gt; HttpTrigger -&gt; UpdateVolcano</code></pre><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/06/image-16.png" class="kg-image" alt loading="lazy"></figure><p>We can now open this in VS Code start adding the appropriate code. First of all, we need to add the appropriate NuGet packages. Open the <code>*.csproj</code> file in your Function App folder and add the following package references:</p><pre><code>&lt;PackageReference Include=&quot;System.IdentityModel.Tokens.Jwt&quot; Version=&quot;6.6.0&quot; /&gt;
&lt;PackageReference Include=&quot;Microsoft.IdentityModel.Protocols.OpenIdConnect&quot; Version=&quot;6.6.0&quot; /&gt;
&lt;PackageReference Include=&quot;Microsoft.Azure.Functions.Extensions&quot; Version=&quot;1.0.0&quot; /&gt;
&lt;PackageReference Include=&quot;Microsoft.Azure.WebJobs.Extensions.CosmosDB&quot; Version=&quot;3.0.7&quot; /&gt;</code></pre><p>Pressing save will trigger VS Code to prompt you if you want to restore the newly added NuGet packages - go ahead and do this. Next, we need to add some extra configuration settings, namely the Azure AD details and the Cosmos DB Connection string. Open your <code>local.settings.json</code> file and add the following information</p><pre><code>{
    &quot;IsEncrypted&quot;: false,
    &quot;Values&quot;: {
        &quot;AzureWebJobsStorage&quot;: &quot;UseDevelopmentStorage=true&quot;,
        &quot;FUNCTIONS_WORKER_RUNTIME&quot;: &quot;dotnet&quot;,
        &quot;CosmosDBConnection&quot;: &quot;&lt;Your Azure CosmosDB connection string in full&gt;&quot;
    },
    &quot;AzureAd&quot;: {
        &quot;Instance&quot;: &quot;&lt;yourAADInstanceName&gt;.onmicrosoft.com&quot;,
        &quot;TenantId&quot;: &quot;b55f0c51-61a7-0000-84df-33569b247796&quot;,
        &quot;ClientId&quot;: &quot;69516c95-a7cc-0000-a62f-66aa336ef62a&quot;
    }
}</code></pre><p>Our Functions need to perform the token validation and also check for the appropriate claims (in the form of scopes and user roles). To do this, we will add class named &#xA0;<code>TokenValidator</code> that contains the following code:</p><!--kg-card-begin: html--><script src="https://gist.github.com/cmatskas/9975e877d35ed08dec3f725d7b26d6a3.js"></script><!--kg-card-end: html--><p>There are 3 methods here:</p><ul><li><code>GetJwtFromHeader()</code></li><li><code>ValidateTokenAsync()</code></li><li><code>HasRightRolesAndScope()</code></li></ul><p>The first one grabs the JWT token from the header. The second one uses Open ID Connect to validate the token against Azure AD and the final one checks that the ClaimsPrincipal has the right roles and scope. Different user will likely have different roles, as in our case we have a read-only and a read-write role. We also check for scopes because different client apps may have different scopes which would also dictate a different behavior in the API. In our case we only have one scope but there is nothing stopping you adding more to your API and doing the appropriate checks in the code.</p><h4 id="getvolcano-function">GetVolcano - Function</h4><p>For this Function, we will use the Cosmos DB Function bindings to connect seamlessly with our database. There is also a little bit of code to grab the config settings from the <code>local.settings.json</code> file. The full function code is provided below:</p><!--kg-card-begin: html--><script src="https://gist.github.com/cmatskas/48d50c8e7c466a7931666ff4bfa7c777.js"></script><!--kg-card-end: html--><p>From an authentication and authorization perspective, the Function allows anyone with the <code>Data.Read</code> and <code>Data.ReadWrite</code> roles to be able to execute the code. It also expects that the user has provided the expected scope, i.e <code>access_as_user</code>.</p><h4 id="getallvolcanoes-function">GetAllVolcanoes - Function</h4><p>For this function we will again use the Cosmos DB Function bindings and the code is more or less the same apart from the fact that we return all the records instead of selecting just one. The roles and scopes allowed are also the same as before. The full code is shown below:</p><!--kg-card-begin: html--><script src="https://gist.github.com/cmatskas/cf924e9a10b7a7b7824a0b8703a01c5e.js"></script><!--kg-card-end: html--><h4 id="updatevolcano-function">UpdateVolcano - Function</h4><p>This function is slightly different. Firstly, we use an output Cosmos DB binding to execute the Update/Insert into Cosmos DB. Secondly, this API endpoint is restricted to users that have the <code>Data.ReadWrite</code> role. Read-only users will receive an HTTP 401 error if they attempt to execute this code. The code is again below:</p><!--kg-card-begin: html--><script src="https://gist.github.com/cmatskas/41c0ab75540bc8d46d1f0241bc121a0b.js"></script><!--kg-card-end: html--><h4 id="volcano-dto">Volcano - DTO</h4><p>Finally, we need a class that describes our volcano object and can be used to serialize and deserialize data. The <code>volcano.cs</code> class is attached below:</p><!--kg-card-begin: html--><script src="https://gist.github.com/cmatskas/867beb49eef2bf82c1952b8292a9ebba.js"></script><!--kg-card-end: html--><h3 id="putting-it-all-together">Putting it all together</h3><p>As I mentioned earlier, I will be using Postman to test the API so off with it :) In Postman, I created a new request and I went straight into the Authorization bit as this is the most important step</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/06/image-17.png" class="kg-image" alt loading="lazy"></figure><p>When we press the <strong>Get New Access Token</strong> button, we are presented with a new window where we need to enter the details from our Client app registration (not the FunctionAPI app - that&apos;s use by our Functions, remember?). </p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/06/image-18.png" class="kg-image" alt loading="lazy"></figure><p>Of particular importance are the Callback URL which needs to match what we put in the client app Redirect URI in AAD and the Scope which should be API Permission we configure in the client app <strong>API Permissions</strong> tab. If you&apos;re wonder where to find the auth and token endpoints, head back to your Azure AD -&gt; App Registrations tab and look at the Overview:</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/06/image-20.png" class="kg-image" alt loading="lazy"></figure><p>If all is configured correctly, upon pressing the <strong>Request Token</strong> button you should be prompted by AAD to login in with your tenant&apos;s account details and in return you should receive a token. We can inspect the token on <a href="https://jwt.ms">jwt.ms</a> where we should see something similar to this:</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/06/image-19.png" class="kg-image" alt loading="lazy"></figure><p>You should notice how the <code>roles</code>, <code>scope</code>(scp) and <code>audience</code>(aud) all contain the information we need for our token to be validated by our API. I can now execute my HTTP request and receive some data:</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/06/image-22.png" class="kg-image" alt loading="lazy"></figure><p>And although this succeeds (as expected), check what happens when I use the same token to call the <code>UpdateVolcano()</code> method - <strong>401 Unauthorized</strong>:</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/06/image-24.png" class="kg-image" alt loading="lazy"></figure><p>As you can see, following the steps in this blog we were able configure AAD, create a Cosmos DB database and implement an Azure AD secured API using .NET Core 3.1 in Azure Functions that performs CRU(D) operations against our data. You can find the full source code in this <a href="https://github.com/cmatskas/AADFunctionsCosmosDb">Github repo</a>. All you need to do is slap a <code>local.settings.json</code> file with your settings (as shown earlier) and you&apos;re ready to go!</p><p>Watch me and <a href="https://twitter.com/azureandchill">JP aka @AzureAndChill</a> build this solution live during our first stream on Mixer/Twitch</p><!--kg-card-begin: html--><iframe title="jpda&apos;s player frame" i18n-title="channel#ShareDialog:playerEmbedFrame|Embed player Frame copied from share dialog" allowfullscreen="true" src="https://mixer.com/embed/player/jpda?vod=qhuBWxxG0EuX6YMdtGe_dg" width="800" height="530" align="middle"> </iframe><!--kg-card-end: html-->]]></content:encoded></item><item><title><![CDATA[Create an Azure AD protected API using Azure Functions and .NET Core 3.1]]></title><description><![CDATA[Learn how to create a protected API using .NET Core 3.1, Azure Functions and Azure Active Directory]]></description><link>https://cmatskas.com/create-an-azure-ad-protected-api-using-azure-functions-and-net-core-3-1/</link><guid isPermaLink="false">631b77ad4e615c07ca3eace8</guid><category><![CDATA[Serverless]]></category><category><![CDATA[Functions]]></category><category><![CDATA[Azure AD]]></category><category><![CDATA[Authentication]]></category><category><![CDATA[.NET Core]]></category><dc:creator><![CDATA[Christos Matskas]]></dc:creator><pubDate>Fri, 29 May 2020 04:54:22 GMT</pubDate><media:content url="https://cmatskas.com/content/images/2020/05/2020-05-28_21-53-12.png" medium="image"/><content:encoded><![CDATA[<img src="https://cmatskas.com/content/images/2020/05/2020-05-28_21-53-12.png" alt="Create an Azure AD protected API using Azure Functions and .NET Core 3.1"><p>It&apos;s been a long time since I got the chance to play with Azure Functions, one of my all time favorite Azure services. I mean, if you are going to create an API today then why not just use Functions? And if you&apos;re going to create an API, why not secure it with Azure AD? In this blog post, I&apos;ll show you how to add the necessary components to your Azure Function to validate access tokens from incoming requests against Azure AD.</p><h3 id="prerequisites">Prerequisites</h3><p>You will need to following to be able to develop and run functions locally</p><ul><li><a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-run-local?tabs=windows%2Ccsharp%2Cbash#v2">Azure Function Core Tools</a> v3 </li><li><a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-use-emulator">Azure Storage Emulator</a></li><li><a href="https://code.visualstudio.com/Download">Visual Studio Code</a>	</li><li> &#xA0; &#xA0;Azure Functions VS Code Extension (optional)	</li><li><a href="https://dotnet.microsoft.com/download/dotnet-core/3.1">.NET Core 3.1</a></li></ul><h3 id="create-your-azure-function">Create your Azure Function</h3><p>We are going to use Visual Studio Code with the Function Core Tools (CLI) to initialize and build the code for our C# Azure Function. Open up your favorite shell and type the following commands to create the Function:</p><pre><code class="language-bash">func init &lt;Function Name&gt;</code></pre><p>You then need to select the language, which, in our case, will be <code>dotnet</code></p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-46.png" class="kg-image" alt="Create an Azure AD protected API using Azure Functions and .NET Core 3.1" loading="lazy"></figure><p>If you open the newly created folder you should see the following file structure:</p><p>At this point we have our Function App, i.e. the Function App definiation, but no Functions or code yet :). To add a function we need to run the following command:</p><pre><code class="language-bash">func function create --name &lt;yourFunctionName&gt; --language C#</code></pre><p>You will be prompted to choose a Trigger (what makes the Function run) -&gt; Choose <code>Http Trigger</code></p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-48.png" class="kg-image" alt="Create an Azure AD protected API using Azure Functions and .NET Core 3.1" loading="lazy"></figure><p>We now have the boilerplate code to run an HTTP-trigger Function locally. You can easily test this by issusing the following command <code>func start</code> and navigating your browser to the URL designated by the Function Core tools:</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-49.png" class="kg-image" alt="Create an Azure AD protected API using Azure Functions and .NET Core 3.1" loading="lazy"></figure><p>So far so good! We have a functional Function! (see what I did there)?</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-50.png" class="kg-image" alt="Create an Azure AD protected API using Azure Functions and .NET Core 3.1" loading="lazy"></figure><h3 id="create-your-azure-ad-app-registrations">Create your Azure AD App Registrations</h3><p>For any app to be able to allow users to authenticate against Azure AD or validate access tokens, we need an App Registration. This will tell Azure AD what our app is supposed to do, what permissions it needs, where it will be running etc. Navigate to your Azure AD tenant and go to the <strong>App Registrations</strong> tab.</p><p>Create a new app, give it a meaningful name, select the <strong>Accounts in this organizational directory only</strong> option and press <strong>Register</strong>! Next, navigate to the <strong>Expose an API</strong> tab and Add a new Scope. The most important bit is the <strong>Scope name</strong> which in our case should be <code>access_as_user</code>. Make sure to press save when you&apos;re done.</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-51.png" class="kg-image" alt="Create an Azure AD protected API using Azure Functions and .NET Core 3.1" loading="lazy"></figure><p>This is all we need for our Function-based API. We also need to create a second App Registration that will be used to authenticate users and acquire the appropriate access tokens to call the API. Create a new App Registration, give it a decent name, select Single Tenant apps and make sure to give it the right <strong>Redirect URI</strong>, if you&apos;re planning on using a web app or a client like PostMan to make the calls. Press <strong>Register</strong> when you are ready.</p><p>Next we need to navigate to the Authentication tab to ensure that everything is right. Check the Redirect URI and that both the Access and ID tokens are checked. If you are using Postman, you&apos;ll need to configure a Client Secret in the <strong>Certificates &amp; secrets</strong> tab. Make sure to store it somewhere safe as you won&apos;t be able to access it again after you leave this page - you could, however, create a new one, they are cheap :) Finally, we need to configure the <strong>API Permissions</strong> tab. Select <strong>Add Permission</strong> and in the new tab, you need to select <strong>My APIs</strong> where you should be able to find the App Registration we created in the previous step:</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-52.png" class="kg-image" alt="Create an Azure AD protected API using Azure Functions and .NET Core 3.1" loading="lazy"></figure><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-53.png" class="kg-image" alt="Create an Azure AD protected API using Azure Functions and .NET Core 3.1" loading="lazy"></figure><p>That&apos;s all we need for the API and Client apps :) Let&apos;s write some code!!!!</p><h3 id="configure-token-validation-in-the-azure-function">Configure token validation in the Azure Function</h3><p>First we need to start by adding the appropriate NuGet packages and references to our Function app. Open your <code>*.csproj</code> file and add the following references:</p><pre><code class="language-xml">&lt;PackageReference Include=&quot;System.IdentityModel.Tokens.Jwt&quot; Version=&quot;6.6.0&quot; /&gt;
&lt;PackageReference Include=&quot;Microsoft.IdentityModel.Protocols.OpenIdConnect&quot; Version=&quot;6.6.0&quot; /&gt;
&lt;PackageReference Include=&quot;Microsoft.Azure.Functions.Extensions&quot; Version=&quot;1.0.0&quot; /&gt;</code></pre><p>The first two packages are required for us to work with the JWT tokens while the last one allows us to load the necessary Azure AD settings from the <code>local.settings.json</code> file.</p><p>Next, we need to add the necesary config settings for the Function to be able to find the appropriate Azure AD and validate the tokens. While developing locally, we will be using the settings in the <code>local.settings.json</code> file but in Production we will be using the Function App Settings since the json file is only used for local development and is not copied in the artifacts that get deployed to Azure. Open the file and add the following json, making sure to use the Tenant ID and Client ID of <strong>your </strong>API App Registration:</p><pre><code class="language-json">&quot;AzureAd&quot;: {
	&quot;Instance&quot;: &quot;&lt;YourAADInstanceName&gt;.onmicrosoft.com&quot;,
	&quot;TenantId&quot;: &quot;b55f0c51-61a7-aaaa-1111-33569b247796&quot;,
	&quot;ClientId&quot;: &quot;f40d746f-f8e4-1111-aaaa-2943f87066ba&quot;
}</code></pre><p>Next we need to wire up the JWT token validation. Open your <code>&lt;YourFunctionName.cs</code> file and add the following code:</p><!--kg-card-begin: html--><script src="https://gist.github.com/cmatskas/0290c023d6cc7f64e3521314cfe3dcd9.js"></script><!--kg-card-end: html--><p>Let&apos;s break it down a bit as there are a few components here. We have one main method<code>async Run()</code> that is the entry point for our Function. it also calls all the helper methods to retrieve and validate the token. The first helper method <code>GetAzureADConfiguration()</code> loads the config settings for Azure AD. The second helper method grabs the access token from the HTTP header. The bulk of the work is then done in the <code>ValidateToken()</code> method that leverages the <code>JwtSecurityTokenHandler</code> class and Open ID Connect (OIDC) to validate the token against AAD and return a <code>ClaimsPrincipal</code>. In the <code>Run()</code> method, we check that the token is passed in the HTTP Request, we then validate it and, for the sake of simplicity, we return either the name of the user that acquired the token, or an error message if the token expired or failed to validate. </p><p>We are now ready to put our code to the test! From your favorite shell, run</p><pre><code class="language-bash">func start</code></pre><p>This will run the Function locally and provide us with the test URL. </p><blockquote>Optional step: I use ngrok to configure a public endpoint for anything that needs to be accessible on port 80 or 443 as I like to test from remote machines. </blockquote><p>Use your tool of choice to authenticate and call your Azure Function. I like to work with Postman these days, &#xA0;so here&apos;s an example that shows Postman hitting my Function app using the ngrok public URL</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-55.png" class="kg-image" alt="Create an Azure AD protected API using Azure Functions and .NET Core 3.1" loading="lazy"></figure><p>This is it. If for whatever reason your Function doesn&apos;t work, doublecheck your settings in the <code>local.settings.json</code> to ensure that you have the right Instance, TenantID and ClientID values.</p><h4 id="publishing-to-azure-going-live">Publishing to Azure - going live</h4><p>As a next step, we want to ensure that our Function works as expected once deployed in Azure. </p><p>At this point, it&apos;s important to take a small detour to discuss about EazyAuth and the fact that both Azure Web Apps and Azure Functions provide a turn-key configuration option to add authentication to your apps or Functions without the need to write any code. So, although I could have spared myself the ~15 lines of code that does the token validation, I wanted to make sure that </p><ol><li>I can develop and test the code locally</li><li>I may want to add extra authorization checks (next blog???) to ensure that the incoming access token has the appopriate scopes and maybe user roles/claims attached to it. </li></ol><p>So there are some pros and cons with each approach. All I have to say is that there are some amazing features that you can leverage if they meet your needs and EazyAuth is one of them:)</p><p>Ok! We are now ready to deploy/publish our Function to Azure and I&apos;m going to take the <s>lazy</s> efficient choice and let the Azure Functions Extension in VS Code do all the work. Open the extension and find the Publish button as per the image below:</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-56.png" class="kg-image" alt="Create an Azure AD protected API using Azure Functions and .NET Core 3.1" loading="lazy"></figure><p>The wizard will guide you through the process and you get the choice to either create a new Function App or use an existing one. If you select an existing one, note that any previous code in that Function app will be overwritten so this is not an iterative action - it&apos;s full on deployment! </p><p>Once the publish process is completed, we have one last step and that&apos;s to configure the Function App settings (remember that the <code>local.settings.json</code> file is not copied to prod). We can also do this from the comfort of VS Code using the extension (this functionality is available in the Core tools as well). Select the Function App you just created or deployed, expand the treeview and find the <code>Application Settings</code> section. Right click and select <strong>Add New Setting</strong>:</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-57.png" class="kg-image" alt="Create an Azure AD protected API using Azure Functions and .NET Core 3.1" loading="lazy"></figure><p>We need to add 3 settings:</p><pre><code>Name: AzureAd:Instance, Value: &lt;YourADTenantName&gt;.onmicrosoft.com
Name: AzureAd:TenantId, Value &lt;yourTenantId&gt;
Name: AzureAd:CientId, Value &lt;yourClientId&gt;</code></pre><p>We need to add the AzureAd: in the name as the code expects a top level section, i.e. AzureAd with the 3 other properties under it in the hierarchy, as per the <code>local.settings.json</code> configuration. In the end, the Function App settings should look like this:</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-59.png" class="kg-image" alt="Create an Azure AD protected API using Azure Functions and .NET Core 3.1" loading="lazy"></figure><p>If everything went according to plan and we followed all the steps above, we should be able to use Postman or any other tool/code to call the Function. The live Function URL should look something like this: <code><a href="https://cmfuncwithauth.azurewebsites.net/api/HttpAuth">https://&lt;yourFunctionAppName&gt;.azurewebsites.net/api/&lt;</a>yourFunctionName&gt;</code></p><h3 id="summary">Summary</h3><p>In this blog post, we saw what it takes to create a protected API using .NET Core 3.1 with Azure Functions and Azure AD. We were able to develop and test everything locally using my favorite tools and then we pushed the Function to a <em>production</em> environment. Using this approach, we know that the code works seamlessly between the different environments and we have full control on how Authorization is taking place</p><h3 id="upcoming-blogs">Upcoming blogs</h3><ul><li>Add scope and claims validation to our Function</li><li>Call Graph and return the data to the user, in effect implementing an On Behalf Of (user) flow</li></ul><p>Let me know on Twitter if you want me to cover any other scenarios using Serverless and Azure AD</p>]]></content:encoded></item><item><title><![CDATA[Create a protected .NET Core 3.1 API that calls into MS Graph on behalf of a Power App]]></title><description><![CDATA[<p>In this blog post I&apos;m going to explain how to create a .NET Core API that accepts authenticated requests from a Power App, validates the user and then makes a call into MS Graph to retrieve the appropriate data. All secured via Azure AD while using the latest</p>]]></description><link>https://cmatskas.com/create-a-protected-api-that-calls-in-ms-graph-on-behalf-of-a-power-app/</link><guid isPermaLink="false">631b77ad4e615c07ca3eace6</guid><category><![CDATA[ASP.NET Core]]></category><category><![CDATA[Power Apps]]></category><category><![CDATA[MS Graph]]></category><category><![CDATA[Azure AD]]></category><category><![CDATA[security]]></category><dc:creator><![CDATA[Christos Matskas]]></dc:creator><pubDate>Sat, 16 May 2020 02:00:34 GMT</pubDate><content:encoded><![CDATA[<p>In this blog post I&apos;m going to explain how to create a .NET Core API that accepts authenticated requests from a Power App, validates the user and then makes a call into MS Graph to retrieve the appropriate data. All secured via Azure AD while using the latest (and funkiest) <a href="https://github.com/AzureAD/microsoft-identity-web">Microsoft.Identity.Web</a> library for authentication and the MS Graph SDK for getting the Graph &#xA0;data. </p><blockquote>If you haven&apos;t used the Microsoft.Identity.Web NuGet package yet, &#xA0;then I would urge you to have a look at the <a href="https://github.com/AzureAD/microsoft-identity-web">repo </a>and start integrating it with your ASP.NET Core apps. The team designed this library to makes working with authentication a lot more straightforward by hiding a lot of the complexities. </blockquote><p>I&apos;ll admit it &#xA0;- this is a big one... there are a few moving components and requires a bit of a setup but we will break it down to individual components to make it more &quot;digestible&quot;. At a high level, this is what we need to do:</p><ol><li>Create 2 app registrations in Azure Active Directory<br> &#xA0; &#xA0;a) one for the client app (i.e the Power App)<br> &#xA0; &#xA0;b) one for the API</li><li>Write a .NET Core API that <br>	2.1 accepts authenticated requests from clients (i.e. the Power App in this &#xA0; &#xA0; case)<br> &#xA0; &#xA0;2.2 makes calls to MS Graph to retrieve data</li><li>Create a Power App that calls our API to get the data</li></ol><p>So let&apos;s get started!</p><h3 id="1-create-the-graph-service-api-app-registration-in-azure-ad">1. Create the Graph Service API app registration in Azure AD</h3><p>Navigate to Azure AD in App Registrations to register a new application for our ASP.NET Core Web API. The API will act as our middleware (think of it as air traffic controller) that provides access to MS Graph data. </p><blockquote>Side note: we could have made our lives easier by calling MS Graph directly from PowerApps, as this is built-in functionality, but <br>a) I wanted to prove that this is possible via a custom API<br>b) In the future we will be adding role-based access so the PowerApp will have different access rights based on who&apos;s using it :)</blockquote><p>Back in the Azure portal &gt; Azure AD resource &gt; App Registrations, let&apos;s register a new app. Give it a meaningful <strong>Name</strong>, select the <strong>Single Tenant </strong>option and press <strong>Register</strong>. We will be coming back to configure the Redirect URI later (once we have our .NET Core API set up) but for now we can ignore this.</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-15.png" class="kg-image" alt loading="lazy"></figure><p>Next, we need to configure the appropriate Graph API permissions as this is the application that will be requesting the Graph data. Go to the <strong>API Permissions</strong> blade and click on the <strong>Add Permission</strong> button and select <strong>Microsoft Graph</strong></p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-16.png" class="kg-image" alt loading="lazy"></figure><p>Search for <code>User.Read</code> to jump into the User API and select the following 3 permissions and press the <strong>Add Permissions </strong>button at the bottom of the page:</p><ul><li>User.Read</li><li>User.ReadAll</li><li>User.ReadWrite</li></ul><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-17.png" class="kg-image" alt loading="lazy"></figure><p>The next step is important. As you can see, One of the permissions requires Admin Consent. Since this app registration is for an API and there is no user interaction, i.e the users can&apos;t consent to permissions, we need to <strong>Grant admin consent</strong> so that the API can access the necessary data. </p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-18.png" class="kg-image" alt loading="lazy"></figure><p>Up to this point, we configured an app that can access the MS Graph data. Next, we need to expose our API so that authenticated client apps can access it. To do this, navigate to the <strong>Expose an API</strong> blade and hit the <strong>Add a scope</strong> button. In the new tab that opens, provide the appropriate information as per the image below:</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-19.png" class="kg-image" alt loading="lazy"></figure><p>The most important bit is the <code>access_as_user</code> scope name. At the end, press the <strong>Add Scope</strong> button at the bottom of the page. Finally, what we need to do is configure a client secret to allow the API to authenticate against Azure AD. Navigate to the <strong>Certificates &amp; Secrets</strong> blade and add a new client secret.</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-20.png" class="kg-image" alt loading="lazy"></figure><p>Make sure to copy the value somewhere (temporary and securely) as we will need to add it to our .NET Core Web API configuration. This concludes our Service API app registration. To recap:</p><ul><li>We created a new app registration</li><li>We configured the API Permissions</li><li>We exposed the API and created a scope</li><li>We created a client secret to use in our .NET Core API code</li></ul><h3 id="2-create-the-graph-client-api-app-registration-in-azure-ad">2. Create the Graph Client API app registration in Azure AD</h3><p>Next, we need to create an app registration for the client app. The app registration will be used by any app (in this case our Power App) to call into Azure AD to get an access token with the right permission and so that it can then pass it to our API.</p><p>In the Azure Portal &gt; Azure AD &gt; App Registrations, create a new registration:</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-22.png" class="kg-image" alt loading="lazy"></figure><p>One important configuration setting here the Redirect URI. Because we are using PowerApps, the Redirect URI needs to be set to:<a href="https://global.consent.azure-apim.net/redirect"><code>https://global.consent.azure-apim.net/redirect</code></a>. Normally, this would be the Redirect URI autogenerated by your Power App Connector. However:</p><blockquote>This is currently a temporary workaround as the PowerApps connector that uses Azure AD with OAuth2 is failing to autogenerate the redirect URI which we would otherwise be configuring here. This is currently being looked at so by the time you do it you should use the standard procedure.</blockquote><p>Also note that you can configure multiple Redirect URIs later. This means that you can have one for your local dev environment i.e. <code>https://localhost:&lt;port&gt;</code>, one for Postman or whichever tool you like to use and one for your test/QA environment.</p><p>Next, we need to configure a Client Secret. use the steps from the previous app registration instructions for this. On the Authentication blade, make sure that both Access Tokens and ID Tokens are selected:</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-23.png" class="kg-image" alt loading="lazy"></figure><p>The final step is to define the appropriate permissions for our client app. Navigate to the <strong>API Permissions</strong> blade and hit the<strong> Add a permission</strong> button. Go to the <strong>My APIs</strong> selection and find the app we registered in the previous step</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-24.png" class="kg-image" alt loading="lazy"></figure><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-25.png" class="kg-image" alt loading="lazy"></figure><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-26.png" class="kg-image" alt loading="lazy"></figure><p>We now have all we need for our client app to authenticate users and return the appropriate access tokens so that users can hit our API and retrieve the Graph data. In this section:</p><ul><li>We created a client app to authenticate users</li><li>We created a client secret</li><li>We added the appropriate Redirect URI(s)</li><li>We configure the appropriate permissions to speak to our exposed API</li></ul><h3 id="3-create-a-protected-net-core-api-to-pull-data-from-ms-graph">3. Create a protected .NET Core API to pull data from MS Graph </h3><p>Time to write some code :) This bit will be fun to write as .NET Core and the new Microsoft.Identity.Web have greatly improved the overall experience when it comes to validating tokens and talking to the Graph API. </p><p>Open up Visual Studio and create a new, blank .NET Core Web API. Next we need to add 3 NuGet packages:</p><ul><li>Microsoft.Identity.Web (v 0.1.2-preview)</li><li>Microsoft.Graph (v 3.5)</li><li>Swashbuckle.AspNetCore (v 5.4.1)</li></ul><p>With the solution created, we can now go back to our API app registration (the one we created in step 1) and configure the <strong>Redirect URL</strong> with our API URL (most likely <code>https://localhost:5001</code> if you&apos;re running on Kestrel.</p><p>To configure authentication, we start with the <code>appsettings.json</code> file. At the top of the file, add the following json:</p><pre><code class="language-json">&quot;AzureAd&quot;: {
    &quot;Instance&quot;: &quot;https://login.microsoftonline.com/&quot;,
    &quot;ClientId&quot;: &quot;&lt;The app ID from the API app registration - step 1&quot;,
    &quot;ClientSecret&quot;: &quot;&lt;your client secret&gt;&quot;,
    &quot;Domain&quot;: &quot;&lt;your domain e.g cmatskas.onmicrosoft.com&gt;&quot;,
    &quot;TenantId&quot;: &quot;&lt;your Azure AD tenant ID&gt;&quot;
  },</code></pre><p>Next, we need to wire up the authentication in our <code>Startup.cs</code>. Open the file and add the following code in the <code>ConfigureServices()</code> method:</p><pre><code class="language-C#">services.AddProtectedWebApi(Configuration)
        .AddProtectedWebApiCallsProtectedWebApi(Configuration)
        .AddInMemoryTokenCaches();</code></pre><p>In the <code>Configure()</code> method, remember to add the following:</p><pre><code class="language-c#">app.UseAuthentication();</code></pre><p>As you can see, with less than 4 lines of code, we&apos;ve instructed our API to authenticate incoming requests and check for valid tokens <code>AddProtectedWebApi</code>, wire up the call to another API, i.e the GraphAPI with <code>.AddProtectedWebApiCallsProtectedWebApi(Configuration)</code> and configure a token cache, albeit only an in memory one in this instance. </p><p>Next we need to create an Auth provider that we can pass to the <code>GraphServiceClient</code>. This helper class or service, will be later injected to our controller to retrieve and return the Graph data. </p><!--kg-card-begin: html--><script src="https://gist.github.com/cmatskas/4d8c6c24aaa935095fdd1232c258cfde.js"></script><!--kg-card-end: html--><p>This class grabs the access token for the user from the incoming request and exposes a <code>DelegateAuthentiationProvider</code>.</p><p>Let&apos;s go back to our <code>Startup.cs</code> and register this as a <strong>scoped</strong> service so that we can later inject it to our controller(s). In the <code>ConfigureServices()</code> method, add the following line: </p><pre><code class="language-c#">services.AddScoped&lt;GraphClientAuthProvider&gt;();
</code></pre><p>Notice that although I would have liked for the <code>GraphClientAuthProvider</code> to be registered as a <strong>singleton</strong>, since this services relies on the <code>ITokenAcquisition</code> service which is also <strong>scoped</strong>, we need to match on the scope.</p><p>We also need to create an additional class that will provide an instance of <code>GraphServiceClient</code>. Add the following code to the new class:</p><!--kg-card-begin: html--><script src="https://gist.github.com/cmatskas/701080780127e73eccb2d3b576bb081b.js"></script><!--kg-card-end: html--><p>We also need to ensure that we register this as a <strong>scoped</strong> service as it depends on the <code>GraphClientAuthProvider</code>. In the <code>ConfigureServices()</code> method, in <code>startup.cs</code> add the following line:</p><pre><code>services.AddScoped&lt;GraphClient&gt;();</code></pre><p>Next, we can build our <code>GraphController.cs</code>. We are going to expose two methods:</p><ul><li>Get() =&gt; an HTTP GET method that returns all users in the directory</li><li>Get(upn) =&gt; an HTTP GET method that returns a single user or <code>me</code> depending on the request parameters passed </li></ul><p>Also notice how we enforce that all requests should be authenticated using the <code>[Authorize]</code> attribute on the controller declaration. &#xA0;</p><!--kg-card-begin: html--><script src="https://gist.github.com/cmatskas/8d94332af458a076675521867b14e4a9.js"></script><!--kg-card-end: html--><blockquote>NOTE: if you attempt to return raw Graph objects then you will get a serialization exception as the Graph SDK hasn&apos;t been ported to work with System.Text.Json (the default json serializer in .NET Core 3.1). You can work around it by using DTOs or configure your controller to work with Newtonsoft.Json by registering the serializer in your <code>Startup.cs</code> as per: <code>services.AddControllers().AddNewtonsoftJson();</code></blockquote><p>Finally, we need to wire up the Swashbuckle functionality to get the OpenAPI/swagger tools to expose the API to external consumers, including our Power App! Let&apos;s go back in our <code>Startup.cs</code> class and add the following code in the <code>ConfigureServices()</code> method:</p><pre><code class="language-c#">services.AddSwaggerGen(c =&gt;
{
    c.SwaggerDoc(&quot;v1&quot;, new OpenApiInfo { Title = &quot;Graph Service API&quot;, Version = &quot;v1&quot; });
});</code></pre><p>In the <code>Configure()</code> method, add the following code:</p><pre><code class="language-c#">app.UseSwagger();
app.UseSwaggerUI(c =&gt;{c.SwaggerEndpoint(&quot;/swagger/v1/swagger.json&quot;, &quot;Graph Service API&quot;);});</code></pre><p>This wraps the necessary steps to create an AAD protected API that calls into MS Graph. To summarize once again:</p><ul><li>We added 3 NuGet packages</li><li>We configured the <code>appsetting.json</code> file with the AD app details</li><li>We updated the <code>Startup.cs</code> class to wire up the authentication, DI and OpenAPI</li><li>We created an Auth provider for our <code>GraphServiceClient</code></li><li>We created a protected API that calls into MS Graph and returns user data</li></ul><h3 id="4-test-the-net-core-api">4. Test the .NET Core API</h3><p>Firstly, we can spin up the API in Visual Studio and navigate to <code>https://localhost:&lt;portnumber&gt;/swagger</code> to ensure that the Open API UI and json can be accessed. This is what you should see:</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-27.png" class="kg-image" alt loading="lazy"></figure><p>This is great but so far I haven&apos;t tested the API authentication and token validation at all. To do this, I decided to use Ngrok (free service) and Postman (free tool). Ngrok allow me to spin up a proxy that exposed my localhost to the world and Postman is great for easily acquiring OAuth tokens and sending requests. If you haven&apos;t used NGrok before, register and download the tool. Unzip the executable and put it somewhere that makes sense. I went with <code>Program Files\ngrok</code>. I also added this directory to my PATH env variables so I can easily access ngrok from any shell. Now all we have to do to expose our API to the world is to start our API and then fire up your favorite shell and type: <br><code>ngrok http https://localhost:&lt;yourport&gt;</code></p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-28.png" class="kg-image" alt loading="lazy"></figure><p>I can now access my API from anywhere by navigating to <code>https://5ab05a0e.ngrok.io</code>! How awesome is this? </p><p>Let&apos;s fire up Postman and run some requests. Create a new request and set it to a GET with the following URL <code>http://53b2317c.ngrok.io/api/graph</code>. </p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-31.png" class="kg-image" alt loading="lazy"></figure><p>We now need to acquire an access token. Change to the Authentication tab and select OAuth2 from the dropdown list:</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-32.png" class="kg-image" alt loading="lazy"></figure><p>We are now ready to request an access token. Click on the Get New Access Token button and fill in the appropriate fields using the details from your Client App registration we setup on step 2 with some gotchas I&apos;ll cover below</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-33.png" class="kg-image" alt loading="lazy"></figure><p>First of all, you&apos;ll notice that the Callback URL is configured for Postman so you&apos;ll need to make sure that this URL is configure in your <strong>App Registration &gt; Authentication</strong> as one of the <strong>Redirect URLs</strong></p><p>Secondly, you&apos;ll need to know your Auth URL and Access Token URLs. You can locate these in the <strong>Azure AD&gt;App Registrations</strong> blade under <strong>Endpoints</strong>. </p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-34.png" class="kg-image" alt loading="lazy"></figure><p>Finally, and this is the important bit, notice the <strong>Scope. </strong>Our client app needs to explicitly ask for this scope with all API requests. This will then be swapped by the API and the appropriate Graph scopes will be applied. We can now execute the request with the newly acquired token :)</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-35.png" class="kg-image" alt loading="lazy"></figure><p>We have now tested our API and have confirmed that we can use the Client app details registered in Azure AD to acquire a token that we can then pass to the API to ask for Graph data! Next step: PowerApps FTW!</p><h3 id="5-create-a-power-app-that-consumes-a-custom-api">5. Create a Power App that consumes a custom API</h3><p>PowerApps allows pro and citizen developers to create data driven solutions quickly and efficiently using built-in, predefined components, layouts and connectors. The platform comes with a plethora of services you can pull data from such as SQL, ServiceNow, SharePoint etc etc. But where I see the great potential is bringing the two worlds together (pro + citizen devs) to achieve even more. With custom connectors and a lot more on the way, I can now leverage datasets and custom APIs in my PowerApps in seconds. And with the deep integration of Azure AD I can have a secure solution built on top of my existing implementation.</p><p>For our example, I&apos;m going to create a Power App that connects securely to my protected API, built with .NET Core 3.1 and pull MS Graph data. So let&apos;s get started:</p><p>Navigate to <code>make.powerapps.com</code>, go to under <strong>Data&gt;Custom Connector </strong>and select the <strong>New Custom Connector&gt;Import and OpenAPI file</strong></p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-36.png" class="kg-image" alt loading="lazy"></figure><p>Grab the json file from you OpenAPI endpoint (like we tested at step 4) and upload it here:</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-37.png" class="kg-image" alt loading="lazy"></figure><p>In General, you only need to provide the <code>Host</code> details. In our case, this is the ngrok URL as per below:</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-38.png" class="kg-image" alt loading="lazy"></figure><p>In the Security tab, we need to configure our connection. </p><ul><li>Authentication Type: OAuth2 </li><li>Identity Provider: Azure Active Directory</li><li>Resource URL: the API URI (you can get this from the Expose API blade of the API app registration in the Azure AD portal)</li><li>Scope: the API URI + /.default (e.g <code>api://c369fdb7-d70b-4651-9e5c-4379c3863d78/.default</code></li></ul><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-39.png" class="kg-image" alt loading="lazy"></figure><p>In the Definition tab, we need to do a little bit of work to configure the <code>Response</code> to allow our Power App to easily wire controls to the API data. To do this, grab a copy of the json output from the <code>Get()</code> method of our GraphController and click in the Response box to configure the expected response object</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-40.png" class="kg-image" alt loading="lazy"></figure><p>On the new tab, press the <strong>Import from Sample</strong> button:</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-41.png" class="kg-image" alt loading="lazy"></figure><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-42.png" class="kg-image" alt loading="lazy"></figure><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-43.png" class="kg-image" alt loading="lazy"></figure><p>As a last step, we need to create a new connection. Press the <strong>Update Connector</strong> at the top to save the current configuration and proceed to test the available API operations. This will ensure that our connector is working as expected. The first time you create a connection, you&apos;ll be prompted to login to your AD your tenant.</p><p>We can now create our UI. Navigate to the <strong>+ Create</strong> tab and use the app template that you like the most. I chose a Canvas app from blank and I dropped a Vertical Gallery to host my Graph data. Select the whole control and configure the Data Source: <code>Items = GraphServiceAPI.GetAllUsers()</code>.</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-44.png" class="kg-image" alt loading="lazy"></figure><p>If everything worked as expected, you should be able to see your data in the dropdown! So far so good :). We now need to configure the individual controls to the Graph data. You can click on each label and either configure the value at the top bar using the: <code>ThisItem.&lt;property&gt;</code> or you can use the Properties tab on the right and configure the same value in the Text property as per below:</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-45.png" class="kg-image" alt loading="lazy"></figure><p>Choose the same for the second label and we now have a vertical list of all the organization users displayed on my Power App in a few steps. </p><p>By leveraging Azure AD and, <strong>Microsoft.Identity.Web</strong> and Graph SDKs, I was able to create a protected API that provides secured and controlled access to MS Graph. You can find the .NET Core API solution on <a href="https://github.com/cmatskas/ProtectedAPICallsMsGraph">GitHub</a> ready to build and run.</p><blockquote>Special thanks to <a href="https://azure.com/azureandchill">JP</a> and <a href="https://twitter.com/davidfowl">David Fowler</a> for their guidance and help to shape the code. And thanks to <a href="https://twitter.com/98codes">Greg Hurlman</a> for helping with the Power Apps implementation - I&apos;m such a n00b :)</blockquote><p>Coming next: Role-based authorization in WebAPI. We will see how we can use Azure AD role to implement authorization to the API resources so when different users work with our PowerApp, they get different access rights.</p>]]></content:encoded></item><item><title><![CDATA[Create a .NET Core Deamon app that calls MSGraph with a certificate]]></title><description><![CDATA[<p>A couple of days ago I blogged about pulling OneDrive data with MS Graph in .NET Core. I wrote all the code in a console app because it was the simplest way to get me what I needed. Mind you, a console app is not the best way when it</p>]]></description><link>https://cmatskas.com/create-a-net-core-deamon-app-that-calls-msgraph-with-a-certificate/</link><guid isPermaLink="false">631b77ad4e615c07ca3eace5</guid><category><![CDATA[MS Graph]]></category><category><![CDATA[Azure AD]]></category><category><![CDATA[.NET Core]]></category><dc:creator><![CDATA[Christos Matskas]]></dc:creator><pubDate>Fri, 08 May 2020 00:05:15 GMT</pubDate><media:content url="https://cmatskas.com/content/images/2020/05/Daemon-app-with-MS-Graph-1.png" medium="image"/><content:encoded><![CDATA[<img src="https://cmatskas.com/content/images/2020/05/Daemon-app-with-MS-Graph-1.png" alt="Create a .NET Core Deamon app that calls MSGraph with a certificate"><p>A couple of days ago I blogged about pulling OneDrive data with MS Graph in .NET Core. I wrote all the code in a console app because it was the simplest way to get me what I needed. Mind you, a console app is not the best way when it comes to creating user interactive apps but it&apos;s convenient. However, convenience comes with a price: I ended up writing a console app that needs user interaction for authenticating the app. So what is the right way to do this? How can we create a headless app/daemon that can still call into MS Graph securely and efficiently?</p><p>With a bit of research I found what I needed. Azure AD allows apps to run without user interaction using the Client Credential flow. To achieve this, we need to register an app in Azure AD and configure either a Client Secret or a Certificate that we can use to authenticate and query MS Graph.</p><p>There are 3 distinct components in this project:</p><ol><li>Create the certificate to use for authentication</li><li>Register the app in Azure AD and configure the appropriate API Permissions</li><li>Implement the code to do the magic</li></ol><h3 id="create-a-self-signed-certificate">Create a self-signed certificate</h3><p>As I mentioned earlier, the Client Credentials flow allows us to speak with Azure AD using a Client ID and either a Client Secret or a certificate. The tricky bit with the Client Secret is storing and managing the plain-text value securely. Developers tend to focus on building things and security is regularly overlooked. Therefore, it shouldn&apos;t come as a surprise that we find client secrets scattered in places that they should never be like: checked in source code, environment variables or config files. This can significantly compromise the security of your data. Certificates, on the other hand, tend to be managed better by enterprises so they should be preferred over Client Secrets. </p><p>Not all is lost for Client Secrets though. For example, we could use a combination of Managed Identities, Azure AD and Azure Key Vault to securely store and retrieve Client Secrets without compromising the integrity and security of your app. I <a href="https://cmatskas.com/secure-app-development-with-azure-ad-key-vault-and-managed-identities/">wrote before</a> how to achieve this tight security loop so feel free to take a look if you still want to go down this route. </p><p>Now let&apos;s get back to the task at hand. We need a certificate! If you already have one, you&apos;re sorted. Just follow the commands below to export it - assuming you have the certificate thumbprint at hand (looks like this: <code>483219ae06a1f8a85b1e500b94575559feab3f3b</code>)</p><pre><code class="language-powershell">$cert = Get-ChildItem -Path Cert:\CurrentUser\My\&lt;Certificate Thumbprint&gt;
Export-Certificate -Cert $cert -FilePath c:\users\cmatskas\certWithKey.cer</code></pre><p>If you don&apos;t have a certificate, we can create one using PowerShell before exporting for use in the AAD portal.</p><pre><code class="language-powershell">$cert=New-SelfSignedCertificate -Subject &quot;CN=ConsoleAppCert&quot; -CertStoreLocation &quot;Cert:\CurrentUser\My&quot; -KeyExportPolicy Exportable
Export-Certificate -Cert $cert -FilePath c:\users\cmatskas\certWithKey_2.cer</code></pre><p>Note that we need to export the key as a <code>*.cer</code> as this is the format expected by Azure AD. Also, we are using the <code>Export-Certificate</code> cmdlet instead of the <code>Export-PfxCertificate</code> one because we don&apos;t need to export the private key.</p><p>We now have a certificate in the personal store and exported, ready to be configured in our Azure AD app, which is the next step.</p><h3 id="create-and-configure-the-azure-ad-app">Create and configure the Azure AD App</h3><p>Our daemon will use an Azure AD app to authenticate and retrieve the appropriate permissions to call into the Graph API. Head to the Azure AD Portal &gt; App Registrations and click on the <strong>New Registration</strong>:</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-6.png" class="kg-image" alt="Create a .NET Core Deamon app that calls MSGraph with a certificate" loading="lazy"></figure><p>Give it a meaningful name, select accounts in my Org only and click on Register. Leave all other options empty.</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-7.png" class="kg-image" alt="Create a .NET Core Deamon app that calls MSGraph with a certificate" loading="lazy"></figure><p>Next, we need to navigate to the Certificates &amp; Secrets section to add our exported certificate. </p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-8.png" class="kg-image" alt="Create a .NET Core Deamon app that calls MSGraph with a certificate" loading="lazy"></figure><p>Finally, we need to configure the API permissions. Because, unlike my previous examples, in this case we know that there will be no user to authenticate against Azure AD at runtime. Therefore, we need to declare in advance and approve the app permissions to ensure that there are no access issues. Head over to API Permissions, click on <strong>Add a permission</strong></p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-9.png" class="kg-image" alt="Create a .NET Core Deamon app that calls MSGraph with a certificate" loading="lazy"></figure><p>Select <strong>Microsfot Graph, </strong>choose <strong>Application Permissions</strong> and search for the <code>Users.Read.All</code> permission. Make sure to click on the <strong>Add permissions</strong> at the bottom of the page. </p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-10.png" class="kg-image" alt="Create a .NET Core Deamon app that calls MSGraph with a certificate" loading="lazy"></figure><p>Almost there, one more small, but very important, step. Our app registration now has a certificate for authentication and the necessary permissions to read users&apos; data from the directory. However, if we were to try to retrieve the data now, (I use Postman to test Graph calls) we would get a 403 error message like this</p><pre><code class="language-json">{
  &quot;error&quot;: {
    &quot;code&quot;: &quot;Authorization_RequestDenied&quot;,
    &quot;message&quot;: &quot;Insufficient privileges to complete the operation.&quot;,
    &quot;innerError&quot;: {
      &quot;request-id&quot;: &quot;d1b49a31-dd42-415b-b36e-3c2959881411&quot;,
      &quot;date&quot;: &quot;2020-05-07T21:57:57&quot;
    }
  }
}</code></pre><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-11.png" class="kg-image" alt="Create a .NET Core Deamon app that calls MSGraph with a certificate" loading="lazy"></figure><p>That&apos;s because the app permissions need to be granted consent by an admin. Let&apos;s go ahead and do this (if you don&apos;t have admin permissions, you will need to ask your AD admin to consent these for you). In the API Permissions tab, press the <strong>Grant admin consent for &lt;your tenant name&gt;</strong></p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-12.png" class="kg-image" alt="Create a .NET Core Deamon app that calls MSGraph with a certificate" loading="lazy"></figure><p>Now we are good to rock &apos;n roll!</p><h3 id="create-the-daemon-app">Create the daemon app</h3><p>For this example I decided to use a .NET Core console app to be my headless &quot;daemon&quot; that grabs a list of all the users in my test AD tenant. Although the example is fairly basic, once you wire up all the components, the full Graph API functionality is at your disposal to implement the solution that meets your needs.</p><p>In Visual Studio 2019, create a new console app that targets .NET Core 3.1. Next we need to add the necessary NuGet packages for Graph, Auth and config settings:</p><ul><li>Microsoft.Graph.Beta</li><li>Microsoft.Identity.Client</li><li>Microsoft.Extensions.Configuration</li><li>Microsoft.Extensions.Configuration.Binder</li><li>Microsoft.Extensions.Configuration.Json</li></ul><p>Add an <code>appsettings.json</code> file and populate the appropriate values</p><pre><code class="language-json">  &quot;Scopes&quot;: &quot;https://graph.microsoft.com/.default&quot;,
  &quot;Tenant&quot;: &quot;&lt;Your Tenant Id&gt;&quot;,
  &quot;ClientId&quot;: &quot;&lt;Your Client Id&gt;&quot;,
  &quot;CertificateName&quot;: &quot;CN=ConsoleAppCert&quot;</code></pre><p>The <code>CertificateName</code> value should be different as it&apos;s likely that the name of your certificate is different, unless you followed my instructions verbatim earlier. </p><blockquote>Unlike in apps with UI where the users are expected to log in and consent to permissions, when we create daemon apps the permisions have to be pre-declared and pre-approved for the application to work . However, we still have to provide a scope. The scope for MS Graph is always <a href="https://graph.microsoft.com/.default"><code>https://graph.microsoft.com/.default</code></a></blockquote><p>Next, add a new class named <code>AuthenticationConfig.cs</code> and add the following code:</p><pre><code class="language-C#"> public class AuthenticationConfig
    {
        public string Scopes { get; set; } = &quot;https://graph.microsoft.com/.default&quot;;
        public string Tenant { get; set; }
        public string ClientId { get; set; }
        public string CertificateName { get; set; }
    }</code></pre><p>We now need to add a new class to handle the authentication process for us. Create a new class <code>ClientCredentialsAuthProvider</code> and add the following code:</p><!--kg-card-begin: html--><script src="https://gist.github.com/cmatskas/a5bb3f0d8d6c84adc777bd42e00ca131.js"></script><!--kg-card-end: html--><p>This class gets the authentication token. It also retrieves the necessary certificate so that we can securely identify against Azure AD.</p><p>For the next step, we are adding an MS Graph helper class to do the necessary call(s) to the Graph API. Create a new class <code>GraphHelper.cs</code> and add the following code: </p><!--kg-card-begin: html--><script src="https://gist.github.com/cmatskas/6c4eec9d7a7686a917c3273c0191beb3.js"></script><!--kg-card-end: html--><p>Finally, we are going to wire everything up in the <code>Program.cs</code>. The final code shoud look like this:</p><!--kg-card-begin: html--><script src="https://gist.github.com/cmatskas/68f35b5aa51d9621d580026aface35b7.js"></script><!--kg-card-end: html--><p>Let&apos;s run the app and see the magic happen:</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-13.png" class="kg-image" alt="Create a .NET Core Deamon app that calls MSGraph with a certificate" loading="lazy"></figure><p>The code successfully authenticates in Azure AD and then pulls all the users in my test tenant. It&apos;s great to see everything working as expected, without any user interaction. </p><p>If you get an error like the one below, make sure that you have added and consented to the appropriate Graph API permissions in the Azure AD App Registration:</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-14.png" class="kg-image" alt="Create a .NET Core Deamon app that calls MSGraph with a certificate" loading="lazy"></figure><h3 id="conclusion">Conclusion</h3><p>If you need to create a headless/daemon app that calls into MS Graph, there are a couple of steps that you need to follow in order to get everything wired up. You need </p><ul><li>a certificate to avoid storing client secrets insecurely,</li><li>an app registration in Azure AD with pre-declared and pre-consented permissions</li><li>a few lines of code to put all of it together</li></ul><p>I hope that this blog helps you get started with Azure AD and MS Graph but feel free to ping me if you have any questions.</p>]]></content:encoded></item><item><title><![CDATA[Working with OneDrive data and MS Graph in .NET Core]]></title><description><![CDATA[Learn how to interact with your OneDrive data via the GraphAPI, Azure AD and .NET Core. In this blog post I explain how to use .NET Core and the Graph API with the latest MSAL library to authenticate a user and then provide access to the OneDrive data. Full code sample also available on GitHub]]></description><link>https://cmatskas.com/working-with-onedrive-data-with-ms-graph-and-net-core/</link><guid isPermaLink="false">631b77ad4e615c07ca3eace4</guid><category><![CDATA[Azure AD]]></category><category><![CDATA[MS Graph]]></category><category><![CDATA[.NET Core]]></category><dc:creator><![CDATA[Christos Matskas]]></dc:creator><pubDate>Wed, 06 May 2020 02:48:32 GMT</pubDate><media:content url="https://cmatskas.com/content/images/2020/05/OneDrive-with-Graph-and-.NET-Core-1.png" medium="image"/><content:encoded><![CDATA[<img src="https://cmatskas.com/content/images/2020/05/OneDrive-with-Graph-and-.NET-Core-1.png" alt="Working with OneDrive data and MS Graph in .NET Core"><p>It&apos;s been a very long time since I tried to access my OneDrive data programmatically and I was curious to find out what the new experience is like. Especially since MS Graph now allows you to interact with your OneDrive data programmatically using .NET Core. The nice thing is that I didn&apos;t have to start from scratch and I was able to get the project off the ground quickly using one of the existing MS Graph tutorials. The code for this project is loosely based on <a href="https://docs.microsoft.com/en-us/graph/tutorials/dotnet-core">this .NET Core sample</a>. And it took a little bit of experimentation and looking up the Graph API documentation to find out how to make calls to my OneDrive via the <a href="https://docs.microsoft.com/en-us/graph/api/resources/onedrive?view=graph-rest-beta">MS Graph Files API</a>.</p><p>But before we even touch the code, we can get a feel of what it looks like to work with the Graph API for OneDrive via the <a href="https://developer.microsoft.com/en-us/graph/graph-explorer#">Graph Explorer</a> - I truly love this tool as it allows me to get a quick glance into the possibilities of MS Graph. </p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image.png" class="kg-image" alt="Working with OneDrive data and MS Graph in .NET Core" loading="lazy"></figure><p>Now that I have &#xA0;a good grasp of what I can do with with MS Graph, I&apos;m ready to start playing with the code. For this project, we have the following components:</p><ul><li> .NET Core 3.1 </li><li>Visual Studio Code </li><li>MSAL (Microsoft Authentication Library)</li><li>Graph SD</li></ul><p>And since I&apos;m using a console app, I am going with <a href="https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-device-code">Device Code Flow</a> for the authentication. <em>The device code flow is a type of authentication flow that is designed for native applications (desktop, mobile&#x2026;) which are by nature considered &#x201C;insecure&#x201D; (in the sense that you do not have direct control over the execution context)</em>.</p><h3 id="create-the-net-console-app">Create the .NET console app</h3><p>Open the command prompt of choice and type the following to create the console app and add the appropriate dependencies/NuGet packages:</p><pre><code>mkdir OneDriveWithMsGraph
cd OneDriveWithMSGraph
dotnet new console

dotnet add package Microsoft.Extensions.Configuration.UserSecrets --version 3.1.2
dotnet add package Microsoft.Identity.Client --version 4.10.0
dotnet add package Microsoft.Graph --version 3.0.1</code></pre><p>We now have a basic .NET Console app. The packages above add MS Graph and MSAL libraries as well as a standard .NET Core config extension where we can store user secrets such as API Keys etc that can be used during development. Although this is a bit of an overkill and for this exercise we don&apos;t have any sensitive information to store, it&apos;s a really good practice to follow :)</p><h3 id="register-your-azure-ad-app">Register your Azure AD app</h3><p>Next, we need to create an App registration in Azure Active Directory to allow our users to interact with their OneDrive data. For this scenario, I opted for a single-tenant, line of business (LOB) app assuming that we only want to give access to our corporate OneDrive data. It&apos;s a subtle configuration change in the AAD App with significant connotations. If you opt in for another registration model, the app can also allow be used to access personal OneDrive data using Microsoft Account.</p><p>To register a new application, head over to the Azure AD blade in the Azure Portal. </p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-1.png" class="kg-image" alt="Working with OneDrive data and MS Graph in .NET Core" loading="lazy"></figure><p>Ensure to set the Redirect URI to <code>https://login.microsoftonline.com/common/oauth2/nativeclient</code>. Next, navigate to the Authentication tab and set the <strong>Default Client Type</strong> option to <strong>Yes </strong>under <strong>Advanced Settings</strong></p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-2.png" class="kg-image" alt="Working with OneDrive data and MS Graph in .NET Core" loading="lazy"></figure><p>Go back to the Overview and grab both the Application ID and Tenant ID values as we will need them in our app. Our Azure AD configuration is complete</p><h3 id="implement-the-authentication-code">Implement the Authentication code</h3><p>Back in our .NET console app let&apos;s add the AppId to our our local secrets. Open the console and type the following:</p><pre><code>dotnet user-secrets init
dotnet user-secrets set appId &quot;YOUR_APP_ID_HERE&quot;
dotnet user-secrets set scopes &quot;User.Read;Files.ReadWriteAll;Files.ReadWriteAppFolder&quot;</code></pre><p>We also need to create a new class named <code>DeviceCodeAuthProvider</code> and add the following code to perform the authentication: </p><!--kg-card-begin: html--><script src="https://gist.github.com/cmatskas/f981f7d43d816d1731d240958b9fab7a.js"></script><!--kg-card-end: html--><p>The difference here, when compared to the sample I based my code on, is that I&apos;m explicitly configuring the my app to work with TenantId using the <code>.WithAuthority(AadAuthorityAudience.AzureAdMyOrg, true)</code> and <code>.WithTenantId(&lt;YourTenantId&gt;)</code> as per the complete code below:</p><pre><code>    _msalClient = PublicClientApplicationBuilder
                .Create(appId)
                .WithAuthority(AadAuthorityAudience.AzureAdMyOrg, true)
                .WithTenantId(&quot;&lt;YourTenantId&gt;&quot;)
                .Build();</code></pre><h3 id="add-the-graph-api-calls">Add the Graph API calls</h3><p>Next, we need to should add a <code>GraphHelper.cs</code> class to do the necessary MS Graph calls. Notably, we have 3 main methods:</p><ul><li>GetMeAsync()</li><li>GetOneDriveAsync()</li><li>GetDriveContentsAsync() </li></ul><!--kg-card-begin: html--><script src="https://gist.github.com/cmatskas/5054de5ea2ad145378fbe1b84d22fe37.js"></script><!--kg-card-end: html--><h3 id="make-it-all-work-onedrive-with-ms-graph">Make it all work - OneDrive with MS Graph</h3><p>The last step is to implement the code that calls our helpers and pulls the OneDrive data we need. Open the <code>Program.cs</code> file and paste the following code:</p><!--kg-card-begin: html--><script src="https://gist.github.com/cmatskas/c5280f4f58730877174c8a2e401a21f1.js"></script><!--kg-card-end: html--><p>The code above:</p><ul><li>Creates an appconfig and pulls our secrets in</li><li>Initializes the authentication provider helper class</li><li>Passes the auth provider to the GraphClient</li><li>Provides an interactive way for the user to pull the data in the console app</li></ul><p>If you run the code the first time and select option &quot;1&quot; you are presented with your Authentication Token. &#xA0;</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-5.png" class="kg-image" alt="Working with OneDrive data and MS Graph in .NET Core" loading="lazy"></figure><p>You can grab your authentication token and use the <a href="https://jwt.com">jwt.ms</a> website to inspect it like in the example below (always handy if you want to ensure that your jwt tokens are in order:</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-3.png" class="kg-image" alt="Working with OneDrive data and MS Graph in .NET Core" loading="lazy"></figure><p>Running the app and selecting option 2 or option 3 returns the following results respectively:</p><figure class="kg-card kg-image-card"><img src="https://cmatskas.com/content/images/2020/05/image-4.png" class="kg-image" alt="Working with OneDrive data and MS Graph in .NET Core" loading="lazy"></figure><p>Fairly basic functionality so far but with all this in place, we are now able to start adding, removing editing files and folders in our OneDrive. In effect, we can programmatically do whatever the UI offers and more!</p><p>As always, you can find a fully working code sample on <a href="https://github.com/cmatskas/OneDriveWithMSGraph">GitHub</a>.</p><h3 id="summary">Summary</h3><p>I was pleasantly suprised to see that MS Graph and MSAL have transfored the way we programmatically interact with not just OneDrive but all our Office365 data. The next time you are creating an app for your enterprise, think about how you can delight your users and create richer, more immersive experiences by leveraging the power of MS Graph and MSAL. Let me know what you think and feel free to reach out if you have any questions :)</p>]]></content:encoded></item></channel></rss>