ASP.NET Core 5.0 - Authentication Part 2: The Challenge - Dot Net Engineering Forum Feb 2021

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
welcome back in part one we learned about cookie-based authentication in asp.net core and discuss the difference between authentication and challenge today we're going to investigate the challenge portion a bit more so stick around [Music] if you recall in our sample application we created a custom login page with a username and a password and we hard coded the validation in the controller in other words we had no database behind it this would not be good enough for a real application in fact there are a number of issues you would really need to address to make it robust enough to use for example one-way encryption or hashing of the password in the database password changing and reset options recovery options multi-factor authentication options such as sms and biometric security because this can add more complexity to your app if you have to build it in it is better to delegate that responsibility to a library or a service outside of your project this way your project can focus on doing what it was designed to do and not worry about user management and identity there are many identity providers available most of them offer free services or free tiers google facebook twitter microsoft github or a few commercial providers such as auth xero and octa are also very popular and offer free tiers there are several ways to use an external identity provider some examples include saml authentication oauth 2.0 and openid connect which is really just an extension of oauth 2.0 today i will focus on openid connect first let's use google as our identity provider as it's one of the easiest to use you may need to set up a developer account in google i don't remember as i've had one set up for many years now so navigate to console.developers.google.com i think if you just have a gmail account you should be able to accept the terms and conditions and have access to this dashboard from this dashboard i have a few things but i'm going to go ahead and create a new project and we'll just call this auth sample project and you can attach it to an organization [Music] okay now that our project has been created i want to switch to it so i'm going to switch to auth sample now i'm going to go to credentials i don't have any credentials in here but what we're going to do is create one so i'm going to say create credentials and i'm going to create an oauth client id to create an oauth client id you must first set a product name on the consent screen so we're going to set it external to our organization means anybody with a google account will be able to log into our app as you see there's four steps that we'll need to complete we need to fill out the application name it's requiring me to put a support email if i had an app logo i could put one in if we were going to host this application we would need to have it on a specific domain we'll be running it as localhost so we don't need to fill out all this information for now if we were going to publish it though we would need to do that and we would need to add an authorized domain and then it's requiring me to put a developer contact email address the next thing it wants to know is certain scopes scopes express the permissions you request users to authorize for your app and allow your project to access specific types of private user data from their google account all right so what does this mean when we're talking about scopes here because we've delegated this responsibility of managing user identity over to a third party in this case google google has lots of information about you more than you think but they have all this information about you or a user if we want to use their authentication system we need to ask specifically for the pieces of information that we need for our application that's what this is all about so to add or remove scopes we just click this button and here are the three pieces of information that google is willing to give us there the user's email their profile and then their open id and their open id is a unique key that represents them so i'm going to select all of those because i want them all so sensitive scopes i haven't asked for any sensitive or restricted scopes there's a lot more we could ask for for instance we could ask for access to their google drive to their google photos if our application needed those types of things but we're not going to do that for now here's some optional info not going to put anything in here and finally the summary screen everything looks good and then we'll go back to the dashboard now we should be able to get our credentials this time around so we're going to create credentials an oauth client id and we're going to set the application type so oauth will work for a lot of different types of application today we're just doing a web application but you could create a windows uwp application a desktop app or an ios or an android app today we're going to just choose web application and we'll just leave it generically what we call it sample auth client good all right so we also need to add a callback uri and this will make more sense in just a second for now since our application is running on local host 5001 i'm just going to have a call back to auth so now we've been given a client id and a secret so we want to capture each of these so i've copied both of those and we'll need those in our application in just a minute here's a little pro tip if you're on windows 10 you should enable the clipboard history use windows plus v to access the clipboard history this will save you multiple trips when copying additionally if you enable syncing of clipboard history you can copy and paste between your devices for example from a laptop to a desktop or vice versa [Music] we want to connect our google credentials to do that we'll need to go to the startup and we're going to add a handler in here but before we can do that we need to grab it from nuget so i'm just going to go right click manage nuget packages and i'm going to search for microsoft dot asp.net core authentication and we'll see several items come up in here but the one i'm looking for is this one google and we'll go ahead and install that the latest version should be fine to connect this we're going to just chain off the end of cookie and we're going to say add google there's some options we'll need to pass one of the options will be our client id we'll paste those in and our client secret and our callback path which when i registered it i set that to slash auth if you recall now go to my clipboard history and i'm going to paste in the client id and i'm going to paste in the password normally we would put these in the user secrets file and use the configuration manager to get those values back out but for simplicity's sake i'm just going to hard code those in here so we can see this work we need to do a little bit of changing here in our overload for add authentication before when we passed this cookie authentication scheme as the the default it was the scheme for everything because we have now two authentication handlers in the system we need to be a little bit more specific about how we define things so we're going to be specific and we'll set a default scheme and that's going to be our cookie authentication defaults dot authentication scheme however we are now specifying a different challenge scheme so i want to set the challenge scheme we're going to configure the google account to be our challenge scheme there's one more thing i need to do we need to remove this roles property from the authorized attribute momentarily we're just not ready for it yet we'll put it back in later but for now i simply want to say if you're logged in with your with a google account then you're authorized to hit the secured endpoint i believe that's all we need so let's go and run this and see what happens click on secured now we're at a google prompt sign in with google to our application auth sample and i've created a test account that i'm going to put in here but let's just read this it says to continue google will share your name email address language preference and profile picture with auth sample our application so this is what we call the consent screen by signing in on this screen i'm giving permission to this application auth sample to receive this information from google okay now that we've signed in google has given us some info information it's given us the name bob tester and it gives it to us and give a name and surname his bob and tester again and his email address is bob and monics.com and his name identifier is this this is the open id or a unique identifier that google is providing for bob tester now if you recall on the consent screen it said it was going to give us a picture but i don't see a picture in here for photo for the user we'll have to go figure that out later but for now it works and we've gotten this information from him but it's all been a little bit magic i promise we'll unravel some of the mystery in a moment but let's check out log out first remember we didn't make any changes to that it seems to have locked out logged us out now if i click on secured again we'll see what happens and we're logged right back in in fact we didn't even get a prompt let's look at the developer tools specifically at the application tab under cookies and our local host we see that we have an asp.net core cookies that represents our logged in state if i click log out it clearly takes the cookie away however let's go to accounts.google.com now if we go to accounts.google.com it google still believes that i'm logged in which i am so i'm logged in with google even though i've logged out of the application so if we go back to our application we'll watch the network tab this time i'm going to clear this i'm going to click secured and this is going to happen pretty fast notice i have preserved log checked what happened is we bounced around a little bit when i click secure secured because it's protected by the authorize attribute it says you're not logged in it performs a redirect a 302 redirect if you can see this let me see if i can make this a bit bigger so if we look closely this particular request to our server results in a 302 redirect it gets the instruction to redirect to this location which is this location here accounts.google.com as you can see now accounts.google.com would normally throw up a login page or login prompt however since i'm still logged in at google.com as bob it says you're already logged in i will just redirect you back to the auth endpoint so if we look here it's saying 302 redirect and it says where i'm going to redirect back to localhost 5001 slash auth that's the callback url that we pre-registered with google in other words we said hey when you're done call us back at this end point we will be listening which we are and we receive some information here then and then it redirects back to the original page that we were headed to the secured page so that's kind of the that's the trail so far we registered an application at the google developer console we received oauth2 credentials so our app can use google as the idp or identity provider we imported a new get package from microsoft that makes connecting to google very easy and we connected and tested the handler to see if it works what exactly is a handler and how does it relate to authentication middleware it can be helpful to think of the authentication middleware as a general contractor who is in charge of building a house the general contractor understands the blueprints how everything fits together and establishes rules for the subcontractors to follow and integrate with subcontractors are specialists who understand their area of expertise they might be experts in plumbing electrical or even window installation likewise the authentication middleware is like the general who knows the blueprints how it fits and sets the rules handlers are subcontractors or specialists who understand different parts of the authentication process cookie and jwt handlers take care of creating and validating the tickets on each request while the oauth and open id handlers control the challenge schemes this subdivision of labor creates a flexible framework that can be mixed and matched according to the application's needs returning to our app i wanted to investigate the log out behavior remember when i click log out and then i return to secured and it just logs me right back in because you've made a quick trip to google recognize that i'm still logged in with google and just let me run into the app now that may be a desired behavior but what if we wanted to let the user choose a different google account to log into returning to our startup.cs file there's an option for the authorization endpoint which if we append on to the authorization endpoint a prompt equals consent that will instruct the authorization endpoint it will prompt them to select or allow the user to select a different user from the consent screen so let's add that and see what happens i'll click log out and then i'll go back to secured and this time i'm prompted to select an account now i can just choose bob tester or i could use another account in this case i'm just going to go ahead and log in with bob tester and i'm logged in again so that works good but what if i were on a public machine or a public computer and i logged in if i clicked log out i might expect that i would be automatically logged out of google account as well but that is not the case this is a good reason to use in private or incognito windows when you're on public machines tip for the day the oauth 2 and openid connect specifications don't provide a standardized mechanism for logging out of the idp or single sign-in provider like google but i can show you how to do it for google and the pattern will probably apply for other providers as well to accomplish this with google let's go to the home controller and let's go to this log out currently after we sign out this http contact sign out async it's only signing us out of the default scheme which is the cookie authentication scheme so it's doing that part really well it's removing the cookie and it's making the user session end but when we're done we just return back to the home page again if we want to log out at google as well then we need to redirect to google so i'm going to replace this one with this and we'll try to break it down here so what we'll be re doing is redirecting to google's idp logout url and then they have a continues equals and you need this for some reason you need to go to app engine.google.com and also log out and then when you're done this last continue tells it where to return to when we're done in other words come back to our application now you could send this anywhere it doesn't have to come back to your application but in this case that's what we want let's move that back to one line now let's run it and see what happens so now when we redirect to google we get this notice that the previous page is sending you to localhost 5001. now it takes us back to our application now when i click secured click on bob tester it prompts me for a password which is great returning to our code i think that's as much as i want to do with the add google handler and now i want to switch to using a generic openid connect handler instead first we'll need to install a nuget package from microsoft asp.net core authentication and we are looking for open id connect so i'm going to leave the add google down here for just a second let's add open id connect and we haven't done this in the past but i'm going to give this a specific name google id how about we call it google open id and then we'll configure the options and we'll need the same options as we have here we'll need to change our challenge scheme from google to google open id and because we've left this add google in here it's going to cause a problem notice that they're both listening at the same callback path it's going to be confusing which handler is actually supposed to listen to this route and complete the call so at this point i'm just going to comment this one out so we don't have a collision at that location and then put my semicolon one other thing that is needed here is for us to specify something called the authority all right let's run this and see what happens okay and now it logged us in and our logout should still work the same and it does if you remember earlier we never got a picture or photo for the user now that we're using open id we are notice this and there's the photo this could come in handy for our application if we want to display a small avatar or an image of the user who's logged in so what's the big difference between openid connect and the add google handler remember the add google handler is built on oauth 2.0 and while openid connect extends oauth 2.0 there are a few differences what you don't see inside of the add google handler is there's a number of endpoints that need to be configured besides the authority which is also embedded in there it also needs to know where the token endpoint is and a couple of other important endpoints and those are configured hard-coded inside of that at google endpoint open id connect takes a slightly different approach they use an endpoint called a well-known endpoint where they publish the other endpoints that are needed for the oauth mechanism we can take a look at that now if we go to accounts.google.com dot well-known open id configuration this is a common endpoint for open id servers dot well known slash open id configuration if you go to this endpoint you receive a json file with key endpoint information and other information located in it if we take a look here you'll see things like the authorization endpoint the token endpoint user info endpoint and this jwk s uri if the endpoint were to ever change for instance the user info endpoint to something like a v2 you wouldn't have to go and update that in your code because the configuration is discoverable the jwks uri is an important one if we click on this one what you will find in here are keys asymmetric keys these keys are used to verify and validate the token that is sent to you and we haven't talked much about the token yet but let's let's spend some time and talk about that let's return to the home controller in our secured action i want to get the id token and the way we do that is by calling get token async and id underscore token and it is async so let's do an await and convert this to an async method and return a task of i action result so we can make that work correctly okay so this will get the token off of the context now the token will only exist on the context if we in startup tell it that we want to save tokens and what they mean by save tokens is the token that we get from google which is an id token isn't automatically saved in the cookie by setting that to true we will save that token in the cookie now this is going to make our cookie larger fairly significantly larger in fact but if we need access to the tokens for some reason then we have to do this now let's set a breakpoint in our controller and run this and watch what happens when we get the token okay if i hover over the id token i get one back there it is so this token is in the form of a jwt or a jot token and let's learn a little bit more about jwts jwt or json web token often pronounced jot is a token that uses json notation to embed authentication and authorization claims for applications a chat is made up of three parts header payload and a signature the header contains information about the type of token it is jwt or jot and the algorithm used to encrypt the signature the payload contains the auth claims the signature is an encrypted block of data which will be used to verify the token's authenticity three parts are separated by a period character header period payload period signature making it easy to parse the first two parts header and payload contain base64 url encoded json data the signature is encrypted with asymmetric keys meaning that you can use a key from the idp to verify the signature but you cannot use those keys to create your own signature this is important to provide security to prevent tampering of the payload data in a token so the data can be trusted by a consuming application let's grab this token and let's go to a website called jwt.io crafted by auth0 and we'll paste it in to this location and you'll see that this website automatically decodes this for us using base64 url decoding we can see what's in the header and we can see what's in the payload and we can see that the signature is verified now the way that it did that is it had to go and get the public key that that's available that public key it found by looking at the issuer going to the well-known endpoint going to the jwk uris the json web keys finding the key that it needed that match this k id to verify that this signature is valid so this website did all of that automatically and your application can do the same thing now i want to demonstrate let's pull out the payload section and i'm going to go to revolt js website go to one of their utilities go to the base64 url decoder i'm just going to paste paste this in here and it always puts an extra space oops they take care of that they trim that on this website so now i have the the json from this so what i want to do is show what happens if we try to modify the token in in any way so let's gonna i'm just gonna try and change bob's last name from tester to jones and then i'll copy this back out and i'll go to the encoder page and again paste this in and encode it and you can't tell it's a little bit different but it's it has changed it so we'll find out what happens now if i copy this and i just paste over this purple block can i do that will it let me and it will let me okay so now the website has the new data and it decoded it and you'll notice that it decoded the payload properly now it thinks it's bob jones now you might think that's scary wait a minute if somebody can just modify their token or some bad actor key and then modify their token wouldn't that be a problem well look at what happened here the signature is no longer valid because the payload has been modified without the signature being updated it now declares this token is bad so that's the protection that's built into jwts is you can't really modify this as so long as you're checking the signature to make sure that that token is valid you should be finding these and you can trust the payload the next obvious question is why do i even need a token and the reality is you don't necessarily need the token at this point the token was important during login so that you could get the data about a user in a trusted way from a third party in this case google once you receive the token the handler extracts the claims from it and it puts those claims into a ticket that then gets encrypted into a cookie for you and really you have access to those claims throughout the session so you don't really need access to the token any longer however there are scenarios especially in enterprise where you may want to pass that token to another service or a microservice in that particular instance it becomes handy to have that token so you'll have to decide for your own application whether it makes sense to turn this save tokens on or not it does increase the size of your cookie so if you don't need it then don't put it in but if you do need that token and want to pass it down the chain somewhere then set save tokens equal to true one final thing i want to do is go back to our home controller and implement roles once again we turn that off temporarily while work while we were connecting google because we didn't have that set up but let's go back and reconnect that just like we did with cookie authentication we can do the same thing here and add an event the events for the openid connect handler are a little bit different than the ones for cookie we have quite a few more things in here access denied authentication failed authorization code received message received to identity provider to identity provider for sign out on remote failure remote sign out signed out callback direct ticket received token response received token validated and on user information received um there's probably a couple places we could put this but i think i want to do it on token validated hopefully that's correct we will see okay and for now i'm just going to i need to take a peek inside of the claims and see what they look what that looks like i'll go to the principal get the list of claims and let's put a break point here and we'll inspect that let's run this okay i'm going to hover over claims and we'll inspect this hopefully you can see this wonder if i can make this bigger all right it's pretty small but in here there is the type which is the name identifier and then here's the value so i'm going to grab this back out so this is bob's unique open id his identifier that you can uniquely identify as him from google what i really want to do is just put an if in here and said if context dot principle dot claims dot first or default let's see for claims or c dot type equals equals claim types dot name identifier then we want dot value equals okay if it equals that value then we know it's bob regardless of what his name says even if it says bob jones now instead of bob tester and we trust that key to be very unique even if he so even if he went back and changed his name we would know it was him so what we want to do is we want to create a claim and we want the claim types dot role and we're going to make him an admin and then we have to attach it to his in his principle and at this point if i were to try to do this let me try that again so what we need to do is do a i'm going to change this so if you try to just go to context.principle.identity and try to add a claim there is no way to add a claim on that what we need to do is create a claims identity well you can't see that anyway you need to cast it as a claims identity then you can take the claims identity and there's an option to add a claim and we'll just add that in now when we run it it will it should let us all the way through okay so now it's let us in here we look at his page he has this additional claim for admin okay so that worked pretty well we have covered a lot in this video we learned a bit about open id connect jwt user json web tokens in their structure we connected our app using the google handler and a generic open id connect handler to google and we re-implemented our authorization using the openid connect events there is still a lot to understand about openid connect and something known as oauth grant types or flows we will look more into flows in our next video when we connect a second idp octa into our application we will demonstrate how to allow multiple providers for people to choose from when logging into your application if you have any questions or topics you would like to see covered please leave me a message in the comments section and as always thanks for watching [Music] you
Info
Channel: Tony Spencer
Views: 9,670
Rating: 5 out of 5
Keywords: ASP.NET Core, Authentication, Authorization, MVC, Razor, web development, html, Microsoft, Google Auth, JWT, OpenIdConnect
Id: K0Z7GTOvbMo
Channel Id: undefined
Length: 36min 38sec (2198 seconds)
Published: Mon Feb 08 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.