Azure AD | OAuth2.0/OIDC deep dive with MSAL SDKs, Web Apps, and Web APIs - Sept 2020 - Advanced Training Center | Day 3
In this article
- Prerequisites
- Lab 03: MSAL JS Angular Single-Page Application
- Lab 05: Create your own web app
- Lab 06: Create a blazor server web app calling your API
- Lab 07: Create your own API
- Lab 08: ASP.NET (OWIN) sample
Install Node.
Have your favorite text editor open and ready. We'll be using Visual Studio 2019.
Ideally, install Visual Studio 2019, checking ASP.NET and web development, and .NET Core cross-platform development, or otherwise, install ASP.NET Core 3.1 SDK
We'll be walking through the following pre-configured MSAL samples, if you want to git clone
and have them ready:
MSAL JS Single-Page Angular Application
Optional The samples are pre-configured and will work "out of the box", but if you have time and interest, you can configure your own B2C tenant and use that configuration instead: B2C Test Tenant
The lab titles (ex. Lab 03) match the title slides in the PowerPoint given with this workshop.
A Single-Page Application (SPA) calling a Web API. The Web API is the MSAL Node JS Web API. We will run both at the same time, in order to see the middleware library (Passport.js) validating the token. This will show the content learned early in the OAuth2.0 & OIDC sections.
-
git clone https://github.com/Azure-Samples/active-directory-b2c-javascript-nodejs-webapi.git
-
cd active-directory-b2c-javascript-nodejs-webapi
-
Install Node.Js if you haven't already
-
Install and update the Node dependencies
npm install && npm update
-
Run the Web API. By default, it runs on
http:localhost:5000
npm start
-
git clone https://github.com/Azure-Samples/active-directory-b2c-javascript-angular-spa.git
-
cd active-directory-b2c-javascript-angular-spa
-
Install and update the Node dependencies
npm install && npm update
-
Open
src/app/app-config.ts
-
Edit Line 49:
replace:
webApi: "https://fabrikamb2chello.azurewebsites.net/hello"
with:
webApi: "http://localhost:5000/hello"
-
Hit Save
-
Run the Web app.
npm start
Listening on port 6420...
Visit http://localhost:6420
and perform the following actions:
- Click the Login button to start the Azure AD B2C sign in or sign up workflow.
- Once signed in, you can click the Call Web API button to have your display name returned from the Web API call as a JSON object.
- Click "Logout" to logout from the application.
In this Lab and the following, we'll need to use the Microsoft.Identity.Web project templates (which are also available in .NET 5.0 from Preview 7). To install them in your system:
- Download the Microsoft.Identity.Web.ProjectTemplates-0.4.0-preview NuGet package from NuGet.org, and save it locally
- In a developer command prompt, type
dotnet new -i Microsoft.Identity.Web.ProjectTemplates.0.4.0-preview.nupkg
This installs the templates, and displays which project templates are available. (You can also type dotnet new --help
to see the list)
In a developer command prompt:
-
Create a folder, and cd into it.
mkdir webapp cd webapp
-
Create the B2C web app
dotnet new webapp2 --auth IndividualB2C ^ --aad-b2c-instance "https://fabrikamb2c.b2clogin.com" ^ --domain "fabrikamb2c.onmicrosoft.com" ^ --client-id "fdb91ff5-5ce6-41f3-bdbd-8267c817015d"
-
Edit the
webapp.csproj
file to replace<TargetFrameworks>netcoreapp3.1; net5.0</TargetFrameworks>
by<TargetFramework>netcoreapp3.1</TargetFramework>
(unless you have installed the .NET 5.0 preview framework) -
Edit the
Properties\launchsettings.json
file so that in the IISExpress configuration, you use "sslPort": 44365, as this is one of the ports for which the redirect URIs are registered in the B2C application (5001 one is another one, and it's used by the other ASP.NET Core profile described in launchsettings.json file){ "iisSettings": { "windowsAuthentication": false, "anonymousAuthentication": true, "iisExpress": { "applicationUrl": "http://localhost:48464", "sslPort": 44365 } }, // More here
-
Run your application (either from Visual Studio or from the command line with
dotnet run
) -
Sign-in with one of your social identities or sign-up for a new local account.
That's what it took to create a B2C application that signs-in users. Note that you don't need any client secret until your web app calls a web API
-
In ASP.NET Core, Web apps have several flavors, MVC, Razor, and Blazor Web server. You have created above a Razor assembly by using the webapp2 template. You can also try the mvc2 one. We'll use the Blazor web server one later in Lab 06: Create a blazor server web app calling your API
-
You can also create a web app with the coordinates you have registered during Day 1. In that case use
--auth SingleOrg
Create a .NET Core 3.1 (or 5.0) Blazor server (Web app) that will exercise the web API that you'll create later. For the moment, to make it easier, it will call the Web API you used in Day 1 and which is deployed in Azure
-
Pre-requisite: you'll have installed the Microsoft.Identity.Web dotnet core templates
-
In a developer command prompt, generate a Blazor Web app calling Microsoft Graph:
mkdir YourAliasCarpoolBlazorWebApp cd YourAliasCarpoolBlazorWebApp dotnet new blazorserver2 --auth SingleOrg ^ --client-id "508ea87c-0ded-4259-ab7c-3ead66006f7b" ^ --tenant-id "fb76fa85-e896-4a3b-b915-99764ea778ed" ^ --domain "M365x670600.OnMicrosoft.com" ^ --called-api-url "https://carpoolapiforatc.azurewebsites.net/" ^ --called-api-scopes: "api://b6128bb8-a1e3-4c69-984c-30da32c3ff0d/Rides.Read api://b6128bb8-a1e3-4c69-984c-30da32c3ff0d/Drivers.Read api://b6128bb8-a1e3-4c69-984c-30da32c3ff0d/Riders.Read"
-
Open the project in your favorite editor or Visual Studio
-
Add the client secret (ask for it) in
appsettings.json
-
Rename
CallApi.razor
intoRiders.Razor
-
In
Riders.Razor
-
Change the first line to be
@page "/drivers"
-
Change the call to CallWebApiForUserAsync() to the following:
response = await downstreamAPI.CallWebApiForUserAsync( "DownstreamApi", options => { options.RelativePath = "api/riders"; options.Scopes = "api://b6128bb8-a1e3-4c69-984c-30da32c3ff0d/Riders.Read"; });
-
-
In Shared\NavMenu.Razor, changed the CalledApi entry to be Riders:
<li class="nav-item px-3"> <NavLink class="nav-link" href="riders"> <span class="oi oi-list-rich" aria-hidden="true"></span>Riders </NavLink> </li>
Just run the project, and when navigating to the "Riders", the app will sign you in, and you'll see the JSon generated by the API.
-
You can add more pages for Drivers and Rides which will call the corresponding web API endpoints.
-
You can change the BaseUrl to point to a deployed Web API. For this you'll need to change the
"BaseUrl"
in theappsettings.json
to have:"BaseUrl": "https://localhost:44383" // or "https://localhost:5001"
- Create the .NET Core 3.1 (or 5.0) web API that you used in Day1 (and which is also deployed at: https://carpoolapiforatc.azurewebsites.net)
- You can see the specs for the API at: https://carpoolapiforatc.azurewebsites.net/swagger
/api/drivers
(Scope"Drivers.Read"
), which really gets the graphs in the tenant from users, and exposes their display name and phone number (displayName, phoneNumber)/api/rides
, (Scope"Rides.Read"
), which returns a collection of strings ["Seattle-Redmond" ]
ClientIdOfTheWebApiYouCreatedInDay1
: the client ID (application ID) of the web api that you registered in Day 1 of the training.- the client secret that you registered for this web API.
-
In a developer command prompt:
dotnet new webapi2 --auth SingleOrg --calls—graph ^ --client-id ClientIdOfTheWebApiYouCreatedInDay1 ^ --tenant-id "fb76fa85-e896-4a3b-b915-99764ea778ed" ^ --domain "M365x670600.OnMicrosoft.com" ^ --default-scope "Riders.Read"
-
Open the generated project with your preferred editor (we use Visual Studio)
-
In the
appsettings.json
file- Add the client secret
- Change the
Scopes
to be"User.ReadBasic.All"
-
In the
.csproj
Replace<TargetFrameworks>netcoreapp3.1; net5.0</TargetFrameworks>
by<TargetFramework>netcoreapp3.1</TargetFramework>
-
Rename
WeatherForecast.cs
toStakeholder.cs
and let Visual Studio rename theWeatherForecast
class toStakeholder
.- Replace the properties in the
WeatherForecast
class by two strings (DisplayName
andPhoneNumber
)
- Replace the properties in the
-
Rename
Controllers\WeatherForecastController.cs
toRidersController.cs
(and let Visual Studio rename the class) -
In
Controllers\RidersController.cs
:-
delete
Summaries
-
Change the signature of the
Get
method to returnIEnumerable<Stakeholder>
and delete the lines that were about the Weather forecast. -
Return stakeholders from the users (select the
DisplayName
andMobilePhone
properties):var users = await _graphServiceClient.Users.Request().GetAsync(); return users.Select(u => new Stakeholder { DisplayName = u.DisplayName, PhoneNumber = u.MobilePhone });
-
Either from Visual Studio, or from the command line (dotnet run, and open a browser at https://localhost:5001
)
- See the swagger for your web API
- To exercise your API, you'll need an access token. You learned in Day 1 how to get one. You can also exercise it with your Blazor app
You can add more controllers for Drivers and Rides, based on the specification in the swagger
To exercise your Web API from your Blazor web server application, you will need to:
- Update the appsetting.json for your Blazor web server application, to use:
- the client ID of the web app you created in Day 1
- the scopes and client ID of your Web API created in Day 1
- the endpoint of your web API created in the previous lab.
- Update the Razor pages to use the right scopes (api://clientIdYourWebApi/XXX)
The equivalent command to create the blazor web server app with your app coordinates is:
dotnet new blazorserver2 --auth SingleOrg ^
--client-id ClientIdOfTheWebAppYouCreatedInDay1 ^
--tenant-id "fb76fa85-e896-4a3b-b915-99764ea778ed" ^
--domain "M365x670600.OnMicrosoft.com" ^
--called-api-url "https://localhost:44383" ^
--called-api-scopes: "api://clientIdYourWebApi/Riders.Read api://api://clientIdYourWebApi/Drivers.Read api://clientIdYourWebApi/Rides.Read"
Go to https://aka.ms/aaddevsamplesv2 (all the samples)
Search for the ASP.NET web app and go to the sample repo (dotnet-webapp-openidconnect-v2)
Follow the Readme.md, try out the sample.