Generating an access token from an ID token - Custom policy

asked 2023-01-09T13:40:15.307+00:00
roshin.thomas 1 Reputation point

I am using a id_token to pass information to AD B2C to bootstrap a user-journey from a link (similar to email sign in ) .

The url-builder creates a link

https://tenant.b2clogin.com/tenant.onmicrosoft.com/oauth2/v2.0/authorize?p=B2C_1A_SIGNIN_WITH_EMAIL&client_id=9----f8a-67890&redirect_uri=https://myapp.com/&nonce=9e4d18.....8302445a8069a&scope=openid&response_type=id_token&id_token_hint=eyJhb......  

I have the policy B2C_1A_SIGNIN_WITH_EMAIL that would read the user info from the email and issue a token .

I am expecting the user to be able to signin to the application with the token generated from the policy. But currently it reads the user, creates the id_token but since no token is generated application goes to login prompt.

The policy is below :

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>  
<TrustFrameworkPolicy  
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  xmlns:xsd="http://www.w3.org/2001/XMLSchema"  
  xmlns="http://schemas.microsoft.com/online/cpim/schemas/2013/06"  
  PolicySchemaVersion="0.3.0.0"  
  TenantId="tenant.onmicrosoft.com"  
  PolicyId="B2C_1A_signin_with_email"  
  PublicPolicyUri="http://tenant.onmicrosoft.com/B2C_1A_signin_with_email_TEST">  
  
  <BasePolicy>  
    <TenantId>tenant.onmicrosoft.com</TenantId>  
    <PolicyId>B2C_1A_TrustFrameworkExtensions</PolicyId>  
  </BasePolicy>  
  
   <BuildingBlocks>  
    <ClaimsSchema>  
      <!--Sample: Stores the error message for unsolicited request (a request without id_token_hint) and user not found-->  
      <ClaimType Id="errorMessage">  
     	  <DisplayName>Error</DisplayName>  
     	  <DataType>string</DataType>  
        <UserHelpText>Add help text here</UserHelpText>  
     	  <UserInputType>Paragraph</UserInputType>  
      </ClaimType>        
    </ClaimsSchema>  
  
    <ClaimsTransformations>  
      <!--Sample: Initiates the errorMessage claims type with the error message-->  
      <ClaimsTransformation Id="CreateUnsolicitedErrorMessage" TransformationMethod="CreateStringClaim">  
        <InputParameters>  
          <InputParameter Id="value" DataType="string" Value="You cannot sign-in without invitation. Please click the link in the email" />  
        </InputParameters>  
        <OutputClaims>  
          <OutputClaim ClaimTypeReferenceId="errorMessage" TransformationClaimType="createdClaim" />  
        </OutputClaims>  
      </ClaimsTransformation>  
  
      <!--Sample: Initiates the errorMessage claims type with the error message user not found-->  
      <ClaimsTransformation Id="CreateUserNotFoundErrorMessage" TransformationMethod="CreateStringClaim">  
        <InputParameters>  
          <InputParameter Id="value" DataType="string" Value="You aren't registered in the system! Please contact the Help Desk on 0800 xxx yyy and ask to be added to the system" />  
        </InputParameters>  
        <OutputClaims>  
          <OutputClaim ClaimTypeReferenceId="errorMessage" TransformationClaimType="createdClaim" />  
        </OutputClaims>  
      </ClaimsTransformation>  
    </ClaimsTransformations>  
  </BuildingBlocks>  
  
  
  <ClaimsProviders>  
    <!--Sample: This technical profile specifies how B2C should validate your token, and what claims you want B2C to extract from the token.   
      The METADATA value in the TechnicalProfile meta-data is required.   
      The “IdTokenAudience” and “issuer” arguments are optional (see later section)-->  
    <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="METADATA">https://tenant.b2clogin.com/tenant.onmicrosoft.com/v2.0/.well-known/openid-configuration?p=B2C_1A_SIGNIN_WITH_EMAIL</Item>  
            <Item Key="issuer">https://tokenbuilder.azurewebsites.net/</Item>  
          </Metadata>  
        <OutputClaims>  
          <!--Sample: Read the email cliam from the id_token_hint-->  
          <OutputClaim ClaimTypeReferenceId="email" />    
        </OutputClaims>  
        </TechnicalProfile>  
      </TechnicalProfiles>  
    </ClaimsProvider>  
  
    <ClaimsProvider>  
      <DisplayName>Self Asserted</DisplayName>  
      <TechnicalProfiles>  
        <!-- Demo: Show error message-->  
        <TechnicalProfile Id="SelfAsserted-Error">  
          <DisplayName>Unsolicited error message</DisplayName>  
          <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>  
          <Metadata>  
            <Item Key="ContentDefinitionReferenceId">api.selfasserted</Item>  
            <!-- Sample: Remove the continue button-->  
            <Item Key="setting.showContinueButton">false</Item>  
         </Metadata>  
          <InputClaims>  
            <InputClaim ClaimTypeReferenceId="errorMessage"/>  
          </InputClaims>  
          <OutputClaims>  
            <OutputClaim ClaimTypeReferenceId="errorMessage"/>  
          </OutputClaims>  
        </TechnicalProfile>  
  
        <!-- Demo: Show unsolicited error message-->  
        <TechnicalProfile Id="SelfAsserted-Unsolicited">  
          <InputClaimsTransformations>  
            <InputClaimsTransformation ReferenceId="CreateUnsolicitedErrorMessage" />  
          </InputClaimsTransformations>  
          <IncludeTechnicalProfile ReferenceId="SelfAsserted-Error" />  
        </TechnicalProfile>  
  
        <!-- Demo: Show user not found error message-->  
        <TechnicalProfile Id="SelfAsserted-UserNotFound">  
          <InputClaimsTransformations>  
            <InputClaimsTransformation ReferenceId="CreateUserNotFoundErrorMessage" />  
          </InputClaimsTransformations>  
          <IncludeTechnicalProfile ReferenceId="SelfAsserted-Error" />  
        </TechnicalProfile>  
      	  
	<TechnicalProfile Id="AAD-UserReadUsingEmailAddress-Hint">  
					<Metadata>  
						<Item Key="Operation">Read</Item>  
						<Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">false</Item>  
						<Item Key="UserMessageIfClaimsPrincipalDoesNotExist">An account could not be found for the provided user ID.</Item>  
					</Metadata>  
					<IncludeInSso>false</IncludeInSso>  
					<InputClaims>  
						<InputClaim ClaimTypeReferenceId="email" PartnerClaimType="signInNames.emailAddress" Required="true" />  
					</InputClaims>  
					<OutputClaims>  
						<!-- Required claims -->  
						<OutputClaim ClaimTypeReferenceId="objectId" />  
						<OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="localAccountAuthentication" />  
  
            <!-- Sample: Change the output email claims-->  
            <!--<OutputClaim ClaimTypeReferenceId="email" />-->  
            <OutputClaim ClaimTypeReferenceId="signInNames.emailAddress" />  
            <OutputClaim ClaimTypeReferenceId="extension_agency" />  
            <OutputClaim ClaimTypeReferenceId="extension_instanceURL" />  
            <OutputClaim ClaimTypeReferenceId="extension_role" />  
            <OutputClaim ClaimTypeReferenceId="extension_access" />  
            <OutputClaim ClaimTypeReferenceId="extension_tenantId" />  
            <OutputClaim ClaimTypeReferenceId="extension_userId" />  
            <OutputClaim ClaimTypeReferenceId="extension_tenantAbbreviation" />  
            <OutputClaim ClaimTypeReferenceId="extension_dateTimeFormat" />  
					</OutputClaims>  
					<!-- <OutputClaimsTransformations>  
						<OutputClaimsTransformation ReferenceId="AssertAccountEnabledIsTrue" />  
					</OutputClaimsTransformations> -->  
					<IncludeTechnicalProfile ReferenceId="AAD-Common" />  
				</TechnicalProfile>  
				</TechnicalProfiles>  
				  
	</ClaimsProvider>			  
  </ClaimsProviders>  
  
  <UserJourneys>  
    <UserJourney Id="SignInWithEmail">  
      <OrchestrationSteps>  
          
        <!--Sample: Read the input claims from the id_token_hint-->  
        <OrchestrationStep Order="1" Type="GetClaims" CpimIssuerTechnicalProfileReferenceId="IdTokenHint_ExtractClaims" />  
  
        <!-- Sample: Check if user tries to run the policy without invitation -->  
        <OrchestrationStep Order="2" Type="ClaimsExchange">  
         <Preconditions>  
            <Precondition Type="ClaimsExist" ExecuteActionsIf="true">  
              <Value>email</Value>  
              <Action>SkipThisOrchestrationStep</Action>  
            </Precondition>  
          </Preconditions>          
          <ClaimsExchanges>  
            <ClaimsExchange Id="SelfAsserted-Unsolicited" TechnicalProfileReferenceId="SelfAsserted-Unsolicited" />  
          </ClaimsExchanges>  
        </OrchestrationStep>  
  
        <!--Sample: Read the user properties from the directory-->  
        <OrchestrationStep Order="3" Type="ClaimsExchange">  
          <ClaimsExchanges>  
            <ClaimsExchange Id="AADUserReadUsingEmailAddress" TechnicalProfileReferenceId="AAD-UserReadUsingEmailAddress-Hint"/>  
          </ClaimsExchanges>  
        </OrchestrationStep>  
  
        <!-- Sample: Check whether the user not existed in the directory -->  
        <OrchestrationStep Order="4" Type="ClaimsExchange">  
          <Preconditions>  
            <Precondition Type="ClaimsExist" ExecuteActionsIf="true">  
              <Value>objectId</Value>  
              <Action>SkipThisOrchestrationStep</Action>  
            </Precondition>  
          </Preconditions>  
          <ClaimsExchanges>  
            <ClaimsExchange Id="SelfAssertedUserNotFound" TechnicalProfileReferenceId="SelfAsserted-UserNotFound" />  
          </ClaimsExchanges>  
        </OrchestrationStep>  
  
        <!--Sample: Issue an access token-->  
        <OrchestrationStep Order="5" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer"/>  
      
      </OrchestrationSteps>  
      <ClientDefinition ReferenceId="DefaultWeb"/>  
    </UserJourney>  
  </UserJourneys>  
  
  <RelyingParty>  
    <DefaultUserJourney ReferenceId="SignInWithEmail" />  
    
    <TechnicalProfile Id="PolicyProfile">  
      <DisplayName>PolicyProfile</DisplayName>  
      <Protocol Name="OpenIdConnect" />  
      <!--Sample: Set the input claims to be read from the id_token_hint-->  
      <InputClaims>  
        <InputClaim ClaimTypeReferenceId="email" />    
      </InputClaims>         
      <OutputClaims>  
        <OutputClaim ClaimTypeReferenceId="correlationId" DefaultValue="{Context:CorrelationId}" />  
        <OutputClaim ClaimTypeReferenceId="signInNames.emailAddress" />  
        <OutputClaim ClaimTypeReferenceId="extension_agency" />  
        <OutputClaim ClaimTypeReferenceId="extension_instanceURL" />  
        <OutputClaim ClaimTypeReferenceId="extension_role" />  
        <OutputClaim ClaimTypeReferenceId="extension_access" />  
        <OutputClaim ClaimTypeReferenceId="extension_tenantId" />  
        <OutputClaim ClaimTypeReferenceId="extension_userId" />  
        <OutputClaim ClaimTypeReferenceId="extension_tenantAbbreviation" />  
        <OutputClaim ClaimTypeReferenceId="extension_dateTimeFormat" />  
        <OutputClaim ClaimTypeReferenceId="tenantId" AlwaysUseDefaultValue="true" DefaultValue="{Policy:TenantObjectId}" />  
        <OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub" />  
      </OutputClaims>  
      <SubjectNamingInfo ClaimType="sub" />  
    </TechnicalProfile>  
  </RelyingParty>  
</TrustFrameworkPolicy>  

Thanks

Azure Active Directory
Azure Active Directory
An Azure enterprise identity service that provides single sign-on and multi-factor authentication.
12,546 questions
Azure Active Directory External Identities
Microsoft Graph SDK
Microsoft Graph SDK
A Microsoft software developer kit designed to simplify building high-quality, efficient, and resilient applications that access Microsoft Graph.
722 questions
{count} votes