title | description | services | author | manager | ms.service | ms.workload | ms.topic | ms.date | ms.author | ms.component |
---|---|---|---|---|---|---|---|---|---|---|
Secure your RESTful services by using HTTP basic authentication in Azure Active Directory B2C | Microsoft Docs |
Secure your custom REST API claims exchanges in your Azure AD B2C by using HTTP basic authentication. |
active-directory-b2c |
davidmu1 |
mtillman |
active-directory |
identity |
conceptual |
09/25/2017 |
davidmu |
B2C |
[!INCLUDE active-directory-b2c-advanced-audience-warning]
In a related Azure AD B2C article, you create a RESTful service (web API) that integrates with Azure Active Directory B2C (Azure AD B2C) user journeys without authentication.
In this article, you add HTTP basic authentication to your RESTful service so that only verified users, including B2C, can access your API. With HTTP basic authentication, you set the user credentials (app ID and app secret) in your custom policy.
For more information, see Basic authentication in ASP.NET web API.
Complete the steps in the Integrate REST API claims exchanges in your Azure AD B2C user journey article.
-
Open the Visual Studio project that you created earlier.
-
Add the following application settings to the web.config file under the
appSettings
element:<add key="WebApp:ClientId" value="B2CServiceUserAccount" /> <add key="WebApp:ClientSecret" value="your secret" />
-
Create a password, and then set the
WebApp:ClientSecret
value.To generate a complex password, run the following PowerShell code. You can use any arbitrary value.
$bytes = New-Object Byte[] 32 $rand = [System.Security.Cryptography.RandomNumberGenerator]::Create() $rand.GetBytes($bytes) $rand.Dispose() [System.Convert]::ToBase64String($bytes)
To begin, add the OWIN middleware NuGet packages to the project by using the Visual Studio Package Manager Console:
PM> Install-Package Microsoft.Owin
PM> Install-Package Owin
PM> Install-Package Microsoft.Owin.Host.SystemWeb
Add the ClientAuthMiddleware.cs
class under the App_Start folder. To do so:
-
Right-click the App_Start folder, select Add, and then select Class.
-
In the Name box, type ClientAuthMiddleware.cs.
-
Open the App_Start\ClientAuthMiddleware.cs file, and replace the file content with following code:
using Microsoft.Owin; using System; using System.Collections.Generic; using System.Configuration; using System.Linq; using System.Security.Principal; using System.Text; using System.Threading.Tasks; using System.Web; namespace Contoso.AADB2C.API { /// <summary> /// Class to create a custom owin middleware to check for client authentication /// </summary> public class ClientAuthMiddleware { private static readonly string ClientID = ConfigurationManager.AppSettings["WebApp:ClientId"]; private static readonly string ClientSecret = ConfigurationManager.AppSettings["WebApp:ClientSecret"]; /// <summary> /// Gets or sets the next owin middleware /// </summary> private Func<IDictionary<string, object>, Task> Next { get; set; } /// <summary> /// Initializes a new instance of the <see cref="ClientAuthMiddleware"/> class. /// </summary> /// <param name="next"></param> public ClientAuthMiddleware(Func<IDictionary<string, object>, Task> next) { this.Next = next; } /// <summary> /// Invoke client authentication middleware during each request. /// </summary> /// <param name="environment">Owin environment</param> /// <returns></returns> public Task Invoke(IDictionary<string, object> environment) { // Get wrapper class for the environment var context = new OwinContext(environment); // Check whether the authorization header is available. This contains the credentials. var authzValue = context.Request.Headers.Get("Authorization"); if (string.IsNullOrEmpty(authzValue) || !authzValue.StartsWith("Basic ", StringComparison.OrdinalIgnoreCase)) { // Process next middleware return Next(environment); } // Get credentials var creds = authzValue.Substring("Basic ".Length).Trim(); string clientId; string clientSecret; if (RetrieveCreds(creds, out clientId, out clientSecret)) { // Set transaction authenticated as client context.Request.User = new GenericPrincipal(new GenericIdentity(clientId, "client"), new string[] { "client" }); } return Next(environment); } /// <summary> /// Retrieve credentials from header /// </summary> /// <param name="credentials">Authorization header</param> /// <param name="clientId">Client identifier</param> /// <param name="clientSecret">Client secret</param> /// <returns>True if valid credentials were presented</returns> private bool RetrieveCreds(string credentials, out string clientId, out string clientSecret) { string pair; clientId = clientSecret = string.Empty; try { pair = Encoding.UTF8.GetString(Convert.FromBase64String(credentials)); } catch (FormatException) { return false; } catch (ArgumentException) { return false; } var ix = pair.IndexOf(':'); if (ix == -1) { return false; } clientId = pair.Substring(0, ix); clientSecret = pair.Substring(ix + 1); // Return whether credentials are valid return (string.Compare(clientId, ClientAuthMiddleware.ClientID) == 0 && string.Compare(clientSecret, ClientAuthMiddleware.ClientSecret) == 0); } } }
Add an OWIN startup class named Startup.cs
to the API. To do so:
-
Right-click the project, select Add > New Item, and then search for OWIN.
-
Open the Startup.cs file, and replace the file content with following code:
using Microsoft.Owin; using Owin; [assembly: OwinStartup(typeof(Contoso.AADB2C.API.Startup))] namespace Contoso.AADB2C.API { public class Startup { public void Configuration(IAppBuilder app) { app.Use<ClientAuthMiddleware>(); } } }
Open Controllers\IdentityController.cs, and add the [Authorize]
tag to the controller class. This tag restricts access to the controller to users who meet the authorization requirement.
To publish your project, in Solution Explorer, right-click the Contoso.AADB2C.API project, and then select Publish.
After your RESTful service is protected by the client ID (username) and secret, you must store the credentials in your Azure AD B2C tenant. Your custom policy provides the credentials when it invokes your RESTful services.
-
In your Azure AD B2C tenant, select B2C Settings > Identity Experience Framework.
-
Select Policy Keys to view the keys that are available in your tenant.
-
Select Add.
-
For Options, select Manual.
-
For Name, type B2cRestClientId.
The prefix B2C_1A_ might be added automatically. -
In the Secret box, enter the app ID that you defined earlier.
-
For Key usage, select Signature.
-
Select Create.
-
Confirm that you've created the
B2C_1A_B2cRestClientId
key.
-
In your Azure AD B2C tenant, select B2C Settings > Identity Experience Framework.
-
Select Policy Keys to view the keys available in your tenant.
-
Select Add.
-
For Options, select Manual.
-
For Name, type B2cRestClientSecret.
The prefix B2C_1A_ might be added automatically. -
In the Secret box, enter the app secret that you defined earlier.
-
For Key usage, select Signature.
-
Select Create.
-
Confirm that you've created the
B2C_1A_B2cRestClientSecret
key.
-
In your working directory, open the extension policy file (TrustFrameworkExtensions.xml).
-
Search for the
<TechnicalProfile>
node that includesId="REST-API-SignUp"
. -
Locate the
<Metadata>
element. -
Change the AuthenticationType to Basic, as follows:
<Item Key="AuthenticationType">Basic</Item>
-
Immediately after the closing
<Metadata>
element, add the following XML snippet:<CryptographicKeys> <Key Id="BasicAuthenticationUsername" StorageReferenceId="B2C_1A_B2cRestClientId" /> <Key Id="BasicAuthenticationPassword" StorageReferenceId="B2C_1A_B2cRestClientSecret" /> </CryptographicKeys>
After you add the snippet, your technical profile should look like the following XML code:
-
In the Azure portal, switch to the context of your Azure AD B2C tenant, and then open Azure AD B2C.
-
Select Identity Experience Framework.
-
Open All Policies.
-
Select Upload Policy.
-
Select the Overwrite the policy if it exists check box.
-
Upload the TrustFrameworkExtensions.xml file, and then ensure that it passes validation.
-
Open Azure AD B2C Settings, and then select Identity Experience Framework.
[!NOTE] Run Now requires at least one application to be preregistered on the tenant. To learn how to register applications, see the Azure AD B2C Get started article or the Application registration article.
-
Open B2C_1A_signup_signin, the relying party (RP) custom policy that you uploaded, and then select Run now.
-
Test the process by typing Test in the Given Name box.
Azure AD B2C displays an error message at the top of the window. -
In the Given Name box, type a name (other than "Test").
Azure AD B2C signs up the user and then sends a loyalty number to your application. Note the number in this example:{ "typ": "JWT", "alg": "RS256", "kid": "X5eXk4xyojNFum1kl2Ytv8dlNP4-c57dO6QGTVBwaNk" }.{ "exp": 1507125903, "nbf": 1507122303, "ver": "1.0", "iss": "https://contoso.b2clogin.com/f06c2fe8-709f-4030-85dc-38a4bfd9e82d/v2.0/", "aud": "e1d2612f-c2bc-4599-8e7b-d874eaca1ee1", "acr": "b2c_1a_signup_signin", "nonce": "defaultNonce", "iat": 1507122303, "auth_time": 1507122303, "loyaltyNumber": "290", "given_name": "Emily", "emails": ["[email protected]"] }
- After you complete the Get started with custom policies walkthrough, we recommend that you build your scenario by using your own custom policy files. For your reference, we have provided Sample policy files.
- You can download the complete code from Sample Visual Studio solution for reference.