Enable authentication in your own web API by using Azure AD B2C

Important

Effective May 1, 2025, Azure AD B2C will no longer be available to purchase for new customers. Learn more in our FAQ.

To authorize access to a web API, you can serve only requests that include a valid access token that Azure Active Directory B2C (Azure AD B2C) issues. This article shows you how to enable Azure AD B2C authorization to your web API. After you complete the steps in this article, only users who obtain a valid access token will be authorized to call your web API endpoints.

Prerequisites

Before you begin, read one of the following articles, which discuss how to configure authentication for apps that call web APIs. Then, follow the steps in this article to replace the sample web API with your own web API.

Overview

Token-based authentication ensures that requests to a web API include a valid access token.

The app completes the following steps:

  1. It authenticates users with Azure AD B2C.

  2. It acquires an access token with the required permissions (scopes) for the web API endpoint.

  3. It passes the access token as a bearer token in the authentication header of the HTTP request by using this format:

    Authorization: Bearer <access token>
    

The web API completes the following steps:

  1. It reads the bearer token from the authorization header in the HTTP request.

  2. It validates the token.

  3. It validates the permissions (scopes) in the token.

  4. It reads the claims that are encoded in the token (optional).

  5. It responds to the HTTP request.

App registration overview

To enable your app to sign in with Azure AD B2C and call a web API, you need to register two applications in the Azure AD B2C directory.

  • The web, mobile, or SPA application registration enables your app to sign in with Azure AD B2C. The app registration process generates an Application ID, also known as the client ID, which uniquely identifies your application (for example, App ID: 1).

  • The web API registration enables your app to call a protected web API. The registration exposes the web API permissions (scopes). The app registration process generates an Application ID, which uniquely identifies your web API (for example, App ID: 2). Grant your app (App ID: 1) permissions to the web API scopes (App ID: 2).

The application registrations and the application architecture are described in the following diagram:

Diagram of the application registrations and the application architecture for an app with web API.

Prepare your development environment

In the next sections, you create a new web API project. Select your programming language, ASP.NET Core, or Node.js. Make sure you have a computer that's running either of the following software:

Step 1: Create a protected web API

Create a new web API project. First, select the programming language you want to use, ASP.NET Core or Node.js.

Use Express for Node.js to build a web API. To create a web API, do the following:

  1. Create a new folder named TodoList.
  2. Under the TodoList folder, create a file named app.js.
  3. In a command shell, run npm init -y. This command creates a default package.json file for your Node.js project.
  4. In the command shell, run npm install express. This command installs the Express framework.

Step 2: Install the dependencies

Add the authentication library to your web API project. The authentication library parses the HTTP authentication header, validates the token, and extracts claims. For more information, review the documentation for the library.

To add the authentication library, install the packages by running the following command:

npm install passport
npm install passport-azure-ad
npm install morgan

The Morgan package is an HTTP request logger middleware for Node.js.

Step 3: Initiate the authentication library

Add the necessary code to initiate the authentication library.

Add the following JavaScript code to your app.js file.

// Import the required libraries
const express = require('express');
const morgan = require('morgan');
const passport = require('passport');
const config = require('./config.json');

// Import the passport Azure AD library
const BearerStrategy = require('passport-azure-ad').BearerStrategy;

// Set the Azure AD B2C options
const options = {
    identityMetadata: `https://${config.credentials.tenantName}.b2clogin.cn/${config.credentials.tenantName}.partner.onmschina.cn/${config.policies.policyName}/${config.metadata.version}/${config.metadata.discovery}`,
    clientID: config.credentials.clientID,
    audience: config.credentials.clientID,
    issuer: config.credentials.issuer,
    policyName: config.policies.policyName,
    isB2C: config.settings.isB2C,
    scope: config.resource.scope,
    validateIssuer: config.settings.validateIssuer,
    loggingLevel: config.settings.loggingLevel,
    passReqToCallback: config.settings.passReqToCallback
}

// Instantiate the passport Azure AD library with the Azure AD B2C options
const bearerStrategy = new BearerStrategy(options, (token, done) => {
        // Send user info using the second argument
        done(null, { }, token);
    }
);

// Use the required libraries
const app = express();

app.use(morgan('dev'));

app.use(passport.initialize());

passport.use(bearerStrategy);

//enable CORS (for testing only -remove in production/deployment)
app.use((req, res, next) => {
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Headers', 'Authorization, Origin, X-Requested-With, Content-Type, Accept');
    next();
});

Step 4: Add the endpoints

Add two endpoints to your web API:

  • Anonymous /public endpoint. This endpoint returns the current date and time. Use it to debug your web API with anonymous calls.
  • Protected /hello endpoint. This endpoint returns the value of the name claim within the access token.

To add the anonymous endpoint:

In the app.js file, add the following JavaScript code:

// API anonymous endpoint
app.get('/public', (req, res) => res.send( {'date': new Date() } ));

To add the protected endpoint:

In the app.js file, add the following JavaScript code:

// API protected endpoint
app.get('/hello',
    passport.authenticate('oauth-bearer', {session: false}),
    (req, res) => {
        console.log('Validated claims: ', req.authInfo);
        
        // Service relies on the name claim.  
        res.status(200).json({'name': req.authInfo['name']});
    }
);

The /hello endpoint first calls the passport.authenticate() function. The authentication function limits access to authenticated users only.

The authentication function also verifies that the web API is called with the right scopes. The allowed scopes are located in the configuration file.

Step 5: Configure the web server

In a development environment, set the web API to listen on incoming HTTP or HTTPS requests port number. In this example, use HTTP port 6000 and HTTPS port 6001. The base URI of the web API will be http://localhost:6000 for HTTP and https://localhost:6001 for HTTPS.

Add the following JavaScript code to the app.js file. It's possible to setup HTTP and HTTPS endpoints for the Node application.

// Starts listening on port 6000
const port = process.env.PORT || 6000;

app.listen(port, () => {
    console.log('Listening on port ' + port);
});

Step 6: Configure the web API

Add configurations to a configuration file. The file contains information about your Azure AD B2C identity provider. The web API app uses this information to validate the access token that the web app passes as a bearer token.

Under the project root folder, create a config.json file, and then add it to the following JSON snippet:

{
    "credentials": {
        "tenantName": "<your-tenant-name>.partner.onmschina.cn",
        "clientID": "<your-webapi-application-ID>",
        "issuer": "https://<your-tenant-name>.b2clogin.cn/<your-tenant-ID>/v2.0/"
    },
    "policies": {
        "policyName": "b2c_1_susi"
    },
    "resource": {
        "scope": ["tasks.read"]
    },
    "metadata": {
        "discovery": ".well-known/openid-configuration",
        "version": "v2.0"
    },
    "settings": {
        "isB2C": true,
        "validateIssuer": true,
        "passReqToCallback": false,
        "loggingLevel": "info"
    }
}

In the config.json file, update the following properties:

Section Key Value
credentials tenantName Your Azure AD B2C tenant name/domain name (for example, contoso.partner.onmschina.cn).
credentials clientID The web API application ID. In the preceding diagram, it's the application with App ID: 2. To learn how to get your web API application registration ID, see Prerequisites.
credentials issuer The token issuer iss claim value. By default, Azure AD B2C returns the token in the following format: https://<your-tenant-name>.b2clogin.cn/<your-tenant-ID>/v2.0/. Replace <your-tenant-name> with the first part of your Azure AD B2C tenant name. Replace <your-tenant-ID> with your Azure AD B2C tenant ID.
policies policyName The user flows, or custom policy. To learn how to get your user flow or policy, see Prerequisites.
resource scope The scopes of your web API application registration. To learn how to get your web API scope, see Prerequisites.

Step 7: Run and test the web API

Finally, run the web API with your Azure AD B2C environment settings.

In the command shell, start the web app by running the following command:

node app.js

You should see the following output, which means that your app is up and running and ready to receive requests.

Example app listening on port 6000!

To stop the program, in the command shell, select Ctrl+C. You can rerun the app by using the node app.js command.

Tip

Alternatively, to run the node app.js command, use the Visual Studio Code debugger. Visual Studio Code's built-in debugger helps accelerate your edit, compile, and debug loop.

Open a browser and go to http://localhost:6000/public. In the browser window, you should see the following text displayed, along with the current date and time.

Step 8: Call the web API from your app

Try to call the protected web API endpoint without an access token. Open a browser and go to http://localhost:6000/hello. The API returns an unauthorized HTTP error message, confirming that web API is protected with a bearer token.

Continue to configure your app to call the web API. For guidance, see the Prerequisites section.

Get the complete example in GitHub: