Getting access token for an api protected by B2C, using custom policies - azure-ad-b2c

I have an api that is protected using ADB2C authentication. I need to call this api via custom policies. I followed the documentation enter link description here and have added the two technical profiles as validation technical profile of a self asserted profile.
I am getting an access token returned by the below technical profile :
<TechnicalProfile Id="SecureREST-AccessToken">
<DisplayName></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://login.microsoftonline.com/{tenant id here}/oauth2/v2.0/token</Item>
<Item Key="AuthenticationType">Basic</Item>
<Item Key="SendClaimsIn">Form</Item>
</Metadata>
<CryptographicKeys>
<Key Id="BasicAuthenticationUsername" StorageReferenceId="B2C_1A_SecureRESTClientId" />
<Key Id="BasicAuthenticationPassword" StorageReferenceId="B2C_1A_SecureRESTClientSecret" />
</CryptographicKeys>
<InputClaims>
<InputClaim ClaimTypeReferenceId="grant_type" DefaultValue="client_credentials" />
<InputClaim ClaimTypeReferenceId="scope" DefaultValue="{app id uri for protected resource}/.default" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="bearerToken" PartnerClaimType="access_token" />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
And then making the rest api call using below profile :
<TechnicalProfile Id="UserMigrationViaLegacyIdp">
<DisplayName>REST API call to communicate with Legacy IdP</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://99a0a14a6402.ngrok.io/api/Identity/SignUpAsync
</Item>
<Item Key="AuthenticationType">Bearer</Item>
<Item Key="SendClaimsIn">Header</Item>
<Item Key="AllowInsecureAuthInProduction">false</Item>
<Item Key="UseClaimAsBearerToken">bearerToken</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="bearerToken"/>
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="phonePresent"/>
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
However, scopes are missing from the returned access token, hence token validation is failing on the api.
Is my call to get access token missing anything?

For the client credentials grant flow, the API permissions must be created as roles (see How to: Add app roles to your application and receive them in the token) and then granted admin consent (see Admin consent button).
As result, the bearer token contains the roles claim, rather than the scp claim.
The API application checks access using this roles claim (see Verify app roles in APIs called by daemon apps).

Related

Azure AD B2C Group Membership Custom policy

Our current b2c custom policy extension property (where we store permissions) is limited to 255 characters. Therefore, we hit the limit of permissions and we need to expose AAD group memberships through Azure B2C Custom policy.
How do we define the custom claim to expose group memberships of the current user in a token?
Either use this sample, which will present the groups in a better format in the token, but requires an API you have to host.
Or call the MS Graph directly from the Custom Policy as follows:
Get a token from AAD with user.read scope:
https://learn.microsoft.com/en-us/azure/active-directory-b2c/secure-rest-api#using-oauth2-bearer
<TechnicalProfile Id="SecureREST-AccessToken">
<DisplayName></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://login.microsoftonline.com/your-tenant-name.onmicrosoft.com/oauth2/v2.0/token</Item>
<Item Key="AuthenticationType">Basic</Item>
<Item Key="SendClaimsIn">Form</Item>
</Metadata>
<CryptographicKeys>
<Key Id="BasicAuthenticationUsername" StorageReferenceId="B2C_1A_SecureRESTClientId" />
<Key Id="BasicAuthenticationPassword" StorageReferenceId="B2C_1A_SecureRESTClientSecret" />
</CryptographicKeys>
<InputClaims>
<InputClaim ClaimTypeReferenceId="grant_type" DefaultValue="client_credentials" />
<InputClaim ClaimTypeReferenceId="scope" DefaultValue="user.read" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="bearerToken" PartnerClaimType="access_token" />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
Then make a call to MS Graph:
https://learn.microsoft.com/en-us/azure/active-directory-b2c/custom-policy-rest-api-claims-exchange
https://learn.microsoft.com/en-us/azure/active-directory-b2c/restful-technical-profile#metadata
<TechnicalProfile Id="REST-GetGroupsFromMSGraph">
<DisplayName>revoke my refresh token</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://graph.microsoft.com/beta/users/{objectId}/memberOf?$select=id"</Item>
<Item Key="AuthenticationType">Bearer</Item>
<Item Key="UseClaimAsBearerToken">bearerToken</Item>
<Item Key="SendClaimsIn">Url</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="bearerToken"/>
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="groupsPayload" PartnerClaimType="value" />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
The claim groupsPayload will contain the value:
[
{
"#odata.type": "#microsoft.graph.group",
"id": "34af9ff3-ebfc-4bfb-9417-a86f5f499845"
},
{
"#odata.type": "#microsoft.graph.group",
"id": "7485108c-7715-49af-a296-ee1f7295958d"
}
]
And the token will have the claim, including the escape characters, as follows:
"groupsPayload": [ "{ \"#odata.type\": \"#microsoft.graph.group\"", " \"id\": \"e06f5fd8-aee1-4e14-a692-dcde772c1465\" }" ],

Sending a Claim in a validation Technical Profile

I am dong a validation check to our database during our password forget policy.
During this process, it calls and API and needs a bearer token. I already have a technical profile to do this we use in another step.
So in this process, It keeps failing to look for the bearer token. It is saying the only token available in the email.
I need to do a step in between to get the bearer token, but I'm not sure how to do that since I'm doing a validation...
Here is what I have. After I type in the email to validate it.
<ClaimsProvider>
<DisplayName>REST API to Check Member</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="LocalAccountDiscoveryUsingEmailAddress">
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="REST-CheckMemberAccountHolder" ContinueOnError="false"/>
</ValidationTechnicalProfiles>
</TechnicalProfile>
<TechnicalProfile Id="REST-CheckMemberAccountHolder">
<DisplayName>Rest API call to Check Member status</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="ServiceUrl">{API}</Item>
<Item Key="SendClaimsIn">Body</Item>
<Item Key="AuthenticationType">Bearer</Item>
<Item Key="UseClaimAsBearerToken">bearerToken</Item>
<Item Key="AllowInsecureAuthInProduction">false</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" PartnerClaimType="emailaddress"/>
<InputClaim ClaimTypeReferenceId="bearerToken" />
</InputClaims>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
I need it to call
<TechnicalProfile Id="REST-AcquireAccessToken">
To get the bearertoken for the REST call in the validation.
I cant seem to figure out how to do it.
As per this, I assume you had something like:
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="bearerToken" PartnerClaimType="access_token" />
</OutputClaims>
when you acquired the token?
Is this all part of the same user journey?
What do you mean by "saying the only token available in the email"?

Calling secure REST API from Azure B2C custom policy to embed claims

I am trying to consume a Azure B2C secured API as part of the user journey by creating custom policies. I have created a claims provider to procure a bearer token as below
<ClaimsProvider>
<DisplayName>REST APIs</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="SecureREST-AccessToken">
<DisplayName></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://***.b2clogin.com/***.onmicrosoft.com/B2C_1A_SignUpOrSignIn/oauth2/v2.0/authorize</Item>
<Item Key="AuthenticationType">Basic</Item>
<Item Key="SendClaimsIn">Form</Item>
</Metadata>
<CryptographicKeys>
<Key Id="BasicAuthenticationUsername" StorageReferenceId="B2C_1A_SecureRESTClientId" />
<Key Id="BasicAuthenticationPassword" StorageReferenceId="B2C_1A_SecureRESTClientSecret" />
</CryptographicKeys>
<InputClaims>
<InputClaim ClaimTypeReferenceId="grant_type" DefaultValue="client_credentials" />
<InputClaim ClaimTypeReferenceId="scope" DefaultValue="https://***.onmicrosoft.com/profileapi/profileapi-scope" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="bearerToken" PartnerClaimType="access_token" />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
And another claims provider to call my secure REST API as below
<ClaimsProvider>
<DisplayName>REST APIs</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="AzureFunctions-GetRole">
<DisplayName>Get Roles </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://***.azurewebsites.net/api/UserProfiles/CheckAdminUser</Item>
<Item Key="AuthenticationType">Bearer</Item>
<Item Key="SendClaimsIn">Body</Item>
<Item Key="AllowInsecureAuthInProduction">false</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" PartnerClaimType="email" />
<InputClaim ClaimTypeReferenceId="signInNames.emailAddress" PartnerClaimType="email" />
<InputClaim ClaimTypeReferenceId="bearerToken"/>
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="IsAdminUser" PartnerClaimType="IsAdminUser" />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
How do I tie these two up? Should these be two steps in the user journey?
AAD B2C endpoint doesn’t support client credentials flow. Your initial call to get a token should model AAD client credentials flow:
https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow
You would call these technical profiles from the user journey if they return no possibility of an error to the user. Or otherwise as validation technical profiles referenced from a self asserted technical profile.

Azure AD B2C - call rest api with parameter in header

I'm trying to call a rest api in a technical profile which requires parameters to be passed to it through the header, but I'm unable to do so. I have:
<TechnicalProfile Id="techProfile1">
<DisplayName>Technical Profile 1</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://xxxxxxx.azurewebsites.net/api/controller/action</Item>
<Item Key="AuthenticationType">Basic</Item>
<Item Key="SendClaimsIn">Header</Item>
<Item Key="AllowInsecureAuthInProduction">true</Item>
</Metadata>
<CryptographicKeys>
<Key Id="BasicAuthenticationUsername" StorageReferenceId="xxxxxx" />
<Key Id="BasicAuthenticationPassword" StorageReferenceId="xxxxxx" />
</CryptographicKeys>
<InputClaims>
<InputClaim ClaimTypeReferenceId="claimName1" PartnerClaimType="paramName1" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="output1"/>
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
Where the value I'm trying to pass in is the ClaimName1 claim, and the parameter name is paramName1. Am I correct in using the InputClaim section for this?
The response back that I get is: AADB2C90075: The claims exchange 'techProfile1' specified in step '3' returned HTTP error response with Code 'InternalServerError' and Reason 'Internal Server Error'.
Am I right in assuming that the parameter is not being passed to the api? When I change the ServiceUrl to: https://xxxxxxx.azurewebsites.net/api/controller/action?paramName1=yyyy (where yyyy is the value held in the claimName1 claim), then it works as expected.
<Item Key="SendClaimsIn">Header</Item>
instead of the above one try the below one
<Item Key="SendClaimsIn">QueryString</Item>
This will add the input claim as query param.

How to set SendClaimsIn for azure ad b2c REST call

I have created an AAD B2C custom policy which makes a call to call our REST API when a new user signs up by creating a custom Azure AD B2C custom policy.But i have to set two values to REST API. Ocp-Apim-Subscription-Key in header and email id in body.but i have to set SendClaimsIn only as either header or body.
so i added SendClaimsIn as header.But i cdont know how to set both values as inputclaim.My code is
<ClaimsProvider>
<DisplayName>Signup REST APIs</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="REST-ValidateProfile">
<DisplayName>Check loyaltyId 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://myapicall.io/api/</Item>
<Item Key="SendClaimsIn">Header</Item>
<Item Key="AuthenticationType">Bearer</Item>
<Item Key="AllowInsecureAuthInProduction">false</Item>
</Metadata>
<CryptographicKeys>
<Key Id="BearerAuthenticationToken" StorageReferenceId="B2C_1A_RestApiBearerToken" />
</CryptographicKeys>
<InputClaims>
<!-- Claims sent to your REST API -->
<InputClaim ClaimTypeReferenceId="email" />
<InputClaim ClaimTypeReferenceId="grant_type" "DefaultValue"="Ocp-Apim-Subscription-Key"/>
</InputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
its shows validation error while uploading
makes a reference to ClaimType with id "Ocp-Apim-Subscription-Key" but
neither the policy nor any of its base policies contain such an
element
i want to set header as Ocp-Apim-Subscription-Key as "12345"
Add the following inside of the <ClaimsSchema> tag near the top of the file:
<ClaimType Id="Ocp-Apim-Subscription-Key">
<DisplayName>OCP APIM Subscription Key</DisplayName>
<DataType>string</DataType>
</ClaimType>
Change the values inside of the <InputClaims> in your REST-ValidateProfile technical profile to the following:
<InputClaims>
<!-- Claims sent to your REST API -->
<InputClaim ClaimTypeReferenceId="email" />
<InputClaim ClaimTypeReferenceId="Ocp-Apim-Subscription-Key" DefaultValue="12345" />
</InputClaims>
You don't need a grant_type input claim for a static OAuth2 bearer (see here).

Resources