Secure APIs with FastAPI and the Microsoft Identity Platform Transcripts
Chapter: Web and headless clients
Lecture: Demo: Building a console app that calls a secure FastAPI API
Login or
purchase this course
to watch this video and the rest of the course contents.
0:00
In the previous module, we looked at different application types and scenarios that we can
0:04
secure using Azure Active Directory. In this module will focus on a scenario where a
0:09
console app written in Python can securely call our FastAPI API to many
0:14
API's but you get the gist to enable our console application to authenticate and acquire an access. Talking to call our FastAPI.
0:21
We need to create a new app registration in Azure Active Directory. This app registration will be our first client app.
0:29
The console app is only one of the types of apps they can consume an API We could also have, for example,
0:35
a web app and mobile app or even another API all calling our API. In this instance
0:40
we would also have to create separate app registrations for its application type.
0:45
If you're wondering why we need different app registrations per application type besides the fact that
0:51
different app types require different authentication settings.
0:54
The different apps also allow for segregation and better security as well as providing the ability
1:00
to configure different levels of access at the application level. For example, a mobile app may be configured to allow read only access to our
1:09
data, whereas a desktop client or web app could provide a more complete and rich experience with read, write access.
1:15
Okay enough talking, let's switch to our Azure Active Directory and configure our app registration
1:20
If you don't remember how to get to Azure Active Directory, then just type aad.portal.Azure.com.
1:28
This takes you directly to one of the tenants that you may have signed in before and here was signing with the one that we created for this module,
1:35
navigate to Azure active directory and from there we want the app registration tab we've done
1:41
this before, remember but this time we're creating one for our console instead of an api let's create a new app registration.
1:49
We'll call it console-FastAPI I will leave everything else as default.
1:54
And click register next. We want to head to the authentication tab because here is
1:59
where we can figure the application type and the authentication flow. So click on authentication and add a platform.
2:07
The dialogue will guide you through the process. But as you can see straight away we have a mobile and desktop application web single
2:13
page and what have you in this instance. We want to choose mobile and desktop applications here we should have a customary directory
2:18
URI https local host and press configure we don't need to change anything else here. As we discussed in the previous module.
2:29
Our console application is non interactive and therefore we need to use a client credential flow to authenticate. We already have the client ID.
2:38
If we go to the overview page, you'll see that the client id's already sitting with us here. So now we need to create a new secret,
2:46
navigate to the certificates and secrets tab and here you'll notice that we have the option for certificates and client secrets. To keep things simple.
2:54
We will go with secrets. However it is best practice to use certificates. When you're running in production, let's create a new client secret.
3:04
Give it a name, console. Secret. Change the expiry date you can say to as long as you want.
3:12
I will choose three months from now and click add your secret will appear down here
3:17
make sure to copy the value and not the secret ID and put it somewhere temporarily so we can use it later.
3:23
It's an important thing to remember that secrets are valid for a specific period of time As with certificates, passwords do and should expire,
3:32
you should automate the monitoring and the securitization for your applications to ensure that your applications
3:38
remain safe and operational before you navigate away from this tab,
3:42
make sure to take a note of the client's secrets and store it somewhere temporarily until
3:46
we added to the application. Once you navigate away from this page, the secret is unreadable and you'll have to issue a new one.
3:54
I'll put in another part for now. And don't worry I will rotate my secrets as well before I forget we need to
4:00
also update our FastAPI app registration for our api to allow apps to authenticate
4:07
and grab an access token. Unlike api permissions we need to configure app roles for this and you can create an app role like so give it a name,
4:18
demo say applications or users and applications if you want to do so like here
4:24
and then give it the permission so app.weather and give it a meaningful description and
4:30
make sure to press apply. We already have that api permission here and this is
4:35
what it looks like. So in effect we have everything we need inside Azure Active directory and now we can move on to write some code.
4:42
Let's do this. So first things first, let me all let me open my console application and let's create a new directory for
4:49
our console app. So mkdir we'll call it Python console and then we'll change directory
4:58
into that and then in here now we can activate our virtual environment, Python VENV .venv.
5:08
It's done. And now we also want to activate this and that's activated. Let's open this directory in code because we need to add some files.
5:16
We need to add some libraries and we want to make sure that we can see what we're working with. Now you can use any editor one but my preferred editor
5:24
these days is VS Code. So first we need to add the requirements.txt to store our dependencies. Next we want to create the main.py.
5:33
That will contain our code. And finally, I also want to add a separate file to keep our Azure active directory configuration.
5:41
So config.json. Great. Let's see what kind of dependencies we need. Well we need 2 dependencies to make our application work.
5:50
One is 'msal' that's the official microsoft authentication,
5:54
library package and then the other one is requests because our console application will need to
5:59
craft and send the request to our Api save this one and let's switch to our config the first property when it is authority.
6:10
This points to our Azure Active directory and we're going to replace common.
6:15
If you were writing a multi tenant application then we could use common but since we know our directory we want to be explicit.
6:23
So we will add our explicit information here. I did not close the brackett here and there you go. Then we need our client
6:31
ID. Client secrets here. Make sure to copy it properly and don't miss any characters or add any characters. Otherwise it will not work.
6:41
And finally we want our scope we will copy this and change it slightly with
6:47
.default this setting this api scope will inform the authentication process that this is a console
6:55
application and that everything has been pre consented.
6:58
Remember that we pre consented data not been consent prior to this inside Azure Active directory for
7:03
our scopes and that translates to the .default. The .default in effect means that when
7:10
we authenticate Azure Active directory will return all the scopes that we have pre consented for if you were trying to use the previous name scope.
7:19
Our authentication would fail at this point we can restore our packages or if I jump here and run pip install requirements.
7:30
He should go and fetch the MSAL and request library and download them and add them to our project. And while we're here we might as well upgrade our
7:39
venv whatever you prefer the pronunciation to be. And now we're good to write some code open our main.py.
7:47
The first thing that we want to do is import our libraries import Json. So we can work with the config file import them msal to work with msal
7:57
and the authentication and import requests. Next we want to load our json data and as you can see copilot's writing the
8:06
code for me we'll soon be out of a job up will be msal.confidential client, this is confidential client application.
8:15
It assumes that this application is running on a server securely and therefore we can add
8:21
the credentials necessary to authenticate. The assumption is that this is secure. client_id= json data and then we have a client ID.
8:34
Then we have authority which is json data authority. And then finally client credential and we have the client idea authority in client credential safe
8:44
And now we want to grab our token. The standard practice with Azure Active directory is to first try to acquire a token silently
8:54
in case there's a cache somewhere that the token is stored that eliminates the need to
8:59
go back to Azure Active Directory and request the token but if the cache is not found or if the token is not found in the cache then we want to reach
9:07
out to Azure Active directory authenticate and grab the access token. Let's write this code result = app which are confidential client acquired,
9:18
token silently. Acquire token silent and then in here we're in the pass an array
9:25
of scopes so you can either do this in config.json and declared the scopes as an array or we can do it in code.
9:34
So here we can do json data and then open close brackets scope = none that's the first attempt and if not result therefore we don't have a token.
9:56
Let's go let's reach out and get it so acquired token for clients. Remember this scope needs to be array and we do it like so at
10:08
this point we assume that we have acquired a token so if access and this quote
10:14
token in result then we want to print said token just to make sure that we have it correctly result access token.
10:30
If not else print, result error or we can say authentication failure. That's totally up to you. Let's leave it at this.
10:42
Let's run the application to see whether we can acquire a token. Very nice. I always like to grab my token and validate that it is correct
10:52
And the easiest way to do this is by going to and browser typing jwt.ms or any other tool that you want to use to validate tokens and
11:05
then by pasting the token up there we can see that it is the application that we requested, the token for that as our audience.
11:12
That's our API. It came from the right tenant and it does include the right role. Now it doesn't, it doesn't look like a scope,
11:21
it looks like a role because this is an application role or it gets it as a role but it does have the right permission and our API should
11:29
read this one and translate accordingly. Remember the onus falls on the API to work with either scopes or rolls
11:36
to make sure that we can retrieve our data so far so good. There's one more step now to actually call our API here and now that we have
11:46
our access token. What we need to do next is we need to create a session request sessions.session and then here we need to add our header.
12:01
Sessions header's update. Oh my God, look at that sessions header update.
12:06
We need to add the authorization header with 'Bearer' space and our token at this point The next final step is to grab response equals session.
12:22
Get Json data, not from the graph end point, Json data to get from API and remember our API is running a local host for now. Local host,
12:35
I will use that auto completion to be a little more efficient. Remember it's API and then it's weather and finally we need to pass this
12:46
api I'll use Seattle quotes in the brackets. I also need to remove this print statement because now we know that everything is working
12:57
also we don't want to be printing out or logging our access tokens because that's private
13:01
and sensitive information that somebody can steal and call your API on your behalf but we
13:06
want to print the response from our session So here we'll have print response.content At this point our API is not running running this code will fail.
13:19
So what we want to do is we want to run it here. We have been sitting in the waiting so let's kick this off. It's running at the expected endpoint.
13:33
So if I were to run this code now we see data for Seattle if everything goes according to plan and there you have it the data is back,
13:42
it does the temperature, how it feels like and other information like temperature max temperature to expect pressure and humidity that is it.
13:51
We now have a console application that gets an access token and calls our api securely
13:56
using the right permissions. We can quickly test whether that worked out of the box by doing something here that will break things.
14:05
I always like to do that as well just to validate, we said in our API endpoint that are expected scope is app.weather.read
14:13
and we have that in our token, remember if we go back to our token you'll see that's their role. So what would happen if we said our
14:21
API has been configured for something else? Will this prove that we have the right information?
14:29
So we're running the API again with a different permission and if we go back to our console application now and run it,
14:38
we should receive an error message, bonus points. If you can think what their message would look like,
14:44
it's running, it's going to fail and there you have it, this is a 403 error message.
14:49
It says they're all claim does not contain the role all app.weather.read2. That's what we changed in our API or it was not found in the token.
14:59
It tells us in other words that we were unauthorized to access the API, even though we had an authenticated token so that proves that end
15:07
to end, we have a working solution next. We'll look on how to use a web app to call our API this time using a
15:15
.net front end just to mix things up a little bit. See you in a bit.