page_type | languages | products | description | ||||
---|---|---|---|---|---|---|---|
sample |
|
|
How to secure a Web API built with ASP.NET Core using the Azure AD B2C |
The sample in this folder is part of a multi-chapter tutorial. The first phase is available at An ASP.NET Core Web app signing-in users with the Microsoft identity platform in your organization.
This sample demonstrates an ASP.NET Core web app calling an ASP.NET Core web API that is secured using Azure AD B2C.
- The client ASP.NET Core web app application uses the Microsoft Authentication Library Microsoft Authentication Library (MSAL) for .NET to sign-in a user and obtain a JWT access token from Azure AD B2C:
- The Access Token is used as a bearer token to authenticate the user when calling the ASP.NET Core Web API.
The client web application essentially takes the following steps to sign-in the user and obtain a bearer token for the Web API:
- Signs-in the user with local or social identities.
- Acquires an access token for the Web API.
- Calls the Web API using the access token as a bearer token in the authentication header of the Http request. The Web API authorizes the caller (user) using the ASP.NET JWT Bearer Authorization middleware.
This sample has a web API and a client web app, both built using the asp.net core platform. The client app signs in users using the OpenID Connect protocol flow and in this process obtains (and caches) an access token for the web API. The client app has a ToDo list that the web app users can work with. This ToDo list is maintained in an in-memory list on the Web API. The client app calls the web API for all operations on the ToDo list.
- Either Visual Studio or Visual Studio Code and .NET Core SDK
- An Azure AD B2C tenant. For more information see: How to get an Azure AD B2C tenant
- A user account in your Azure AD B2C tenant.
From your shell or command line:
git clone https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2.git
cd "4-WebApp-your-API\4-2-B2C"
or download and extract the repository .zip file.
⚠️ To avoid path length limitations on Windows, we recommend cloning into a directory near the root of your drive.
As a first step you'll need to:
- Sign in to the Azure portal.
- If your account is present in more than one Azure AD B2C tenant, select your profile at the top right corner in the menu on top of the page, and then switch directory to change your portal session to the desired Azure AD B2C tenant.
Please refer to: Tutorial: Create user flows in Azure Active Directory B2C
Current sample uses the self-service password reset experience that is configured for Sign up and sign in (Recommended) user flow.
Please refer to: Tutorial: Add identity providers to your applications in Azure Active Directory B2C
- Navigate to the Azure portal and select the Azure AD B2C service.
- Select the App Registrations blade on the left, then select New registration.
- In the Register an application page that appears, enter your application's registration information:
- In the Name section, enter a meaningful application name that will be displayed to users of the app, for example
TodoListService-aspnetcore-webapi
. - Under Supported account types, select Accounts in any identity provider or organizational directory (for authenticating users with user flows).
- In the Name section, enter a meaningful application name that will be displayed to users of the app, for example
- Select Register to create the application.
- In the app's registration screen, find and note the Application (client) ID. You use this value in your app's configuration file(s) later in your code.
- Select Save to save your changes.
- In the app's registration screen, select the Expose an API blade to the left to open the page where you can declare the parameters to expose this app as an API for which client applications can obtain access tokens for.
The first thing that we need to do is to declare the unique resource URI that the clients will be using to obtain access tokens for this Api. To declare an resource URI, follow the following steps:
- Select
Set
next to the Application ID URI to generate a URI that is unique for this app. - For this sample, accept the proposed Application ID URI (
https://{tenantName}.onmicrosoft.com/{clientId}
) by selecting Save.
- Select
- All APIs have to publish a minimum of one scope for the client's to obtain an access token successfully. To publish a scope, follow the following steps:
- Select Add a scope button open the Add a scope screen and Enter the values as indicated below:
- For Scope name, use
access_as_user
. - For Admin consent display name type
Access TodoListService-aspnetcore-webapi
. - For Admin consent description type
Allows the app to access TodoListService-aspnetcore-webapi as the signed-in user.
- Keep State as Enabled.
- Select the Add scope button on the bottom to save this scope.
- For Scope name, use
- Select Add a scope button open the Add a scope screen and Enter the values as indicated below:
Open the project in your IDE (like Visual Studio or Visual Studio Code) to configure the code.
In the steps below, "ClientID" is the same as "Application ID" or "AppId".
- Open the
TodoListService\appsettings.json
file. - Find the key
Instance
and replace the value with your tenant name. For example,https://fabrikam.b2clogin.com
- Find the key
Domain
and replace the existing value with your Azure AD tenant name. - Find the key
ClientId
and replace the existing value with the application ID (clientId) of the application copied from the Azure portal. - Find the key
SignUpSignInPolicyId
and replace with the name of theSign up and sign in
policy you created.
- Navigate to the Azure portal and select the Azure AD B2C service.
- Select the App Registrations blade on the left, then select New registration.
- In the Register an application page that appears, enter your application's registration information:
- In the Name section, enter a meaningful application name that will be displayed to users of the app, for example
TodoListClient-aspnetcore-webapi
. - Under Supported account types, select Accounts in any identity provider or organizational directory (for authenticating users with user flows).
- In the Redirect URI (optional) section, select Web in the combo-box and enter the following redirect URI:
https://localhost:5000/
.Note that there are more than one redirect URIs used in this sample. You'll need to add them from the Authentication tab later after the app has been created successfully.
- In the Name section, enter a meaningful application name that will be displayed to users of the app, for example
- Select Register to create the application.
- In the app's registration screen, find and note the Application (client) ID. You use this value in your app's configuration file(s) later in your code.
- In the app's registration screen, select Authentication in the menu.
- If you don't have a platform added, select Add a platform and select the Web option.
- In the Redirect URIs section, enter the following redirect URIs.
https://localhost:5000/signin-oidc
- In the Front-channel logout URL section, set it to
https://localhost:5000/signout-oidc
. - In Implicit grant section, select the check boxes for Access tokens and ID tokens.
- Select Save to save your changes.
- In the app's registration screen, select the Certificates & secrets blade in the left to open the page where we can generate secrets and upload certificates.
- In the Client secrets section, select New client secret:
- Type a key description (for instance
app secret
), - Select one of the available key durations (In 1 year, In 2 years, or Never Expires) as per your security posture.
- The generated key value will be displayed when you select the Add button. Copy the generated value for use in the steps later.
- You'll need this key later in your code's configuration files. This key value will not be displayed again, and is not retrievable by any other means, so make sure to note it from the Azure portal before navigating to any other screen or blade.
- Type a key description (for instance
- In the app's registration screen, select the API permissions blade in the left to open the page where we add access to the APIs that your application needs.
- Select the Add a permission button and then,
- Ensure that the My APIs tab is selected.
- In the list of APIs, select the API
TodoListService-aspnetcore-webapi
. - In the Delegated permissions section, select the Access 'TodoListService-aspnetcore-webapi' in the list. Use the search box if necessary.
- Select the Add permissions button at the bottom.
- Select Grant admin consent for (your tenant name).
Open the project in your IDE (like Visual Studio or Visual Studio Code) to configure the code.
In the steps below, "ClientID" is the same as "Application ID" or "AppId".
- Open the
Client\appsettings.json
file. - Find the key
Instance
and replace the value with your tenant name. For example,https://fabrikam.b2clogin.com
- Find the key
Domain
and replace the existing value with your Azure AD tenant name. - Find the key
ClientId
and replace the existing value with the application ID (clientId) of the application copied from the Azure portal. - Find the key
SignUpSignInPolicyId
and replace with the name of theSign up and sign in
policy you created. - Find the key
EditProfilePolicyId
and replace with the name of theProfile editing
policy you created. - Find the key
ClientSecret
and replace the existing value with the key you saved during the creation of the app, in the Azure portal. - Find the key
TodoListScope
and replace the existing value with the service Scope. For example,https://{tenantName}.onmicrosoft.com/{service_clientId}/access_as_user
.
This sample is configured with the password reset experience that is a part of the sign-up or sign-in policy. If separate password reset flow is required then add the key ResetPasswordPolicyId
under AzureAdB2C section, and value of the key as the name of the Password reset
policy you created.
You can run the sample by using either Visual Studio or command line interface as shown below:
Clean the solution, rebuild the solution, and run it. You might want to go into the solution properties and set both projects as startup projects, with the service project starting first.
cd TodoListService
dotnet restore
Then:
In a separate console window, execute the following commands
cd ../
cd Client
dotnet restore
dotnet dev-certs https --clean
dotnet dev-certs https --trust
Learn more about HTTPS in .NET Core.
In both the console windows execute the below command:
dotnet run
- Open your web browser and navigate to https://localhost:5000. Accept the IIS Express SSL certificate if needed. Click on Sign In button.
- If you don't have an account registered on the Azure AD B2C used in this sample, follow the sign up process. Otherwise, input the email and password for your account and click on Sign in.
When you start the Web API from Visual Studio, depending on the browser you use, you'll get:
- an empty web page (case with Microsoft Edge)
- or an error HTTP 401 (case with Chrome)
This behavior is expected as the browser is not authenticated. The client application will be authenticated, so it will be authorized to access the Web API.
Explore the sample by signing in into the TodoList client, adding items to the To-Do list. If you stop the application without signing out, the next time you run the application, you won't be prompted to sign in again.
NOTE: Remember, the To-Do list is stored in memory in this TodoListService
app. Each time you run the projects, your To-Do list will get emptied.
Did the sample not work for you as expected? Did you encounter issues trying this sample? Then please reach out to us using the GitHub Issues page.
-
Run the following command to create a sample from the command line using the
SingleOrg
template:md TodoListClient cd TodoListClient dotnet new mvc --auth SingleOrg --client-id <Enter_the_Application_Id_here> --tenant-id <yourTenantId>
Note: Replace
Enter_the_Application_Id_here
with the Application Id from the application Id you just registered in the Application Registration Portal and<yourTenantId>
with the Directory (tenant) ID where you created your application.
-
Open the generated project (.csproj) in Visual Studio, and save the solution.
-
Add the
Microsoft.Identity.Web.csproj
project which is located at the root of this sample repo, to your solution (Add Existing Project ...). It's used to simplify signing-in and, in the next tutorial phases, to get a token. -
Add a reference from your newly generated project to
Microsoft.Identity.Web
(right click on the Dependencies node under your new project, and choose Add Reference ..., and then in the projects tab find theMicrosoft.Identity.Web
project) -
Open the Startup.cs file and:
-
at the top of the file, add the following using directive:
using Microsoft.Identity.Web;
-
in the
ConfigureServices
method, replace the two following lines:services.AddAuthentication(AzureADDefaults.AuthenticationScheme) .AddAzureAD(options => Configuration.Bind("AzureAd", options));
by this line:
services.AddMicrosoftIdentityWebAppAuthentication(Configuration, "AzureAdB2C") .EnableTokenAcquisitionToCallDownstreamApi(new string[] { Configuration["TodoList:TodoListScope"] }) .AddInMemoryTokenCaches(); services.AddInMemoryTokenCaches();
-
-
Update the
Configure
method to include app.UseAuthentication(); before app.UseMvc();app.UseAuthentication(); app.UseMvc();
-
Change the
Properties\launchSettings.json
file to ensure that you start your web app from https://localhost:44321 as registered. For this:- update the
sslPort
of theiisSettings
section to be44321
- in the
applicationUrl
property of usehttps://localhost:44321
- Then add the following code to inject the ToDoList service implementation in the client
services.AddTodoListService(Configuration);
- update the
-
Open the
appsettings.json
file and copy the keys from the sample's corresponding file under theAzureAd
andTodoList
sections.
- In the TodoListClient project, add a folder named
Models
and then create a new file namedTodoItem.cs
. Copy the contents of the TodoListClient\Models\TodoItem.cs in this file. - Create a new Controller named
TodoListController
and copy and paste the code from the sample (TodoListService\Controllers\TodoListController.cs) to this controller. - Copy the files
TodoListService
andTodoListService.cs
in the TodoListClient\Services folder provided in this sample to your project . - Copy the contents of TodoListClient\views\ToDo folder to the views folder of your project.
- Modify the
Views\Shared\_Layout.cshtml
to add a link to the **ToDolist controller. Check theViews\Shared\_Layout.cshtml
in the sample for reference. - Add a section name TodoList in the appsettings.json file and add the keys
TodoListScope
,TodoListBaseAddress
.
The code for the TodoListService was created in the following way:
-
Run the following command to create a sample from the command line using the
SingleOrg
template:md TodoListService cd TodoListService dotnet new webapi -au=SingleOrg
-
Open the generated project (.csproj) in Visual Studio, and save the solution.
In the TodoListService project, add a folder named Models
and then create a new file named TodoItem.cs
. Copy the contents of the TodoListService\Models\TodoItem.cs in this file.
- Add the
Microsoft.Identity.Web.csproj
project which is located at the root of this sample repo, to your solution (Add Existing Project ...). - Add a reference from your newly generated project to
Microsoft.Identity.Web
(right click on the Dependencies node under your new project, and choose Add Reference ..., and then in the projects tab find theMicrosoft.Identity.Web
project) UpdateStartup.cs
file :
- Add the following two using statements
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.Client.TokenCacheProviders;
-
In the
ConfigureServices
method, replace the following code:services.AddAuthentication(AzureADDefaults.BearerAuthenticationScheme) .AddAzureADBearer(options => Configuration.Bind("AzureAd", options));
with
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddMicrosoftIdentityWebApi(options => { Configuration.Bind("AzureAdB2C", options); options.TokenValidationParameters.NameClaimType = "name"; }, options => { Configuration.Bind("AzureAdB2C", options); });
-
Add the method app.UseAuthentication() before app.UseMvc() in the
Configure
methodapp.UseAuthentication(); app.UseMvc();
- Add a folder named
Models
and then create a new file namedTodoItem.cs
. Copy the contents of the TodoListClient\Models\TodoItem.cs in this file. - Create a new Controller named
TodoListController
and copy and paste the code from the sample (\TodoListService\Controllers\TodoListController.cs) to this controller. TodoListController requires below code:
[Authorize]
[RequiredScope(scopeRequiredByAPI)]
public class TodoListController : Controller
{
const string scopeRequiredByAPI = "access_as_user" ;
...
}
The RequiredScopes attribute validates if token contains the scopes required by a web API. Value for scopeRequiredByAPI is the required scope.
In Startup.cs
, below lines of code enables Microsoft identity platform endpoint. This endpoint is capable of signing-in users both with their Work and School Accounts.
services.AddMicrosoftIdentityWebAppAuthentication(Configuration, "AzureAdB2C")
.EnableTokenAcquisitionToCallDownstreamApi(new string[] { Configuration["TodoList:TodoListScope"] })
.AddInMemoryTokenCaches();
- AddMicrosoftIdentityWebAppAuthentication : This enables your application to use the Microsoft identity platform endpoint. This endpoint is capable of signing-in users both with their Work and School and Microsoft Personal accounts.
- EnableTokenAcquisitionToCallDownstreamApi : Enables the web app to call the protected API ToDoList Api.
- AddInMemoryTokenCaches: Adds an in memory token cache provider, which will cache the Access Tokens acquired for the Web API.
In Startup.cs
, below lines of code protects the web API with Microsoft identity platform.
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(options =>
{
Configuration.Bind("AzureAdB2C", options);
options.TokenValidationParameters.NameClaimType = "name";
},
options => { Configuration.Bind("AzureAdB2C", options); });
There are two web projects in this sample. To deploy them to Azure App Services, you'll need, for each one, to:
- create an Azure App Service
- publish the projects to the App Services, and
- update its client(s) to call the web site instead of the local environment.
- Sign in to the Azure portal.
- Click
Create a resource
in the top left-hand corner, select Web --> Web App, and give your web site a name, for example,TodoListService-aspnetcore-webapi-contoso.azurewebsites.net
. - Next, select the
Subscription
,Resource Group
,App service plan and Location
.OS
will be Windows andPublish
will be Code. - Click
Create
and wait for the App Service to be created. - Once you get the
Deployment succeeded
notification, then click onGo to resource
to navigate to the newly created App service. - Once the web site is created, locate it in the Dashboard and click it to open App Services Overview screen.
- From the Overview tab of the App Service, download the publish profile by clicking the Get publish profile link and save it. Other deployment mechanisms, such as from source control, can also be used.
- Switch to Visual Studio and go to the TodoListService-aspnetcore-webapi project. Right click on the project in the Solution Explorer and select Publish. Click Import Profile on the bottom bar, and import the publish profile that you downloaded earlier.
- Click on Configure and in the
Connection tab
, update the Destination URL so that it is ahttps
in the home page URL, for example https://TodoListService-aspnetcore-webapi-contoso.azurewebsites.net. Click Next. - On the Settings tab, make sure
Enable Organizational Authentication
is NOT selected. Click Save. Click on Publish on the main screen. - Visual Studio will publish the project and automatically open a browser to the URL of the project. If you see the default web page of the project, the publication was successful.
- Navigate back to the Azure portal. In the left-hand navigation pane, select the Azure Active Directory service, and then select App registrations (Preview).
- In the resulting screen, select the
TodoListService-aspnetcore-webapi
application. - From the Branding menu, update the Home page URL, to the address of your service, for example https://TodoListService-aspnetcore-webapi-contoso.azurewebsites.net. Save the configuration.
- Add the same URL in the list of values of the Authentication -> Redirect URIs menu. If you have multiple redirect URIs, make sure that there a new entry using the App service's Uri for each redirect Uri.
Update the TodoListClient-aspnetcore-webapi
to call the TodoListService-aspnetcore-webapi
Running in Azure App Services
- In your IDE, go to the
TodoListClient-aspnetcore-webapi
project. - Open
TodoListClient\appsettings.json
. Only one change is needed - update thetodo:TodoListBaseAddress
key value to be the address of the website you published, for example, https://TodoListService-aspnetcore-webapi-contoso.azurewebsites.net. - Run the client! If you are trying multiple different client types (for example, .Net, Windows Store, Android, iOS) you can have them all call this one published web API.
- Sign in to the Azure portal.
- Click
Create a resource
in the top left-hand corner, select Web --> Web App, and give your web site a name, for example,TodoListClient-aspnetcore-webapi-contoso.azurewebsites.net
. - Next, select the
Subscription
,Resource Group
,App service plan and Location
.OS
will be Windows andPublish
will be Code. - Click
Create
and wait for the App Service to be created. - Once you get the
Deployment succeeded
notification, then click onGo to resource
to navigate to the newly created App service. - Once the web site is created, locate it it in the Dashboard and click it to open App Services Overview screen.
- From the Overview tab of the App Service, download the publish profile by clicking the Get publish profile link and save it. Other deployment mechanisms, such as from source control, can also be used.
- Switch to Visual Studio and go to the TodoListClient-aspnetcore-webapi project. Right click on the project in the Solution Explorer and select Publish. Click Import Profile on the bottom bar, and import the publish profile that you downloaded earlier.
- Click on Configure and in the
Connection tab
, update the Destination URL so that it is ahttps
in the home page URL, for example https://TodoListClient-aspnetcore-webapi-contoso.azurewebsites.net. Click Next. - On the Settings tab, make sure
Enable Organizational Authentication
is NOT selected. Click Save. Click on Publish on the main screen. - Visual Studio will publish the project and automatically open a browser to the URL of the project. If you see the default web page of the project, the publication was successful.
- Navigate back to the Azure portal. In the left-hand navigation pane, select the Azure Active Directory service, and then select App registrations (Preview).
- In the resulting screen, select the
TodoListClient-aspnetcore-webapi
application. - In the Authentication page for your application, update the Logout URL fields with the address of your service, for example https://TodoListClient-aspnetcore-webapi-contoso.azurewebsites.net
- From the Branding menu, update the Home page URL, to the address of your service, for example https://TodoListClient-aspnetcore-webapi-contoso.azurewebsites.net. Save the configuration.
- Add the same URL in the list of values of the Authentication -> Redirect URIs menu. If you have multiple redirect URLs, make sure that there a new entry using the App service's Uri for each redirect URL.
⚠️ If your app is using an in-memory storage, Azure App Services will spin down your web site if it is inactive, and any records that your app was keeping will emptied. In addition, if you increase the instance count of your web site, requests will be distributed among the instances. Your app's records, therefore, will not be the same on each instance.
Learn more about Microsoft Identity Platform and Azure AD B2C:
- Microsoft identity platform (Azure Active Directory for developers)
- Overview of Microsoft Authentication Library (MSAL)
- What is Azure Active Directory B2C?
- Azure AD B2C User Flows
- Azure AD B2C Custom Policies
- Tutorial: Grant access to an ASP.NET web API using Azure Active Directory B2C
To learn more about the code, visit:
- Conceptual documentation for MSAL.NET and in particular:
- Acquiring tokens with authorization codes on web apps
- Customizing Token cache serialization
Use Stack Overflow to get support from the community.
Ask your questions on Stack Overflow first and browse existing issues to see if someone has asked your question before.
Make sure that your questions or comments are tagged with [msal
ms-identity
azure-active-directory
azure-ad-b2c
].
If you find a bug in the sample, raise the issue on GitHub Issues.
To provide feedback on or suggest features for Azure Active Directory, visit User Voice page.
If you'd like to contribute to this sample, see CONTRIBUTING.MD.
This project has adopted the Microsoft Open Source Code of Conduct. For more information, see the Code of Conduct FAQ or contact [email protected] with any additional questions or comments.