Define a RESTful technical profile in an Azure Active Directory B2C custom policy

Note

In Azure Active Directory B2C, custom policies are designed primarily to address complex scenarios. For most scenarios, we recommend that you use built-in user flows.

Azure Active Directory B2C (Azure AD B2C) provides support for integrating your own RESTful service. Azure AD B2C sends data to the RESTful service in an input claims collection and receives data back in an output claims collection. For more information, see Integrate REST API claims exchanges in your Azure AD B2C custom policy.

Protocol

The Name attribute of the Protocol element needs to be set to Proprietary. The handler attribute must contain the fully qualified name of the protocol handler assembly that is used by Azure AD B2C: Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null.

The following example shows a RESTful technical profile:

<TechnicalProfile Id="REST-UserMembershipValidator">
  <DisplayName>Validate user input data and return loyaltyNumber claim</DisplayName>
  <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
  ...

Input claims

The InputClaims element contains a list of claims to send to the REST API. You can also map the name of your claim to the name defined in the REST API. Following example shows the mapping between your policy and the REST API. The givenName claim is sent to the REST API as firstName, while surname is sent as lastName. The email claim is set as is.

<InputClaims>
  <InputClaim ClaimTypeReferenceId="email" />
  <InputClaim ClaimTypeReferenceId="givenName" PartnerClaimType="firstName" />
  <InputClaim ClaimTypeReferenceId="surname" PartnerClaimType="lastName" />
</InputClaims>

The InputClaimsTransformations element may contain a collection of InputClaimsTransformation elements that are used to modify the input claims or generate new ones before sending to the REST API.

Send a JSON payload

The REST API technical profile allows you to send a complex JSON payload to an endpoint.

To send a complex JSON payload:

  1. Build your JSON payload with the GenerateJson claims transformation.
  2. In the REST API technical profile:
    1. Add an input claims transformation with a reference to the GenerateJson claims transformation.
    2. Set the SendClaimsIn metadata option to body
    3. Set the ClaimUsedForRequestPayload metadata option to the name of the claim containing the JSON payload.
    4. In the input claim, add a reference to the input claim containing the JSON payload.

The following example TechnicalProfile sends a verification email by using a third-party email service (in this case, SendGrid).

<TechnicalProfile Id="SendGrid">
  <DisplayName>Use SendGrid's email API to send the code the the user</DisplayName>
  <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
  <Metadata>
    <Item Key="ServiceUrl">https://api.sendgrid.com/v3/mail/send</Item>
    <Item Key="AuthenticationType">Bearer</Item>
    <Item Key="SendClaimsIn">Body</Item>
    <Item Key="ClaimUsedForRequestPayload">sendGridReqBody</Item>
    <Item Key="DefaultUserMessageIfRequestFailed">Cannot process your request right now, please try again later.</Item>
  </Metadata>
  <CryptographicKeys>
    <Key Id="BearerAuthenticationToken" StorageReferenceId="B2C_1A_SendGridApiKey" />
  </CryptographicKeys>
  <InputClaimsTransformations>
    <InputClaimsTransformation ReferenceId="GenerateSendGridRequestBody" />
  </InputClaimsTransformations>
  <InputClaims>
    <InputClaim ClaimTypeReferenceId="sendGridReqBody" />
  </InputClaims>
</TechnicalProfile>

Output claims

The OutputClaims element contains a list of claims returned by the REST API. You may need to map the name of the claim defined in your policy to the name defined in the REST API. You can also include claims that aren't returned by the REST API identity provider, as long as you set the DefaultValue attribute.

The OutputClaimsTransformations element may contain a collection of OutputClaimsTransformation elements that are used to modify the output claims or generate new ones.

The following example shows the claim returned by the REST API:

  • The MembershipId claim that is mapped to the loyaltyNumber claim name.

The technical profile also returns claims, that aren't returned by the identity provider:

  • The loyaltyNumberIsNew claim that has a default value set to true.
<OutputClaims>
  <OutputClaim ClaimTypeReferenceId="loyaltyNumber" PartnerClaimType="MembershipId" />
  <OutputClaim ClaimTypeReferenceId="loyaltyNumberIsNew" DefaultValue="true" />
</OutputClaims>

Metadata

Attribute Required Description
ServiceUrl Yes The URL of the REST API endpoint.
AuthenticationType Yes The type of authentication being performed by the RESTful claims provider. Possible values: None, Basic, Bearer, or ClientCertificate. The None value indicates that the REST API is anonymous. The Basic value indicates that the REST API is secured with HTTP basic authentication. Only verified users, including Azure AD B2C, can access your API. The ClientCertificate (recommended) value indicates that the REST API restricts access by using client certificate authentication. Only services that have the appropriate certificates, for example Azure AD B2C, can access your API. The Bearer value indicates that the REST API restricts access using client OAuth2 Bearer token.
AllowInsecureAuthInProduction No Indicates whether the AuthenticationType can be set to none in production environment (DeploymentMode of the TrustFrameworkPolicy is set to Production, or not specified). Possible values: true, or false (default).
SendClaimsIn No Specifies how the input claims are sent to the RESTful claims provider. Possible values: Body (default), Form, Header, or QueryString. The Body value is the input claim that is sent in the request body in JSON format. The Form value is the input claim that is sent in the request body in an ampersand '&' separated key value format. The Header value is the input claim that is sent in the request header. The QueryString value is the input claim that is sent in the request query string. The HTTP verbs invoked by each are as follows:
  • Body: POST
  • Form: POST
  • Header: GET
  • QueryString: GET
ClaimsFormat No Not currently used, can be ignored.
ClaimUsedForRequestPayload No Name of a string claim that contains the payload to be sent to the REST API.
DebugMode No Runs the technical profile in debug mode. Possible values: true, or false (default). In debug mode, the REST API can return more information. See the Returning error message section.
IncludeClaimResolvingInClaimsHandling   No For input and output claims, specifies whether claims resolution is included in the technical profile. Possible values: true, or false (default). If you want to use a claims resolver in the technical profile, set this to true.
ResolveJsonPathsInJsonTokens No Indicates whether the technical profile resolves JSON paths. Possible values: true, or false (default). Use this metadata to read data from a nested JSON element. In an OutputClaim, set the PartnerClaimType to the JSON path element you want to output. For example: firstName.localized, or data.0.to.0.email.
UseClaimAsBearerToken No The name of the claim that contains the bearer token.

Error handling

The following metadata can be used to configure the error messages displayed upon REST API failure. The error messages can be localized.

Attribute Required Description
DefaultUserMessageIfRequestFailed No A default customized error message for all REST API exceptions.
UserMessageIfCircuitOpen No Error message when the REST API is not reachable. If not specified, the DefaultUserMessageIfRequestFailed will be returned.
UserMessageIfDnsResolutionFailed No Error message for the DNS resolution exception. If not specified, the DefaultUserMessageIfRequestFailed will be returned.
UserMessageIfRequestTimeout No Error message when the connection is timed out. If not specified, the DefaultUserMessageIfRequestFailed will be returned.

Cryptographic keys

If the type of authentication is set to None, the CryptographicKeys element is not used.

<TechnicalProfile Id="REST-API-SignUp">
  <DisplayName>Validate user's input data and return loyaltyNumber claim</DisplayName>
  <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
  <Metadata>
    <Item Key="ServiceUrl">https://your-app-name.azurewebsites.NET/api/identity/signup</Item>
    <Item Key="AuthenticationType">None</Item>
    <Item Key="SendClaimsIn">Body</Item>
  </Metadata>
</TechnicalProfile>

If the type of authentication is set to Basic, the CryptographicKeys element contains the following attributes:

Attribute Required Description
BasicAuthenticationUsername Yes The username that is used to authenticate.
BasicAuthenticationPassword Yes The password that is used to authenticate.

The following example shows a technical profile with basic authentication:

<TechnicalProfile Id="REST-API-SignUp">
  <DisplayName>Validate user's input data and return loyaltyNumber claim</DisplayName>
  <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
  <Metadata>
    <Item Key="ServiceUrl">https://your-app-name.azurewebsites.NET/api/identity/signup</Item>
    <Item Key="AuthenticationType">Basic</Item>
    <Item Key="SendClaimsIn">Body</Item>
  </Metadata>
  <CryptographicKeys>
    <Key Id="BasicAuthenticationUsername" StorageReferenceId="B2C_1A_B2cRestClientId" />
    <Key Id="BasicAuthenticationPassword" StorageReferenceId="B2C_1A_B2cRestClientSecret" />
  </CryptographicKeys>
</TechnicalProfile>

If the type of authentication is set to ClientCertificate, the CryptographicKeys element contains the following attribute:

Attribute Required Description
ClientCertificate Yes The X509 certificate (RSA key set) to use to authenticate.
<TechnicalProfile Id="REST-API-SignUp">
  <DisplayName>Validate user's input data and return loyaltyNumber claim</DisplayName>
  <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
  <Metadata>
    <Item Key="ServiceUrl">https://your-app-name.azurewebsites.NET/api/identity/signup</Item>
    <Item Key="AuthenticationType">ClientCertificate</Item>
    <Item Key="SendClaimsIn">Body</Item>
  </Metadata>
  <CryptographicKeys>
    <Key Id="ClientCertificate" StorageReferenceId="B2C_1A_B2cRestClientCertificate" />
  </CryptographicKeys>
</TechnicalProfile>

If the type of authentication is set to Bearer, the CryptographicKeys element contains the following attribute:

Attribute Required Description
BearerAuthenticationToken No The OAuth 2.0 Bearer Token.
<TechnicalProfile Id="REST-API-SignUp">
  <DisplayName>Validate user's input data and return loyaltyNumber claim</DisplayName>
  <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
  <Metadata>
    <Item Key="ServiceUrl">https://your-app-name.azurewebsites.NET/api/identity/signup</Item>
    <Item Key="AuthenticationType">Bearer</Item>
    <Item Key="SendClaimsIn">Body</Item>
  </Metadata>
  <CryptographicKeys>
    <Key Id="BearerAuthenticationToken" StorageReferenceId="B2C_1A_B2cRestClientAccessToken" />
  </CryptographicKeys>
</TechnicalProfile>

Returning validation error message

Your REST API may need to return an error message, such as 'The user was not found in the CRM system'. If an error occurs, the REST API should return an HTTP 4xx error message, such as, 400 (bad request), or 409 (conflict) response status code. The response body contains error message formatted in JSON:

{
  "version": "1.0.0",
  "status": 409,
  "code": "API12345",
  "requestId": "50f0bd91-2ff4-4b8f-828f-00f170519ddb",
  "userMessage": "Message for the user",
  "developerMessage": "Verbose description of problem and how to fix it.",
  "moreInfo": "https://restapi/error/API12345/moreinfo"
}
Attribute Required Description
version Yes Your REST API version. For example: 1.0.1
status Yes Must be 409
code No An error code from the RESTful endpoint provider, which is displayed when DebugMode is enabled.
requestId No A request identifier from the RESTful endpoint provider, which is displayed when DebugMode is enabled.
userMessage Yes An error message that is shown to the user.
developerMessage No The verbose description of the problem and how to fix it, which is displayed when DebugMode is enabled.
moreInfo No A URI that points to additional information, which is displayed when DebugMode is enabled.

The following example shows a C# class that returns an error message:

public class ResponseContent
{
  public string version { get; set; }
  public int status { get; set; }
  public string code { get; set; }
  public string userMessage { get; set; }
  public string developerMessage { get; set; }
  public string requestId { get; set; }
  public string moreInfo { get; set; }
}

Next steps

See the following articles for examples of using a RESTful technical profile: