Skip to content

Instantly share code, notes, and snippets.

@hossambarakat
Last active July 15, 2020 09:09
Show Gist options
  • Save hossambarakat/c6b4406404546330e60610045e374674 to your computer and use it in GitHub Desktop.
Save hossambarakat/c6b4406404546330e60610045e374674 to your computer and use it in GitHub Desktop.
B2C Client Credentials

As a first step you'll need to:

  1. Sign in to the Azure portal using either a work or school account or a personal Microsoft account.
  2. If your account is present in more than one Azure AD tenant, select Directory + Subscription at the top right corner in the menu on top of the page, and switch your portal session to the desired Azure AD tenant.
  3. In the left-hand navigation pane, select the Azure Active Directory service, and then select App registrations (Preview).

Register the app (webapi-and-daemon-app)

  1. Navigate to the Microsoft identity platform for developers App registrations page.
  2. Select New registration.
  3. When the Register an application page 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 webapi-and-daemon-app.
    • Leave Supported account types on the default setting of Accounts in any organizational directory or any identity provider. For authenticating users with Azure AD B2C..
  4. Select Register to create the application.
  5. On the app Overview page, find the Application (client) ID value and record it for later. You'll need it to configure the Visual Studio configuration file for this project.
  6. Select the Expose an API section, and:
    • On Application ID URI, click on Set. Keep the suggested value, for example https://<b2c-directory-name>.onmicrosoft.com/<web api client id>
    • Click Save
  7. Select the Manifest section, and:
    • Edit the manifest by locating the appRoles. The role definition is provided in the JSON code block below. Leave the allowedMemberTypes to Application only. Each role definition in this manifest must have a different valid Guid for the "id" property.
    • Save the manifest.

The content of appRoles should be the following (the id can be any unique Guid)

{
  ...
    "appRoles": [
        {
            "allowedMemberTypes": [
                "Application"
            ],
            "description": "Daemon apps in this role can consume the web api.",
            "displayName": "DaemonAppRole",
            "id": "7489c77e-0f34-4fe9-bf84-0ce8b74a03c4",
            "isEnabled": true,
            "lang": null,
            "origin": "Application",
            "value": "DaemonAppRole"
        }
    ],
 ...
}
  • Edit the manifest by locating the identifierUris. Add a new identifier with the format api://<unique guid>.
  • Save the manifest.
{
  ...
    "identifierUris": [
		"api://a4733c14-fd0d-47f2-bd9f-fa8be72ad71d",
		"https://<b2c-directory-name>.onmicrosoft.com/<web api client id>"
	],
 ...
}
  1. From the Certificates & secrets page, in the Client secrets section, choose New client secret:
    • Type a key description (of instance app secret),
    • Select a key duration of either In 1 year, In 2 years, or Never Expires.
    • When you press the Add button, the key value will be displayed, copy, and save the value in a safe location.
    • You'll need this key later to configure the project in Visual Studio. This key value will not be displayed again, nor retrievable by any other means, so record it as soon as it is visible from the Azure portal.
  2. In the list of pages for the app, select API permissions
    • Click the Add a permission button and then,
    • Ensure that the My APIs tab is selected
    • Select the API created in the previous step, for example TodoList-webapi-daemon-v2
    • In the Application permissions section, ensure that the right permissions are checked: DaemonAppRole
    • Select the Add permissions button
  3. At this stage permissions are assigned correctly but the client app does not allow interaction. Therefore no consent can be presented via a UI and accepted to use the service app. Click the Grant/revoke admin consent for {tenant} button, and then select Yes when you are asked if you want to grant consent for the requested permissions for all account in the tenant. You need to be an Azure AD tenant admin to do this.

You can request a client credentials token for an Azure B2C application by using the following code

using (var httpClient = new HttpClient())
    {
        httpClient.BaseAddress = new Uri("https://login.microsoftonline.com");

        var content = new FormUrlEncodedContent(new[]
        {
                new KeyValuePair<string, string>("grant_type", "client_credentials")
            , new KeyValuePair<string, string>("client_id", "application GUID")
            , new KeyValuePair<string, string>("client_secret", "client secret")
            , new KeyValuePair<string, string>("scope", "[App ID URI of the web api azure ad app]/.default e.g. https://my-b2c-tenant.onmicrosoft.com/my-azure-ad-ap/.default key thing is to make sure that you have /.default")
        });

        var requestResult = await httpClient.PostAsync("/my-b2c-tenant.onmicrosoft.com/oauth2/v2.0/token", content);
        var contentResult = await requestResult.Content.ReadAsStringAsync();

        var json = JObject.Parse(contentResult);
        var accessToken = (string)json["access_token"];
    }

Or using Identity Model

using (var httpClient = new HttpClient())
{
    var response = await httpClient.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest
    {
        Address = "https://login.microsoftonline.com/my-b2c-tenant.onmicrosoft.com/oauth2/v2.0/token",

        ClientId = "application GUID",
        ClientSecret = "client secret",
        Scope = "[App ID URI of the web api azure ad app]/.default e.g. https://my-b2c-tenant.onmicrosoft.com/my-azure-ad-ap/.default key thing is to make sure that you have /.default"
    });
}

In order to secure an ASP.NET Core API, You can use multiple authentication schemes

    services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(options =>
        {
            options.Authority = $"https://my-b2c-tenant.b2clogin.com/my-b2c-tenant.onmicrosoft.com/SignUpSignInPolicyId/v2.0";
            options.Audience = "api app client GUID";
        })
        .AddJwtBearer("AzureAD", options =>
        {
            options.Audience = "daemon app client GUID";
            options.Authority = "https://login.microsoftonline.com/<tenant GUID>";
            options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
            {
                ValidAudience = daemonClientId,
                ValidIssuer = "https://login.microsoftonline.com/<tenant GUID>/v2.0"
            };
        });

    services.AddAuthorization(options =>
    {
        var defaultAuthorizationPolicyBuilder = new AuthorizationPolicyBuilder(
            JwtBearerDefaults.AuthenticationScheme,
            "AzureAD");
        defaultAuthorizationPolicyBuilder = defaultAuthorizationPolicyBuilder.RequireAuthenticatedUser();
        options.DefaultPolicy = defaultAuthorizationPolicyBuilder.Build();
    });

You can use single application for both the API and Daemon applications

Further details could be read here https://docs.microsoft.com/en-us/aspnet/core/security/authorization/limitingidentitybyscheme?view=aspnetcore-3.1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment