This sample console app (.Net core) demonstrates how to send sign-up email invitation. The console application generates a link to sign-up policy with the email address to be validated. The link to the sign-up policy contains the email address, which is encapsulated inside a JWT token (client assertion). When a user clicks on that link, Azure AD B2C validates the JWT token signature, reads the information from the token, and extracts the email address.
The sample solution contains two policies you can use:
- B2C_1A_invite_signup - Sign-up invitation policy
- B2C_1A_invite_signin_with_mfa - Sign-up invitation with MFA policy. The application sends also the user phone number as input claim. User is asked to verify the phone number, without the ability to change the phone number.
The solution also contains the sign-in policy, with and without MFA. Policy names:
- B2C_1A_invite_signin
- B2C_1A_invite_signin_with_mfa
The sample app is developed and managed by the open-source community in GitHub. The application is not part of Azure AD B2C product and it's not supported under any Microsoft standard support program or service. The app is provided AS IS without warranty of any kind.
Important: The way Azure AD B2C accepts the client assertion probably will be changed in the future. Until this change, you can use the client assertion method safely. But you should prepare yourself to the changes.
The key of sending data to Azure AD B2C custom policy is to package the data into a JWT token as claims (client assertion). In this case, we send the user's email address to Azure B2C. Sending JWT token requires adding two query strings in the request to the policy.
- client_assertion_type The value always should be
urn:ietf:params:oauth:client-assertion-type:jwt-bearer
, which is a constant string. - client_assertion The value is a JWT token containing input claims for the policy and signed by your application.
As described earlier, the data to be sent, needs to be packaged as JWT with claims. In this example, we add the ValidationEmail claim, which represents the user email address. You can add more claims as nessuccry. The app generates a JWT representation, which can then be used as a client assertion.
With client assertion, the client signs the JWT token to prove the token request comes from your web application, by using signing key. You need the signing key, later to store it B2C keys. Your policy uses that key to validate the incoming JWT token, issued by your web application. Use following PowerShell code to generate client secret.
$bytes = New-Object Byte[] 32
$rand = [System.Security.Cryptography.RandomNumberGenerator]::Create()
$rand.GetBytes($bytes)
$rand.Dispose()
$newClientSecret = [System.Convert]::ToBase64String($bytes)
$newClientSecret
Note: the PowerShell generates a secret string. But you can define and use any arbitrary string.
As mentioned, Azure AD B2C needs the client secret to validate the incoming JWT token. You need to store the client secret your application uses to sign in, in your Azure AD B2C tenant:
- Go to your Azure AD B2C tenant, and select B2C Settings > Identity Experience Framework
- Select Policy Keys to view the keys available in your tenant.
- Click +Add.
- For Options, use Manual.
- For Name, use
ClientAssertionSigningKey
.
The prefixB2C_1A_
might be added automatically. - In the Secret box, enter your sign-in key you generated earlier
- For Key usage, use Encryption.
- Click Create
- Confirm that you've created the key
B2C_1A_ClientAssertionSigningKey
.
The Relying Party is responsible to read the input claim (client assertion). Make sure you specify the client_secret
with the policy key you already created. In this example, we read the input claim ValidationEmail
to both claim types: email this claim use to store the email address in the user account. And the second one is ReadOnlyEmail for display only
<CryptographicKeys>
<Key Id="client_secret" StorageReferenceId="B2C_1A_ClientAssertionSigningKey" />
</CryptographicKeys>
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" PartnerClaimType="ValidationEmail" />
<InputClaim ClaimTypeReferenceId="ReadOnlyEmail" PartnerClaimType="ValidationEmail" />
</InputClaims>
This sample policy is based on SocialAndLocalAccountsWithMfa starter pack.
- All changes are marked with Demo: comment inside the policy XML files.
- Make the necessary changes in the Action required comments
- Program.cs The
static void Main(string[] args)
contains the code that generates the client assertion, marge the HTML template and send the email - appsettings.json application settings
- Template.html The email template. You can customize the template.
- Models folder - this folder contains the necessary object-mapping classes
To test the sample solution, open the AADB2C.Invite.sln
Visual Studio solution in Visual Studio. In the AADB2C.Invite
project, open the appsettings.json
. Replace the app settings with your own values:
- SMTPServer: Your SMTP server
- SMTPPort: Your SMTP server port number
- SMTPUsername: SMTP user name, if necessary
- SMTPPassword: SMTP password, if necessary
- SMTPUseSSL: SMTP use SSL, true of false
- SMTPFromAddress: Send from email address
- SMTPSubject: The invitation email's subject
- ClientSigningKey: The JTW signature secret you generated earlier with the PowerShell.
- SignUpUrl: Full url to your policy, including your tenant name, policy name such as
B2C_1A_invite_signup
orB2C_1A_invite_signin_with_mfa
, client Id and redirect URL.
For example:
"AppSettings": {
"SMTPServer": "smtp.sendgrid.net",
"SMTPPort": 587,
"SMTPUsername": "[email protected]",
"SMTPPassword": "1234",
"SMTPUseSSL": true,
"SMTPFromAddress": "[email protected]",
"SMTPSubject": "Sign-up account email verification",
"ClientSigningKey": "VK62QTn0m1hMcn0DQ3RPYDAr6yIiSvYgdRwjZtU5QhI=",
"SignUpUrl": "https://contoso.b2clogin.com/contoso.onmicrosoft.com/oauth2/v2.0/authorize?p=B2C_1A_invite_signin&client_id=0239a9cc-309c-4d41-87f1-31288feb2e82&nonce=defaultNonce&redirect_uri=https%3A%2F%2Fjwt.ms&scope=openid&response_type=id_token&prompt=login"
}
- Run the console app
- Type user email address and click enter
- [Optional] Type a phone number with country prefix, such as (+4402072343456). You can skip this step.
- Open the user's mailbox and click on the Confirm account link
- Provide your password and user profile and click continue
- If you use MFA, verify your phone number and click continue
- Try to send an invite and make user the user is created in the directory
- Try to run the policy without invitation, make sure B2C presents the unsolicited error message