How Do I Whitelist Email Domains In Signup With Azure B2C? - azure-ad-b2c

I am using simple email signup for Azure B2C and not SSO and my user flow is the basic one from this tutorial
https://learn.microsoft.com/en-ca/azure/active-directory-b2c/tutorial-create-user-flows
At the moment I am using temporary email addresses for my testing, however, when I go live I want to whitelist the domains that people can sign up with.
How do I do this whitelisting?

Currently Using Azure AD B2C Userflows we can't Whitelist the users while signup based on the email domain. We Need to handle it using Custom policies by calling the Rest API and need to validate the email address.
Please go through the documents and sample on using Custom policies with Rest API.
A Restful technical profile provides support for interfacing with your own RESTful service. Azure AD B2C sends data to the RESTful service in an InputClaims collection and receives data back in an OutputClaims collection. Find the ClaimsProviders element in your
Configure the REST API technical profile
<ClaimsProvider>
<DisplayName>REST APIs</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="REST-GetProfile">
<DisplayName>Get user extended profile Azure Function web hook</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-account.azurewebsites.net/api/GetProfile?code=your-code</Item>
<Item Key="SendClaimsIn">Body</Item>
<!-- Set AuthenticationType to Basic or ClientCertificate in production environments -->
<Item Key="AuthenticationType">None</Item>
<!-- REMOVE the following line in production environments -->
<Item Key="AllowInsecureAuthInProduction">true</Item>
</Metadata>
<InputClaims>
<!-- Claims sent to your REST API -->
<InputClaim ClaimTypeReferenceId="objectId" />
<InputClaim ClaimTypeReferenceId="userLanguage" PartnerClaimType="lang" DefaultValue="{Culture:LCID}" AlwaysUseDefaultValue="true" />
</InputClaims>
<OutputClaims>
<!-- Claims parsed from your REST API -->
<OutputClaim ClaimTypeReferenceId="balance" />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
You need to handle the Email validation logic in your REST API. The above Provideed document links helps you in building the custom policy.
This limitation is already raised in the Azure Feedback uservoice and to consider this feature request for the future, please upvote on the existing UserVoice.
That way the product group can prioritize this accordingly.

Related

How to avoid hardcoding ServiceUrl in AD B2C custom policy API connector?

I have a REST API connector in my B2C custom policy. All examples I have seen hard code the value of the ServiceUrl metadata item in the REST technical profile. For example:
<ClaimsProvider>
<DisplayName>REST APIs</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="REST-MyApiConnector">
<DisplayName>This an example of my API connector</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://someapi.com/api/endpoint</Item>
<Item Key="SendClaimsIn">Url</Item>
<Item Key="AuthenticationType">Basic</Item>
<Item Key="AllowInsecureAuthInProduction">false</Item>
</Metadata>
<CryptographicKeys>
<Key Id="BasicAuthenticationUsername" StorageReferenceId="B2C_1A_RestApiUsername" />
<Key Id="BasicAuthenticationPassword" StorageReferenceId="B2C_1A_RestApiPassword" />
</CryptographicKeys>
<InputClaims>
</InputClaims>
<OutputClaims>
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
I have seen a snippet on a GitHub issue (https://github.com/MicrosoftDocs/azure-docs/issues/58267) where the poster seems to have pulled the ServiceUrl from some external settings:
<Item Key="ServiceUrl">{Settings:CID-ApiUrl}/{user_id}</Item>
I can't seem to find any further information on this. Is there a way to store things like the ServiceUrl in some external settings that can then be accessed within the custom policy to avoid having to hardcode the URL?
Loading the ServiceUrl dynamically is not possible once it is deployed to B2C. But there is a very useful VS Code extension which should help during development. Go to the policy settings section from the following documentation: Azure AD B2C Tools for VSCode
In short, it helps to define variables, and replace them based on values stored in an appsettings.json file. You can have multiple sets of settings for different environments. Then use a single command to replace all variables and get the final policies to another folder.
You can then deploy them to your b2c tenant. Another option is to replace the variables from a CI/CD pipelines and deploy them to the tenant.
It’s not dynamic. They would be using CICD pipeline to populate them before uploading into the tenant.

Azure B2C - Facebook Signup asks for Profile picture instead of email

I have a B2C custom policy that uses Facebook as an IDP. My policy asks FB for name, email etc. However, when a user signs up throug Facebook, FB displays that the name and profile picture is required. I have not specified profile picture in my policy. What am i missing?
Here is a screenshot of what I see on FB
Below is the a snippet of my facebook configuration in my custom policy
<ClaimsProvider>
<DisplayName>Sign in with Facebook</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="Facebook-OAUTH">
<DisplayName>Sign in with Facebook</DisplayName>
<Metadata>
<Item Key="client_id">{Settings:FacebookAppId}</Item>
<Item Key="scope">email public_profile</Item>
<Item Key="ClaimsEndpoint">https://graph.facebook.com/me?fields=id,first_name,last_name,name,email</Item>
</Metadata>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="email" />
</OutputClaims>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
Facebook prompts for consent based on the permissions you selected on the Facebook dev portal for your application. This has nothing to do with your B2C custom policy. You need to adjust the permissions on your application in the Facebook dev portal and remove the permission for profile photo.

B2C: Localization for messages originating from REST API

I am currently implementing this example to use an rest API during the user registration.
The basic idea is that the API throws an 409 Conflict error to interrupt the registration.
// Can I return a special "StringId" or something here for localization?
return new ConflictObjectResult(new B2CResponseModel($"A verification email sent to you. Please open your mail box and click on the link. If you didn't receive the email, please click on the 'Send verification email' button.", HttpStatusCode.Conflict));
I want to show the user a message that is localized to their current language. I would prefer to do the localization within the custom policies, but I would also accept a solution within the API (would need to get the User Language for this).
Is there a way to do this localization? Like returning a StringId via API and using this within the policy?
I am also considering not returning an error from the API, to show the message in a new screen instead (like How to display error returned from custom REST API endpoint in a subsequent orchestration step?). However, localization options for this elude me as well.
In case anybody is looking for a way to send the user's locale to the REST API:
https://learn.microsoft.com/nb-no/azure/active-directory-b2c/claim-resolver-overview
<TechnicalProfile Id="REST-API-SendVerificationEmail">
<DisplayName>Sign-Up send link</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://xxxx</Item>
<Item Key="AuthenticationType">None</Item>
<Item Key="SendClaimsIn">Body</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" />
<InputClaim ClaimTypeReferenceId="userLanguage" DefaultValue="{Culture:LanguageName}" />
<InputClaim ClaimTypeReferenceId="policyId" PartnerClaimType="policy" DefaultValue="{Policy:PolicyId}" />
<InputClaim ClaimTypeReferenceId="scope" DefaultValue="{OIDC:scope}" />
<InputClaim ClaimTypeReferenceId="clientId" DefaultValue="{OIDC:ClientId}" />
</InputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
Hope this is similar to this
See the answer by Jas Suri. Pass the localisation parameter to API and return the localised message or can return an error code and based on that display translated message using policy itself.

Reading Extension Claims in Azure AD B2C

I have 2 claims that I want to store in the Directory for my application to use. These are not available for the user to edit however is available for the application to read from the Token.
The BuiltIn policies are able to retrieve the claims however, I have not had any success with retrieving these claims using Custom Policies.
Reading through Next Steps of the article “Creating and using custom attributes in a custom profile edit policy” the claims will need to be added to the RP and TechnicalProfile to read from Directory. I accordingly updated the RP and as well the TP's that read from Directory such as
<TechnicalProfile Id="AAD-UserReadUsingAlternativeSecurityId">
<TechnicalProfile Id="AAD-UserReadUsingObjectId">
<TechnicalProfile Id="SelfAsserted-LocalAccountSignin-Email">
<TechnicalProfile Id="AAD-UserReadUsingEmailAddress">
Unable to figure out what might be missing to retreive the 2 extension claims.
Assuming you are reading the custom claims in the user journeys and writing them via the Azure AD Graph API, then you must:
1: Add the custom claims as <ClaimType />s to the base policy.
<ClaimType Id="extension_UserAttribute1">
<DisplayName>User Attribute 1</DisplayName>
<DataType>string</DataType>
</ClaimType>
<ClaimType Id="extension_UserAttribute2">
<DisplayName>User Attribute 2</DisplayName>
<DataType>string</DataType>
</ClaimType>
2: Add the application and object identifiers for the extensions app to the "AAD-Common" technical profile which is required to read the custom claims from the Azure AD B2C directory.
<TechnicalProfile Id="AAD-Common">
<DisplayName>Azure Active Directory</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.AzureActiveDirectoryProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="ApplicationObjectId">Insert the object identifier for the b2c-extensions-app application here</Item>
<Item Key="ClientId">Insert the application identifier for the b2c-extensions-app application here</Item>
</Metadata>
<CryptographicKeys>
<Key Id="issuer_secret" StorageReferenceId="TokenSigningKeyContainer" />
</CryptographicKeys>
...
</TechnicalProfile>
Note: If you are wanting to read the custom claims in both built-in policies and custom policies, then you must use the application and object identifiers for the built-in b2c-extensions-app application rather than a custom extensions app as suggested by the Azure Active Directory B2C: Creating and using custom attributes in a custom profile edit policy tutorial.
3: Add the custom claims as <OutputClaim />s to the following technical profiles:
"AAD-UserReadUsingObjectId" for local account sign-in and profile editing
"AAD-UserReadUsingAlternativeSecurityId" for a social account sign-in and profile editing
"LocalAccountDiscoveryUsingEmailAddress" and "AAD-UserReadUsingEmailAddress" for a local account password reset
<OutputClaims>
...
<OutputClaim ClaimTypeReferenceId="extension_UserAttribute1" />
<OutputClaim ClaimTypeReferenceId="extension_UserAttribute2" />
</OutputClaims>
4: Issue the custom claims as <OutputClaim />s in any relying party policies.
Thanks #ChrisPadget. For anybody still struggling. Make sure that the UserJourney Step that reads data from AD is actually available in your User Journey. In my case, I had to add:
<OrchestrationStep Order="2" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="AADUserReadWithObjectId" TechnicalProfileReferenceId="AAD-UserReadUsingObjectId" />
</ClaimsExchanges>
</OrchestrationStep>

ad b2c allow user to change MFA setting

how would I allow the user to change their MFA setting like their phone number? I don't see any option for them to be able to do that easily.
Try this. B2C MFA reset was the reason I wrote it.
http://gordon.byers.me/azure/resetting-a-users-azure-ad-multi-factor-mfa-requirement/
As it's powershell you could put it inside an Azure function and call it via HTTP to allow the user to self serve.
Currently it is not possible to change an Azure AD B2C users' MFA settings.
There's already an ask for this ask in the Azure AD B2C forum that you should vote for:
https://feedback.azure.com/forums/169401-azure-active-directory/suggestions/15334329-change-security-info
The MFA phone number can be changed with custom policies. When you create a UserJourney that invokes a TechnicalProfile that does not take the strongAuthenticationPhoneNumber as InputClaim, IEF acts as if the user registers for MFA for the first time.
Of course you need to think about security measures, since it is a second factor that the user changes (e.g. ask the user to input some data, that can be validated, before allowing the user to change the phonenumber). Otherwise the use of MFA makes no sense.
Apparently, user's can't do that as stated by Saca 😢
Admins 👮 can do this on the user's behalf via the Azure Portal though:
Users -> All users -> Pick the user you're interested in -> Update Phone under Authentication contact info
Looks like this is now possible with custom policies.
There is a full example here: https://github.com/azure-ad-b2c/samples/tree/master/policies/edit-mfa-phone-number
In case the link breaks, the key part appears to be this:
<TechnicalProfiles>
<TechnicalProfile Id="PhoneFactor-EditAndVerify">
<DisplayName>PhoneFactor</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.PhoneFactorProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="ContentDefinitionReferenceId">api.phonefactor</Item>
<Item Key="ManualPhoneNumberEntryAllowed">true</Item>
</Metadata>
<CryptographicKeys>
<Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
</CryptographicKeys>
<InputClaimsTransformations>
<InputClaimsTransformation ReferenceId="CreateUserIdForMFA" />
</InputClaimsTransformations>
<InputClaims>
<InputClaim ClaimTypeReferenceId="userIdForMFA" PartnerClaimType="UserId" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="Verified.strongAuthenticationPhoneNumber" PartnerClaimType="Verified.OfficePhone" />
<OutputClaim ClaimTypeReferenceId="newPhoneNumberEntered" PartnerClaimType="newPhoneNumberEntered" />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>

Resources