[MUSIC]
Matthijs Hoekstra: Hello. My name is  Matthijs
Hoekstra. I'm a Program Manager in the
Azure Identity Engineering Organization. And in
this video, we're going to talk about protecting your
APIs. Well, let's talk about authorization. We have
talked about authentication where you login users,
this is about protecting resources, we call
this authorization.
So, when you talk about protecting APIs or authorization,
there's different places where this actually starts
happening. My browser single page app might be calling
an API, maybe I've got a native application or a
background process who has to be calling my API,
but sometimes APIs call APIs as well and there's
different ways we can do it and actually help have you
flow your user's information through those APIs as well.
When you protect an API with Azure Active Directory,
first of all, we have to register your API.
Remember, everything in Azure Active Directory is an
application, so doesn't matter if it's a website,
a single page application, a background process for
PowerShell or .NET application, or your API,
Azure Active Directory or Azure Active Directory B2C,
all the same, have to know about your application.
So, first of all, you have to register the app.
Then we can define what kind of permissions your
application, or your API, actually needs to expose.
It's a best practice to keep a least privileged approach,
you can create one set of permissions, so that's an
all or nothing approach.
And that's okay, we see it often happening in Azure,
but you have the capabilities with the permission and
consent framework to make it more granular.
Try to be conservative with what kind of information
users actually have to consent to.
So, don't try to go I want access to everything and all,
that might scare away your users, just try to build it up.
So, once it's all done and an application starts calling
your API, you're the resource. We talked in another
video about identity and access tokens.
If you're a resource, you care about access tokens,
this is actually the only time you're allowed to look
inside of access tokens. Since you're the API,
you have the registration, you have to contract between
Azure Active Directory and yourself, you know what's
actually going on inside of these tokens.
If it's encrypted, you actually know the keys, so as a
resource or an API, you actually are allowed,
and you should validate access tokens.
We do advise you to use either middleware or an existing
library. To do this incorrectly makes your app less
secure and it's actually really hard to do it secure
as well. You as a developer for your API,
you are responsible to apply and enforce permissions.
That's not something we do.
So, once we send you the access token, you have to make
sure that this user calling your API is actually allowed
to do the things they want to do.
And delegated permissions, make sure they don't exceed
what the signed in user is allowed to do.
You are the developer who is responsible to build that
model, so if I need access to a mailbox, all mailboxes but
I only have access to one, Exchange is actually
determining if that user has access or not.
That's not something Azure Active Directory does for you.
We grant you the access token with the permissions inside
which we send along, but in the end, the resource is
responsible to figure out if what the user tries to do is
actually okay.
So, let's look at the portal and how you set up an
application with APIs.
So, again, we are back in my most favorite blade in Azure
Portal, which is the Azure Active Directory Portal and we
can register applications here.
So, let's just do a new one for this demo. Demo API.
We talked about single and multi-tenancy in one of our
videos, an API can be a multi-tenant application as well.
So, our Microsoft Graph APIs are all multi-tenant,
that means that anybody with an AAD account can access
that API in the context of their own directory.
I'm going to create a single tenant API for now because
it's only going to be used by my own organization.
The next thing I need to set up is those permissions we
just talked about. I go to API permissions,
I can actually add my own permissions, sorry,
expose an API, I can actually add my own permissions.
Scopes, permissions are the same thing.
First of all, it will pop up this URI.
Every scope or permission has to be unique.
I think well wait a minute, when I use the Graph API,
I can actually just use user.read. That's correct.
We call this a global scope. We call ourselves special, so
user.read is actually graph.microsoft.net/user.read.
We just remove that stuff for readability, but in the end
it has to be unique. So, this can be anything,
any string, just leave it as your unique app ID but this
could be something you come up as long as the string
is unique in your tenant. In here, I can actually
create my own permissions, for example, files.read.
In the consent and permission video, we talked about user
and admin consent role permissions, this is the setting
where you decide which one it is.
Okay, this permission is both for users and admins or only
for admins and what is the text you actually want to show
to the user. Read users files.
Allow the app to read users files.
And the user consent window. Read users files, and allow the
app to read users files.
The state can be enabled or disabled, but let's enable it
for now and add a scope.
So, at this point, if I want to use this API,
my client application can actually ask for this permission
and that will end up as a scope in a token.
So, I just created my own files.read permissions.
Let me go back to the CactusAPI. We talked about
this API in the permission and consent framework
video, it has a few permissions. Catalog View Published
and Catalog View All. That's the ones we use in the
quiz, so this is how we create it. And I choose to not
use a GUID, I use just microsoftidentity.dev,
that's the name of my developer tenant.
That's it. That's how you create a permission and
from now on, an application can actually request
that permission and your API will receive those permissions
inside of the access token.
So, any API secured with Azure AD will require a valid
access token and we have chosen to use a so called JWT,
or JSON web token.
That's the same format we use for ID tokens.
This is also the reason why developers, when they start
dealing with ID tokens, and then with access tokens,
they're like what a minute, I can read these things
and there's a lot of interesting information inside
of those access tokens, I want to use that information
to start my client. Don't do that. The resource and
the IDP have a contract if they start encrypting the
token, you might not be able to read it in a client.
A client should never touch an access token,
it should only pass along to the API.
And a JWT consists of a header, a payload, and a
signature. Some folks might even have heard of
introspection, some other IDPs so what they do,
they receive a binary blob, an access token, and
they actually call back to the IDP and say well,
I just received this access token, can you tell
me what it is? And the IDP will actually tell the
resource what the access token contains.
We at Microsoft decided not to do that.
It also has to do with a lot of load, we have billions of
authentications every day, every round trip we can save
actually saves us a lot of money and resources and also
response time, so that's why we have a readable format for
access tokens, the resource can actually validate
themselves. Again, jwt.ms is a really good resource
to actually display information about access tokens
and ID tokens and explains what the claims in
the tokens are.
When you validate access tokens, please use a library for
signature verification and the decoding of your JWT.
If you do it yourself, you open yourself up for security
risks, so please don't do it.
And the general guidelines are first of all, make sure the
audience claim is your app ID, so also your API is an app
ID, that needs to be the same. That means that the
access token is actually meant for you.
Make sure the issuer is actually the ones you trust.
Make sure the token is coming from us.
It has to be valid, so you have to prevent people
replaying an old token.
It has to be immutable.
Your object ID and the subject are good options,
so these things will not change when users actually
can change their names or even their email addresses.
People do get married and divorced and things will happen,
or companies get acquired.
Make sure the tokens are actually signed within the valid
algorithm. And this link will actually give you more
information about the tokens and what you should
do when you start manually validating those.
We also have application permissions.
We talked about in a previous video, sometimes you have an
application process running in the background and it needs
to be able to do certain tasks as well. We unfortunately
don't have a UI in the portal to actually build
application permissions, you have to do that manually in
the manifest, which I'll show you in a minute.
Application permissions are implemented as application
rules. Applications do not authenticate as a user,
they authenticate as themselves and we use client credentials
to authenticate applications against APIs.
Once the application authenticates and gets an access
token, the access token is passed through the API,
and instead of a scope in the token, we actually have
roles in a token, which you have to use to figure out what
permissions it asked for and what the application tries to do.
So, let me show you how to create application permissions.
My CactusAPI actually already has an application
permission. How do I know?
Well, let me show you how I grant permission or ask for
permissions in my client application.
I go to API permissions, I can add permissions,
this is the best practice to do to set up the application,
what kind of permissions it needs.
I go to, instead of just Microsoft Graph, I go to my APIs,
and here's my CactusAPI.
And it has a delegated and application permission.
Look at the delegated permissions, it has Catalog.View.All
and Catalog.View.Published, those are the ones I just
created through the UI as well.
But it also has an application permission that's called
Catalog.View.All.
So, I can actually build a background process which calls
the Catalog.View.All and for example exports the information.
Going back to my API, again, there's no UI. For the user
delegated permissions, I have the UI. But for the one I
just talked about, the app permissions, I actually have to
add it to the manifest manually.
I'm looking for the roles part, I'm looking for a type
application. This is the application permission and
it's called Catalog.View.All.
A gotcha is if you want to create an application
permission with the same name as a user delegated
permission, you have to make sure that the value and the
ID are the same as the user delegated permission.
And you can find those if you go scroll down, OAuth2
permissions, there's a Catalog.View.All.
You have to make sure that you use this ID for your app
permissions ID as well. So, the name and ID have to
be the same, and the description. But again, you have
to add a user of an application role in a manifest
with a description and all that kind of stuff to make
sure that this application permission is visible.
So, let me show you how you can validate tokens manually.
Typically, that's something you should do automatically,
but I want you to understand the concepts of what the
steps are when we actually are validating those tokens.
So, let me switch to Visual Studio and I got an
application here, it's a WPF app, a client app,
it's calling a service, and what I did in the service,
in the global asax.cs file is create a method which is
always called when authentication needs to happen for
an API request. And this is the one where I actually start
doing things manually. I'm going to start this app a
few times and since I'm talking all the time, it will
time out, so I might have to restart the application
a couple of times because of time out messages,
so you're aware of that and bear with me for now.
My background service is starting, there you go.
I sign in and it will immediately call.
Let's sign in as Megan.
Here the method is called. I can step through it.
First of all, we want to get the access token and there's
a value here. Let me copy this value.
And let me go to jwt.ms
and paste this token without the double quotes.
And it actually gives you a lot information.
The audience, this should be me, the issuer,
this is Microsoft we trust this one, the expiration
times and dates and all the stuff.
My app ID is here.
There's an IP address, there's a name, the OID which is
unique, I got my scope.
This is user_impersonation, that's not the right one.
The subject, the tenant ID, etc.
So, this example application, the API has just one
permission, it's called user_impersonation and that's the
scope which is actually available in this token.
When I go to the claims tab, we show this issuer, issued
at, not before, it explains all the different claims you
care about. This is all the information you can use
as a developer to figure out if this is what the user
tries to do, if that's okay, yes or no.
Switch back to Visual Studio.
I can continue browsing, it will check if there's a token
or whatnot.
So, how do I actually determine if the token is valid?
So, the interesting thing here is well this is checking if
that information we need to validate a token is cached or
not for the last 24 hours, and it should not be because
this is the first time I called it and here's the first
timeout I just talked about.
But we start the app.
And step over this stuff a bit quicker.
So, Azure Active Directory published so called
DiscoveryEndpoint. If I copy this URL and I actually
have this page open here, this is the information we
publish about our endpoint, what kind of modes we
support, where the public keys are, the authorization
and token endpoints, etc., etc.
This is what the middleware, the ASP.NET middleware also uses
to figure out how to set up proper AAD protection.
The interesting part I'm interested in here is the
public keys. So, every token has a signature,
that means that Azure Active Directory signs the
token and actually tells us what public key I should
use to validate that token.
If I go back to my decoded token, we tell you look,
this is the key ID which I used to sign this token.
The private key's kept by us heavily secured,
but the public key is something I should download
and figure out if the combination is correct.
So, in the keys when I go back to DiscoveryEndpoint,
there's a URL to where all the keys are if I opened up
that one. Here are actually the keys.
So, the one I just used should be here as well,
so here this is the key and we got a few because we
can rotate keys, and that might not happen all the time,
but it can happen. And here's the public key I
should download, and this is the public key I should
use to validate that signature.
Let's go back to my code.
So, hopefully this is the last time.
Since this information doesn't change that much,
we download this information,
we're going to cache it for 24 hours, and now
we're going to create a security token handler
and we're going to tell it okay, this are the
parameters I actually want you to validate.
I want to validate the audiences, I want to validate the
issuer, and I want to validate the sign in keys.
And this is where I actually validate the tokens,
so I still use some library to actually do the
validation and if that works out, I got a claims
principle with all the information in there as an
identity and the identity as claims, so all the
information is here.
I'm Megan, there's a role claim which is probably empty.
So, we just validated the token, we validated the
signature by downloading the public key, we validated if
it actually was coming from Azure Active Directory.
So, why would you ever change the validation behavior?
Why wouldn't I just do a default validation anyhow?
One of the reasons would be, for example, if you build a
multi-tenant application and validation goes for ID tokens
as well, I only want to allow people to login if they
actually bought a license.
So, in a database you keep a list of tenants or tenant IDs
so every time somebody logs in, you're going to validate
against that list and only allow users in your application
if they actually have bought a license.
Or for example, you're going to change behavior,
you're going to redirect people to a signup page,
like hey, welcome to our trial, click here to sign up
for 30 days free trial before you sign up for a real service.
So, depending on what you need, this would be the place to
do it. Another reason would be we've seen customers
building a service or an API which is protected by
both Azure Active Directory and some other directory,
but for example B2C, Azure Active Directory B2C.
At that time, you actually have to validate if your token
is actually coming from either one of the issuers,
so you cannot do it automatically, you have to check
against two issuers instead of just one.
So, that could be a reason to build an exception as well.
So, typically, as a developer you don't have to override
these settings, but there are reasons why you might
consider doing that.
The reason I showed you is just to make you understand
that what are all the steps involved. So the API is
actually talking directly to the IDP, Azure Active
Directory, downloading the public keys so it can validate the
tokens which are coming from your applications.
We did a CactusAPI example in the permission and consent
video. I want to refer back to that API and explain more
about what's happening here.
So, if I would ask you what does this access token allow
you to do, I would be curious what the answer is.
Okay, I know, stupid joke, nobody can read and encoded access
tokens. So, let's decode the access token and show you this.
So, in the CactusAPI call, so I'm the audience, that's
correct. There's an issuer here, there's an expiration
date, there's a name.
The ones we were interested in are the rules, I'm an
administrator, and the scope, Catalog.View.All and
Catalog.View.Published. This access token actually proves that
the application was granted consent to use both of
these scopes. So, you as a developer have to interpret
this token and figure out what the effective
permissions are.
So, what, for example, would this token allow you to do?
Catalog.View.All is a role, this means it's actually an
application permission. We can also see that because
the OID and the subject are the same.
That's an extra check you can do as a developer,
right now you know it's an application permission,
you have to look at the rules claim to figure out
what the application permission is.
I do have a little code sample to show you what it is.
So, if you really take a step back and try to understand
what you are needing to do as a developer,
it's actually not that complicated.
You get a token with a bunch of strings, we call it
claims, in the end you use all those claims and those
strings to get enough context to figure out what your
application is supposed to do.
Let me see. I got the catalog here.
So, I got an API here which is protected and it's
the Get Items API.
First of all, what I do is get my claims, get my scopes
from the token. This is the name of the claim.
It's a space separated list so we're going to do a split,
so we've got an array of scopes.
Then I'm going to find if there's scopes like catalog view
all or catalog view published is actually part of that
array, and if so, I set this little boolean.
I'm going to check if there's an administrator calling
this API. I need to figure out if the OID and the
subject are the same, so I know it's an app permission,
and if that's an app permission, I'm going to find
the scope, or the user role in this case, and if it's
catalog view all I know there's an app permission
with catalog view all available as well.
This is just all plumbing to figure out what's in that
token, so like string handling, it's nothing more than
that. Now, as a developer, I actually have to
calculate what the effective permission is.
In that catalog API example, an admin was allowed to see
all items, and in catalog view all was a user delegated
permission where an application was allowed to view all
items as well. And the app permission catalog view all
items, that should get you access to all the items as
well. So, I check all those requirements.
So if I'm an admin and the application has the permission
catalog view all or I use an app permission,
I'm going to return all items. If that's not the case,
it's catalog view published or it's catalog view
all scopes but I'm not an admin, I'm only going to
return all published items.
This is what you as a developer have to do to code
effective permissions.
So, it's nothing more than getting a bunch of strings,
and by using those strings figure out what the context
is and either grant or don't grant access to certain things.
Nothing will stop you by just ignoring all this stuff,
just look up the OID because that's this user, you look up
in your database okay, is this user allowed to do certain
things, yes or no?
And if that result doesn't come back so okay, I guess this
user's not allowed to call the API, you're going to throw
back an unauthorized.
Or you know what, by just doing this database lookup,
I'm going to figure out what the user is allowed to
do and then you can discuss about okay, well how do
I cache this information? I don't want to do a database
lookup for every API call, etc., etc.
That's all an exercise up to the developer, but those
things you have to do.
What I've seen typically is that the developers know
pretty well how to build authorization, that's not new,
the only change now is that all that information comes
back as claim inside of the principal name.
But if you have used all our schemes before, it's the same
old, same old.
So, since we are now in the token business and figuring
out what kind of strings and claims we have in tokens,
let's talk about more tokens.
So, let's talk about an enterprise application, single
tenant, for your LOB application.
The interesting part here is that we have the issuer,
which is login.microsoftonline.com and instead of /common,
it's going to be /tenantID.
And the tenant ID is also a claim in the token, and they
should be the same.
A multi-tenant application will have a different issuer,
so somebody else from a different tenant logs into your
application, it will be a different tenant ID.
So, if you go back to this one and this one, you can
actually see there's different tenant IDs.
The audience though is still the same.
So, if you build a multi-tenant application or an API,
you have to make sure that you use the tenant ID to
figure out what people are actually allowed to see.
So, your responsibility is to make sure that somebody from
one tenant will never see information in your application
from the other tenant.
So, you have to check the audience is correct, you have to
write a little bit of logic to make sure that the first
part of the issuer is actually us and the second part,
the tenant ID, is something you use to uniquely identify
the organization the user's coming from.
But what happens if I'm actually a guest in another
tenant? So, again, the issuer is there, the tenant
ID is there, but there will be an extra claim, it's
called IDP and it actually tells you from what tenant
the user is coming from.
Remember when we talked about in the first one of the
videos, where you can have the B2B guest scenario,
where you can invite people inside of your tenant,
so we do create an object for that user,
but we know that the user's coming from an IDP.
This is what you actually have to use to determine if a
user is a guest, yes or no.
I don't know if people have experience with Teams,
you can actually see Teams showing something like guest
behind a name. This is what they have to use to figure
out if somebody's a guest in a tenant, yes or no.
Again, so the tenant ID and the issuer have the same
unique ID but the IDP claim extra adds the information
about where the user's coming from and can actually store
their tenant ID as well because it's part of that claim.
If we invite a user from Gmail as a guest, which we can do
too, again, the issuer is there, the tenant ID is there,
the IDP will say gmail.com and we actually have a unique
name coming from Google you could use as well if you want to.
So, again, you're just handling a bunch of strings
in a token, and we just call it fancy claims.
If you use B2C or Azure Active Directory B2C,
you will see that the issuer is different.
There's an IDP Facebook because in this case in my account
I was using Facebook to login to my application.
It will give you an email address and a tenant ID as well.
This is just same format as a token with claims and you
can use to figure out well, it's a Facebook user,
should I allow this, yes or no, if you want to.
You just handle the strings, you handle the OID to
uniquely identify the user or the subject depending on
your scenario and you go from there.
So, at the start of this presentation, I also talked
about well, APIs can call APIs as well.
I don't know if people have used Kerberos and Kerberos
delegation in the past, that was actually a pain to setup
correctly and make it really secure.
There was a lot of permissions needed to set it up.
We have a better scenario with modern protocols for that
now and we call it On-Behalf-Of flow. It's a standard
OAuth protocol feature.
So, remember the scenario where an application can call an
API and this API actually has to call another API. And
instead of just knowing that this API is calling me,
I actually want to do that in the context of that user.
So, how does it work?
So, in one of the videos we explained how you get an ID
and access token, assume that my application logs in the
user, asks for permissions to call an API, I get an ID
token and an access token, I pass along the access token
to the API, it will authorize if this is all good,
I call the API and I get my results.
Now this API wants to call another protected API,
so what happens here?
Well, the API is going to talk to Azure Active Directory
and going to ask well, I need an access token to read the
user's profile using the Microsoft Graph on behalf of the
user. We have to send an access token and a secret
or a cert, which is only known by the API, to Azure
Active Directory. And we use that secret or cert
credential to get our client ID to login as the API
for my web application to Azure Active Directory.
We pass along the original access token, and if everything
checks out, we get a new access token.
This access token is passed along
to the API, the API actually checks the access token,
it has no clue this one is coming from another API or
not from the user. It still has all the information it
needs, so for this API, it just looks like the user is
calling this API with the on behalf permissions.
And if the token works out, you can grant access and we
will return you the result.
So, how you write this code. We have to get in the
Confidential Client Application Builder with your client
ID. You pass the secret. Well. don't do it, use the
certificate because it's more secur. And this is actually
the code you have to do. We use the name, you're going to
read the certificate, depending on what device you're
running on, it's stored for example in Windows,
it's stored in the credential store.
And after you get the token, you have read the certificate
or used the secret, you call the line
application.AcquireTokenOnBehalfOf with the scopes you
need to call, the access token.
This will result in an access token and you can use that
to do the next call. That's it.
So, we actually have a really nice model where you can
call an API, that API can call another API, you as a
client have no clue that all this is happening and that
can cascade along nicely.
So, this concludes the video talking about authorization,
protect your APIs, creating user delegated permissions,
creating app permissions, and even calling an API on behalf
of a user so you can actually chain along a few API calls.
I hope you liked this video and see you next time.
[MUSIC]
