Define an ID token hint technical profile in an Azure Active Directory B2C custom policy

Azure AD B2C allows relying party applications to send an inbound JWT as part of the OAuth2 authorization request. The JWT token can be issued by a relying party application or an identity provider, and it can pass a hint about the user or the authorization request. Azure AD B2C validates the signature, issuer name, and token audience, and extracts the claim from the inbound token.

Use cases

You can use this solution to send data to Azure AD B2C encapsulated in a single JWT token. The Signup with email invitation solution, where your system admin can send a signed invite to users, is based on id_token_hint. Only users with access to the invite email can create the account in the directory.

Token signing approach

With id_token_hint, the token issuer (a relying party app or an identity provider) composes the token, and then signs it by using a signing key to prove the token comes from a trusted source. The signing key can be symmetric or asymmetric. Symmetric cryptography, or private key cryptography, uses a shared secret to both sign and validate the signature. Asymmetric cryptography, or public key cryptography, is a cryptographic system that uses both a private key and a public key. The private key is known only to the token issuer and is used to sign the token. The public key is shared with the Azure AD B2C policy to validate the signature of the token.

Token format

The id_token_hint must be a valid JWT token. The following table lists the claims that are mandatory. Additional claims are optional.

Name Claim Example value Description
Audience aud 00001111-aaaa-2222-bbbb-3333cccc4444 Identifies the intended recipient of the token. The audience is an arbitrary string defined by the token issuer. Azure AD B2C validates this value, and rejects the token if it doesn't match.
Issuer iss https://localhost Identifies the security token service (token issuer). The issuer is an arbitrary URI defined by the token issuer. Azure AD B2C validates this value, and rejects the token if it doesn't match.
Expiration time exp 1600087315 The time at which the token becomes invalid, represented in epoch time. Azure AD B2C validates this value, and rejects the token if the token is expired.
Not before nbf 1599482515 The time at which the token becomes valid, represented in epoch time. This time is usually the same as the time the token was issued. Azure AD B2C validates this value, and rejects the token if the token lifetime is not valid.

The following token is an example of a valid ID token:

{
  "alg": "HS256",
  "typ": "JWT"
}.{
  "displayName": " John Smith",
  "userId": "john.s@contoso.com",
  "nbf": 1599482515,
  "exp": 1600087315,
  "iss": "https://localhost",
  "aud": "00001111-aaaa-2222-bbbb-3333cccc4444"
}

Protocol

The Name attribute of the Protocol element needs to be set to None. For example, the protocol for the IdTokenHint_ExtractClaims technical profile is None:

<TechnicalProfile Id="IdTokenHint_ExtractClaims">
  <DisplayName> My ID Token Hint TechnicalProfile</DisplayName>
  <Protocol Name="None" />
  ...

The technical profile is called from an orchestration step with type of GetClaims.

<OrchestrationStep Order="1" Type="GetClaims" CpimIssuerTechnicalProfileReferenceId="IdTokenHint_ExtractClaims" />

Output claims

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

Metadata

The following metadata is relevant when using symmetric key.

Attribute Required Description
issuer Yes Identifies the security token service (token issuer). This value must be identical to the iss claim within the JWT token claim.
IdTokenAudience Yes Identifies the intended recipient of the token. Must be identical to the aud claim within the JWT token claim.

The following metadata is relevant when using an asymmetric key.

Attribute Required Description
METADATA Yes A URL that points to a token issuer configuration document, which is also known as an OpenID well-known configuration endpoint.
issuer No Identifies the security token service (token issuer). This value can be used to overwrite the value configured in the metadata, and must be identical to the iss claim within the JWT token claim.
IdTokenAudience No Identifies the intended recipient of the token. Must be identical to the aud claim within the JWT token claim.

Important

Your endpoints must comply with the Azure AD B2C security requirements. Older TLS versions and ciphers are deprecated. For more information, see Azure AD B2C TLS and cipher suite requirements.

Cryptographic keys

When using a symmetric key, the CryptographicKeys element contains the following attribute:

Attribute Required Description
client_secret Yes The cryptographic key that is used to validate the JWT token signature.

How-to guide

Issue a token with symmetric keys

Step 1: Create a shared key

Create a key that can be used to sign the token. For example, use the following PowerShell code to generate a key.

$bytes = New-Object Byte[] 32
$rand = [System.Security.Cryptography.RandomNumberGenerator]::Create()
$rand.GetBytes($bytes)
$rand.Dispose()
$newClientSecret = [System.Convert]::ToBase64String($bytes)
$newClientSecret

This code creates a secret string like VK62QTn0m1hMcn0DQ3RPYDAr6yIiSvYgdRwjZtU5QhI=.

Step 2: Add the signing key to Azure AD B2C

The same key that is used by the token issuer needs to be created in your Azure AD B2C policy keys.

  1. Sign in to the Azure portal.
  2. If you have access to multiple tenants, select the Settings icon in the top menu to switch to your Azure AD B2C tenant from the Directories + subscriptions menu.
  3. In the Azure portal, search for and select Azure AD B2C.
  4. On the overview page, under Policies, select Identity Experience Framework.
  5. Select Policy Keys
  6. Select Manual.
  7. For Name, use IdTokenHintKey.
    The prefix B2C_1A_ might be added automatically.
  8. In the Secret box, enter the sign-in key you generated earlier.
  9. For Key usage, use Encryption.
  10. Select Create.
  11. Confirm that you've created the key B2C_1A_IdTokenHintKey.

Step 3: Add the ID token hint technical profile

The following technical profile validates the token and extracts the claims.

<ClaimsProvider>
  <DisplayName>My ID Token Hint ClaimsProvider</DisplayName>
  <TechnicalProfiles>
    <TechnicalProfile Id="IdTokenHint_ExtractClaims">
      <DisplayName> My ID Token Hint TechnicalProfile</DisplayName>
      <Protocol Name="None" />
      <Metadata>
        <Item Key="IdTokenAudience">00001111-aaaa-2222-bbbb-3333cccc4444</Item>
        <Item Key="issuer">https://localhost</Item>
      </Metadata>
      <CryptographicKeys>
        <Key Id="client_secret" StorageReferenceId="B2C_1A_IdTokenHintKey" />
      </CryptographicKeys>
      <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="userId" />
      </OutputClaims>
    </TechnicalProfile>
  </TechnicalProfiles>
</ClaimsProvider>

Step 4: Prepare your policy

Complete the Configure your policy step.

Step 5: Prepare the code

The GitHub sample is an ASP.NET web application and console app that generates an ID token that is signed using a symmetric key.

Issue a token with asymmetric keys

With an asymmetric key, the token is signed using RSA certificates. This application hosts an OpenID Connect metadata endpoint and JSON Web Keys (JWKs) endpoint that is used by Azure AD B2C to validate the signature of the ID token.

The token issuer must provide following endpoints:

  • /.well-known/openid-configuration - A well-known configuration endpoint with relevant information about the token, such as the token issuer name and the link to the JWK endpoint.
  • /.well-known/keys - the JSON Web Key (JWK) end point with the public key that is used to sign the key (with the private key part of the certificate).

See the TokenMetadataController.cs .NET MVC controller sample.

Step 1: Prepare a self-signed certificate

If you don't already have a certificate, you can use a self-signed certificate for this how-to guide. On Windows, you can use PowerShell's New-SelfSignedCertificate cmdlet to generate a certificate.

Run this PowerShell command to generate a self-signed certificate. Modify the -Subject argument as appropriate for your application and Azure AD B2C tenant name. You can also adjust the -NotAfter date to specify a different expiration for the certificate.

New-SelfSignedCertificate `
    -KeyExportPolicy Exportable `
    -Subject "CN=yourappname.yourtenant.onmicrosoft.com" `
    -KeyAlgorithm RSA `
    -KeyLength 2048 `
    -KeyUsage DigitalSignature `
    -NotAfter (Get-Date).AddMonths(12) `
    -CertStoreLocation "Cert:\CurrentUser\My"

Step 2: Add the ID token hint technical profile

The following technical profile validates the token and extracts the claims. Change the metadata URI to your token issuer well-known configuration endpoint.

<ClaimsProvider>
  <DisplayName>My ID Token Hint ClaimsProvider</DisplayName>
  <TechnicalProfiles>
    <TechnicalProfile Id="IdTokenHint_ExtractClaims">
      <DisplayName> My ID Token Hint TechnicalProfile</DisplayName>
      <Protocol Name="None" />
      <Metadata>
        <!-- Replace with your endpoint location -->
        <Item Key="METADATA">https://your-app.azurewebsites.net/.well-known/openid-configuration</Item>
        <Item Key="IdTokenAudience">your_optional_audience</Item>
        <!-- <Item Key="issuer">your_optional_token_issuer_override</Item> -->
      </Metadata>
      <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="userId" />
      </OutputClaims>
    </TechnicalProfile>
  </TechnicalProfiles>
</ClaimsProvider>

Step 3: Prepare your policy

Complete the Configure your policy step.

Step 4: Prepare the code

This GitHub sample ASP.NET web application generates ID tokens and hosts the metadata endpoints required to use the "id_token_hint" parameter in Azure AD B2C.

Configure your policy

For both symmetric and asymmetric approaches, the id_token_hint technical profile is called from an orchestration step with type of GetClaims and needs to specify the input claims of the relying party policy.

  1. Add the IdTokenHint_ExtractClaims technical profile to your extension policy.

  2. Add the following orchestration step to your user journey as the first item.

    <OrchestrationStep Order="1" Type="GetClaims" CpimIssuerTechnicalProfileReferenceId="IdTokenHint_ExtractClaims" />
    
  3. In your relying party policy, repeat the same input claims you configured in the IdTokenHint_ExtractClaims technical profile. For example:

    <RelyingParty>
      <DefaultUserJourney ReferenceId="SignUp" />
      <TechnicalProfile Id="PolicyProfile">
        <DisplayName>PolicyProfile</DisplayName>
        <Protocol Name="OpenIdConnect" />
        <InputClaims>
          <InputClaim ClaimTypeReferenceId="email" PartnerClaimType="userId" />
        </InputClaims>
        <OutputClaims>
          <OutputClaim ClaimTypeReferenceId="displayName" />
          <OutputClaim ClaimTypeReferenceId="givenName" />
          <OutputClaim ClaimTypeReferenceId="surname" />
          <OutputClaim ClaimTypeReferenceId="email" />
          <OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub"/>
          <OutputClaim ClaimTypeReferenceId="identityProvider" />
        </OutputClaims>
        <SubjectNamingInfo ClaimType="sub" />
      </TechnicalProfile>
    </RelyingParty>
    

Depending on your business requirements, you might need to add token validations, for example check the format of the email address. To do so, add orchestration steps that invoke a claims transformation technical profile. Also add a self-asserted technical profile to present an error message.

Create and sign a token

The GitHub samples illustrate how to create such a token issue a JWT that later sent as a id_token_hint query string parameter. Following is an example of an authorization request with id_token_hint parameter

https://tenant-name.b2clogin.com/tenant-name.onmicrosoft.com/B2C_1A_signup_signin/oauth2/v2.0/authorize?client_id=11112222-bbbb-3333-cccc-4444dddd5555&nonce=defaultNonce&redirect_uri=https%3A%2F%2Fjwt.ms&scope=openid&response_type=id_token&prompt=login&id_token_hint=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkaXNwbGF5TmFtZSI6IiBKb2huIFNtaXRoIiwidXNlcklkIjoiam9obi5zQGNvbnRvc28uY29tIiwibmJmIjoxNTk5NDgyNTE1LCJleHAiOjE2MDAwODczMTUsImlzcyI6Imh0dHBzOi8vbG9jYWxob3N0IiwiYXVkIjoiYTQ4OWZjNDQtM2NjMC00YTc4LTkyZjYtZTQxM2NkODUzZWFlIn0.nPmLXydI83PQCk5lRBYUZRu_aX58pL1khahHyQuupig

Next steps