Azure B2C With Verifiable Credentials - QR Code Not Generated in SelfAsserted.html

130 Views Asked by At

Following the Verifiable Credentials B2C Sample here https://github.com/Azure-Samples/active-directory-verifiable-credentials/blob/main/B2C/README.md

I have updated the selfasserted.html file with the path (in Azure Storage) of qrcode.min.js. But none of the following B2C policies render the QRCode when the user journey is run. This means a verifiable credential can neither be issued nor verified.

B2C_1A_SIGNINMFA_VC B2C_1A_SIGNIN_VC B2C_1A_SIGNUP_SIGNIN_VC B2C_1A_VC_SUSIQ B2C_1A_VC_SUSI_ISSUEVC However, there are no issues loading the QR code when hitting the app endpoint directly via localhost or using ngrok. Only seems to happen when going via Azure B2C.

UPDATE 1

After updating the sample to use the claim resolver everywhere VCStateId is used as an input claim as well as adding the metadata key I notice the following

  1. The request url now has an id parameter, except that it is exactly "{Context:CorrelationId}" and not resolving to the actual correlation id. I see the following under headers in dev tools (sanitized) "Request URL: https://xxxx-xxxx.ngrok-free.app/api/verifier/presentation-response-status?id={Context:CorrelationId}"

  2. I see the script for the initial page you see when using ngrok, that warns you about proceeding only of you trust the site

UPDATE 2

I now consistently see an 'id' getting added to the request url. I was missing one more spot to add the metadata key IncludeClaimResolvingInClaimsHandling => true. But still, no qrcode.

UPDATE 3

I went a step further and made a bit of progress. I added an header in ngrok to skip the warning page and was able to get rid of the error: "Uncaught (in promise) SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON". Now here is what I see in console:

Generating QR code encoded with openid://vc/?request_uri=https ://xxx.ngrok-free. app/api/verifier/presentation-request-proxy?id=xxxx-xxxx-xxxx-xxxx-xxxx

QRCode is not defined

Also in the B2C sign in page, instead of the QR code I see the screenshot

enter image description here

UPDATE 4

enter image description here

2

There are 2 best solutions below

0
On

It appears like the sample has been updated on the sign-up/sign-in quick flow but not the others.

On the SignupOrSigninVCQ policy, the technical profile that is executed sets the VCStateId to the Correlation ID of the journey.

        <!-- TP that gets executed after QR code is scanned on signin page -->
        <TechnicalProfile Id="SelfAsserted-VCSigninQuick">
          <DisplayName>Verifiable Credentials</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.vc</Item>
            <Item Key="setting.showCancelButton">false</Item>
            <Item Key="IncludeClaimResolvingInClaimsHandling">true</Item>
          </Metadata>
          <IncludeInSso>false</IncludeInSso>
          <InputClaims>
            <InputClaim ClaimTypeReferenceId="VCStateId" DefaultValue="{Context:CorrelationId}" AlwaysUseDefaultValue="true" />
            <!-- if you change this one, you need to change the all ServiceUrl in this file -->
            <!-- CHANGE THE BELOW LINE -->
            <InputClaim ClaimTypeReferenceId="VCServiceUrl" AlwaysUseDefaultValue="true" DefaultValue="https://df4a-158-174-131-118.ngrok.io/api/verifier" />
          </InputClaims>
          <DisplayClaims>
            <DisplayClaim ClaimTypeReferenceId="VCStateId" />
            <DisplayClaim ClaimTypeReferenceId="VCServiceUrl" />
          </DisplayClaims>
          <OutputClaims>
            <OutputClaim ClaimTypeReferenceId="VCStateId" />
            <OutputClaim ClaimTypeReferenceId="displayName" />
            <OutputClaim ClaimTypeReferenceId="givenName" />
            <OutputClaim ClaimTypeReferenceId="surName" />
            <OutputClaim ClaimTypeReferenceId="VCCredentialType" />
            <OutputClaim ClaimTypeReferenceId="VCCredentialType" />
            <OutputClaim ClaimTypeReferenceId="VCSubject" />
            <OutputClaim ClaimTypeReferenceId="VCIssuer" />
            <OutputClaim ClaimTypeReferenceId="VCKey" />
            <OutputClaim ClaimTypeReferenceId="objectId" />
            <OutputClaim ClaimTypeReferenceId="email" />
            <OutputClaim ClaimTypeReferenceId="identityProvider" DefaultValue="DID" />
            <OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="localAccountAuthentication" />
          </OutputClaims>
          <ValidationTechnicalProfiles>
            <ValidationTechnicalProfile ReferenceId="REST-VC-GetAuthResult" />
            <!-- make sure the user exists in the directory -->
            <ValidationTechnicalProfile ReferenceId="AAD-UserReadUsingObjectId" />
          </ValidationTechnicalProfiles>
        </TechnicalProfile>

Compare this to the SigninVC policies technical profile, you can see that the input claim VCStateId is never given a default value.

        <!-- Signing in with a VC when VC references a B2C account -->
        <TechnicalProfile Id="SelfAsserted-VCSignin">
          <DisplayName>Verifiable Credentials</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.vc</Item>
            <Item Key="setting.showCancelButton">false</Item>
          </Metadata>
          <IncludeInSso>false</IncludeInSso>
          <InputClaims>
            <InputClaim ClaimTypeReferenceId="VCStateId" />
            <!-- if you change this one, you need to change the all ServiceUrl in this file -->
            <!-- CHANGE THE BELOW LINE -->
            <InputClaim ClaimTypeReferenceId="VCServiceUrl" AlwaysUseDefaultValue="true" DefaultValue="https://df4a-158-174-131-118.ngrok.io/api/verifier"/>
          </InputClaims>
          <DisplayClaims>
            <DisplayClaim ClaimTypeReferenceId="VCStateId" />
            <DisplayClaim ClaimTypeReferenceId="VCServiceUrl" />
          </DisplayClaims>
          <OutputClaims>
            <OutputClaim ClaimTypeReferenceId="displayName" />
            <OutputClaim ClaimTypeReferenceId="givenName" />
            <OutputClaim ClaimTypeReferenceId="surName" />
            <OutputClaim ClaimTypeReferenceId="vcCredentialType" />
            <OutputClaim ClaimTypeReferenceId="vcSubject" />
            <OutputClaim ClaimTypeReferenceId="vcIssuer" />
            <OutputClaim ClaimTypeReferenceId="vcKey" />
            <OutputClaim ClaimTypeReferenceId="objectId" />
            <OutputClaim ClaimTypeReferenceId="email" />
            <OutputClaim ClaimTypeReferenceId="identityProvider" DefaultValue="DID" />
            <OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="localAccountAuthentication" />
          </OutputClaims>
          <ValidationTechnicalProfiles>
            <ValidationTechnicalProfile ReferenceId="REST-VC-GetAuthResult" />
            <!-- make sure the user exists in the directory -->
            <ValidationTechnicalProfile ReferenceId="AAD-UserReadUsingObjectId" />
          </ValidationTechnicalProfiles>
        </TechnicalProfile>

A few changes to make this work are:

Any input claims for VCStateId should be updated to have a default value:

<!-- before -->
<InputClaim ClaimTypeReferenceId="VCStateId" />

<!-- after -->
<InputClaim ClaimTypeReferenceId="VCStateId" DefaultValue="{Context:CorrelationId}" AlwaysUseDefaultValue="true" />

You will also need to add the Claims Resolver metadata to each of the technical profiles you change:

<Metadata>
  ...
  <Item Key="IncludeClaimResolvingInClaimsHandling">true</Item>
</Metadata>

The presentation request should now include the id in the query string.


Please do not forget to "Accept the answer” and “up-vote” wherever the information provided helps you, this can be beneficial to other community members.

0
On

Closing this. The sample was just refreshed (less than 48 hours ago) with several changes. But for anyone who cares, I was finally able to resolve this issue by modifying the chaining of the promises related to the fetch in function callPresentationResponse(id). After the catch block .then(response => response.text()) is trying to access the response variable. But at this point, it is not the response from fetch but the undefined value or error caught by the previous catch block. This leaves response undefined and by extension respMsg. Did the same for the same for the getQRCode function. Now, I am able to scan the QR code during issuance and verification. There were other issues after that but like I said the repo has been refreshed and there have been significant changes. But if not that, I'd be opening another question for it anyways. Thanks to @bolt-io for his contribution.