B2C in .NET MAUI apps *without* MSAL!

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
if you're looking to have user authentication in your.net Maui app there's a good chance you've looked at Azure active directory b2c now usually when you use b2c you use a client package called msel msel isn't available for net Maui apps just yet but the good news is you don't need it you can actually get your apps authenticating with b2c without using M cell at all I'm going to show you how let's take a look [Music] so I have got here a full stack solution using asp.net core web API I've got a shared project that's got some shared types in it in fact this is just the standard weather forecast that comes out of the box with this with this asp.net core API template and I've got a net Maui beta.net Maui UI you can see that I've got my b2c config set up here in my app settings.json I've actually got the API running here already and I've got engrock running so I can tunnel back to it and show you that in a minute let's take a quick look at b2c okay so this is my Azure ad b2c tenant I've got a couple of in fact I'll show you the user flow I've got the user flow here b2c1 Suzy that's sign up and sign in comes out the box I've tweaked it a little bit but you know this is all pretty vanilla I've got my app registrations here where I've got my an app registration for my API and an app registration for the client this is how you you should set up your your b2c and the API exposes the scope that when you request a token on the client it requests that scope that then sets the audience on the token to be the the ID of the API which you can see that we've got here this client ID which is different from the app client ID and that's going to allow the API to authenticate that token now as I mentioned MCL not quite available yet if we have a look here there's an open issue for it for Maui uh they're nearly there most of this is done but there's some underlying issues not actually with Maui but with the underlying platforms that they're working on they're nearly there but we're not there yet but you don't need it right and the reason you don't need it is because Azure adb2c is an almost oauth to an oidc compliant identity provider I say almost because there's a couple of caveats what I want to show you here is see this endpoints link up here you can see here that we've got some oauth2 endpoints now all you need to do to change these is is put the policy name and so if we look at the metadata document this is the What's called the discovery document so I'm just going to go and pop this in a tab here I'm going to replace this policy name here with b2c one Susie uh and this is going to open up something so now the reason I say that this is almost compliant and not fully is because uh the authority here uh is actually the the policy so in Azure adb2c in all terms The Authority is the policy but the issuer is the tenant now really those two are supposed to match the issue where is supposed to be the authority uh in b2c they don't um that's not really a big deal but the problem with that is that that you can't use a package called a IDC client which is what you would normally use for this kind of stuff um but RDC client will throw an error because those two don't match but again that's fine we can work around that now I'm going to show you how it's actually it's actually not that hard right so it's a bit tricky you have to jump through some hoops but you can make it work so what I've done here in my Maui program uh the first thing that I've done is I've added this auth Handler I'll just show you this what the auth handle does is uh in fact you would need this if you're using M cell as well but what this is going to do is this is going to intercept our HTTP requests and it's going to add an authentication header called Bearer with a value of the token the token that we're gonna we're gonna get in a minute from B to C and that is going to allow our course that API to be authenticated so I've added that that auth Handler you're going to need to do that anyway really really cool feature actually the next thing I've done is I've set up an authenticated HTTP client this can be with a name here called authenticated client this is just a const on my auth service which is here the reason I've done that is just so I can refer to it throughout my app without worrying about typos it's got a base address which at the moment is my ngrok address which is tunneling back to my API and I'm adding that auth Handler as a Handler and so that means that I can inject this named HD HTTP client and anyway we'll actually check the HTTP client Factory and then I generate that name client and that's going to give me a client that's got the token for my my b2c uh token on it and I've also got an unauthenticated client as well which we're going to use in a minute and I'm going to show you why we're going to need that and then setting up some b2c options this is just a type that I've created here um you know it's nothing special it's just got some values in it but we've got the domain of the the tenant the client ID the policy and then some Scopes now this is the scope from the API that I've exposed here now this is specifically the scope that we need to request if we want the audience on that token to match the client ID of the API which is what we need if the API is going to validate that token I'm also requesting offline access the reason I'm requesting offline access is that that's going to give us a refresh token that means once the user has interactively logged in we can then go and request a token on their behalf when when their access token expires without them needing to log in again and open ID is just a standard scope which gives us information about the user so this is going to allow us to get an ID token and then the last thing is the redirect URI now the redirect URI is using a custom URL scheme here um so in a URL scheme you normally uh start with the the protocol so with https for example that tells that tells us that that's the protocol FTP UDP these can be other schemes this is a custom scheme and the reason we're using that is that that is registered with the operating system so that after we've authenticated we're going to be redirected back to our app I'm not going to go through the details of registering this in your Maui app but you need to do it in the platforms folder here there's different ways to do it for each platform so I've got a callback activity and I've added it to my manifest in for iOS and Mac Catalyst you edit your info.plist and for Windows you add it to your package.apex manifest I'm not going to go through how to do those but I will give you a link to this repo you can have a look for yourself and then adding these options uh so that I can inject them where I'm going to need them which is going to be my auth service and then I've got an authenticator which I'm going to show you in a moment and the auth service and then I'm adding my main page so I can inject all this into my main page let's have a look at the auth service so in the auth service let's talk a bit actually quickly about what the M cell does so the MCL basically just wraps everything that we're doing here it gives you a bunch of convenient methods and classes for accessing all this sort of stuff but we're just going to do it ourselves um so as I said here I'm injecting my authenticator which I'll show you in a minute my my options with my b2c informations and the HTTP client Factory and in here I'm using the unauthenticated client because we haven't created the authenticated authenticated client yet well we actually have but we haven't added the the token to it but I don't need it to call b2c because we're going to do it all interactively and we're going to do it with the code the the authorization code and the token that we're going to get at the moment um and uh basically all I'm doing here when I call login async because I'm calling this Authenticator and that is using the built-in uh web authenticator that comes with uh dot net Maui and what that does is that opens a web browser that lets you use an oauth 2 login um and it handles a bunch of stuff which we're going to see in a moment now the one caveat here is that the web authenticator doesn't currently work on uh on Windows but on the plus side uh Morton Nelson here has given us this package called win UI extensions and this includes a custom oauth web authenticator which does work on Windows and it works really nicely so um if you look at my code here you can see that I'm using IF Windows I'm using the win UI extensions package available authenticator for every other platform I'm just using the built-in Maui one so that's kind of a nice workaround for now now what I'm also doing is that the web authenticator result returns a bunch of properties it returns an access token refresh token all that sort of stuff now that's not going to work with b2c in fact the ID token and the access token will but it's not going to give you a refresh token because the interactive login which is the the grant type um that we're using there doesn't actually return a a refresh token so what we're going to do is we're going to use the authorization code and we're going to use the other authorization code to get the tokens that we want so I'm using this helper package here to generate the different URLs that you need to call b2c so the first one is the oauth so this is for the interactive authorization code login we're calling authorize endpoint to get the token we're calling the uh the token endpoint this is going to return one of the properties that we're going to get back from this is an authorization code and we can use that authorization code here to get a token that's going to include the ID token the refresh token and the access token and then of course we can call uh the token endpoint again but using the grant type refresh token rather than authorization code and that's going to give us a refresh token so we're going to use all of these so the the authenticator uh rather than using um you know the the the token directly in the returns we're just going to get the code and we're going to call that token endpoint and that's going to let us get the the refresh token as well then we can return this login result type um and that is going to contain uh all three of those properties and this is just another one that I've defined here as well so it's going to have the ID token the access token and the refresh token back to our auth service so we can see that we're calling uh we're calling the authenticator async option in our in our authenticator type that we've defined here and then back from that we're getting the login result type that we want I'm then calling a method called set refresh token um and that is storing it to Secure Storage one last hump you need to uh hoop sorry you need to jump through for this um you'll see here that there's actually an open issue uh in in the Maui Reaper at the moment about Secure Storage not working on Mac the reason for this is that to use Secure Storage you need to set an entitlements.plished file and which I've actually done here and I've done it for iOS and for Mac OS works for sorry on this Branch it's not here but it doesn't work on Mac o it doesn't work on Mac Catalyst at the moment so what you would need to do here if you want to persist the token is uh just change this and we can use a compiler directive here so I'm going to go if Mac Catalyst um else and then I'm going to go end if after this now what I'm going to do on my Catalyst instead is I'm going to use uh preferences preferences.set and then I can of course use preferences here uh to store the token instead of using Secure Storage I'm just going to get rid of that um now one thing to bear in mind is that obviously that isn't as secure as using uh Secure Storage but it is just as secure if not more so as using a web app which just persists in browser storage anyway so it's up to you to decide whether that's an issue um it's it's probably not it's not an issue for me I am in fact going to put that code in before I I push this back up to my Branch so when you see the repo that will be in there you'll see how you can use this on Mac OS differently um but but with all that done all those Hoops jump through and there's there's really not a lot there and this will work on every platform it'll work on Windows it will work on Mac OS it'll work on iOS and it'll work on Android so in fact let's uh just spin it up and give it a go and we'll see what happens so I'm going to run this now on Windows we'll see that this is going to give us a Windows app um and in fact I should have showed you my main page here but on the main page I've got a a button called login button where you log in and then after you log in it's going to go off and call the API using your token and it's going to go and get all those weather forecasts and then I just display them here and if I go to my main page code behind you can see that I'm injecting the auth service I'm injecting the HTTP client Factory and I'm generating that client using the authenticated client name here and that is the one that injects the tokens with the requests uh injects the token into requests then when I click my login button all I'm doing is displaying an activity indicator calling the login service um and then getting the forecast from the API as I said I've already got the API running here and so I should just now be able to log in and this is going to take me to b2c this part is working nicely I'm just going to log in uh here Matt go for goldman.com using my super secure password pass word one two three now what's going to happen is I'm going to hit enter here and I'm going to be authenticated and it's going to ask me if I want to go back to the app so you can see here that it's trying to open this application the reason it's trying to open this application is because that URL scheme on the redirect URL is associated with our Maui app so I can click click open that should take us back to our app here we can see that now it's just getting the data from the API and I have hit a uh ah so I've hit a slight issue here and this is an end Rock issue let's see if we can fix this so we're getting a 502. let's have a look why so bad gateway uh and that's uh https localhost 7075 that's running that's running ah okay uh it's running on a different port super simple we'll fix this up so I'm just going to change this 5001 and I've now got a new engrock URL so I'm going to have to copy that that's fine um let me just stop this I'll go back to my Maui program update my ngrok URL here [Music] let's just run that again so um yeah slight problem there is that I had an engrock tunnel running to him up to the wrong Port super simple to fix up so this is just going to start up again and a quick reminder we've got a login button here that when I click on this it takes us to b2c which I can log in now and when I log in it asks us to go back to the app which is fine that's what we want to do so back to the app so now we're getting an unauthorized so the first thing that I want to do now in fact let's just run that again and let's go into the auth service what I want to do is I want to have a look at the the information that we're getting back so I'm going to put a break point here I'm just going to run this again log in [Music] back to the app and we should hit our breakpoint so let's have a look at this login result so we've got tokens we've got an access token an ID token and a refresh token um there is our access token let's just spin up posts man [Music] okay so I should be able to go https slash Local Host colon 5001 slash weather forecast now at the moment I'm expecting a 401 because I'm not sending a token authorization I'm going to change this to Bearer token get rid of that paste in the one that we got okay so we're going to 401 now let's have a look and see if we can figure this out let's have a look at the token and let's see if we can figure out what's wrong with it I'm going to use Dev toys here uh devtoys is automatically pasted the token in for us the audience is the Right audience this is the audience of the API and if we go to app settings.json uh so it starts with bc6 ends with 1aa bc618a that's the right token yeah I'm running the Run API that's why so we can see now this is on the original Port that I was expecting so I'm just going to kill that and spin it up again on the right Port grab this URL jump back into here fix that up [Music] run this again now this time I am expecting this to work so we're running the right instance of the API on the right Port we're going to get the right token and it's going to have the Right audience on it and this should work this time so I'm going to click log in back to b2c login again [Music] it's going to ask us if we want to go back to our app which we do and okay we've hit this again this breakpoint and we can see that we've got uh all the tokens there that we're expecting great uh now it's asking me if I want to allow my app to access the internet this is just my firewall I'm going to allow it and it's my own app that's fine and there we go and there are our forecasts that is my.net Maui app running uh Azure active directory b2c in my web API and I have now successfully authenticated got a token used that token to authenticate against the API and got some data back and all of that without using uh the msel at all now I'm going to share the repo below and you're welcome to to use this and and use this approach in your uh in your.net Maui apps as well but bear in mind that this is technical this whole thing is technical debt if you use it super useful if you need to get over the line and you need Azure active directory b2c but bear in mind that this is all technical debt so if you do this keep an eye out for that M cell package and when it becomes available Ripple this out and just use MSL instead thanks [Music]
Info
Channel: Matt Goldman
Views: 3,224
Rating: undefined out of 5
Keywords:
Id: gQoqg4P-uJ0
Channel Id: undefined
Length: 17min 19sec (1039 seconds)
Published: Tue Sep 13 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.