We were having the same issue with user info-endpoint. It turned out that the issuer Item under TechnicalProfile Id="UserInfoAuthorization" was not matching with the iss claim in the token due to a case mismatch
We figured it out after looking into ApplicationInsights Traces for Azure B2C. The only difference was in the issuer URL where the case was different. In token, the iss claim is always in lowercase. So this could be one reason why we could get a 401 error even when the token is valid.
Another reason could be a mismatch in Audience (Item Key="audience") value. Since its optional, we haven't restricted it to a particular clientId. If it is set when we can use user info endpoint only for those specific endpoints.
Example:
The technical profile here has an issuer in mixed case.
<TechnicalProfile Id="UserInfoAuthorization">
<DisplayName>UserInfo authorization</DisplayName>
<Protocol Name="None" />
<InputTokenFormat>JWT</InputTokenFormat>
<Metadata>
<!-- Update the Issuer and Audience below -->
<!-- Audience is optional, Issuer is required-->
<Item Key="issuer">https://SampleB2CTenant.b2clogin.com/11111111-1111-1111-1111-111111111111/v2.0/</Item>
<!-- <Item Key="audience">[ "22222222-2222-2222-2222-222222222222", "33333333-3333-3333-3333-333333333333" ]</Item> -->
<Item Key="client_assertion_type">urn:ietf:params:oauth:client-assertion-type:jwt-bearer</Item>
</Metadata>
<CryptographicKeys>
<Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
</CryptographicKeys>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub"/>
<OutputClaim ClaimTypeReferenceId="signInNames.emailAddress" PartnerClaimType="email"/>
<!-- Optional claims to read from the access token. -->
<!-- <OutputClaim ClaimTypeReferenceId="givenName" PartnerClaimType="given_name"/>
<OutputClaim ClaimTypeReferenceId="surname" PartnerClaimType="family_name"/>
<OutputClaim ClaimTypeReferenceId="displayName" PartnerClaimType="name"/> -->
</OutputClaims>
</TechnicalProfile>
JWT Token
In the token the iss claim has the value as lowercase always.
{
"ver": "1.0",
"iss": "https://sampleb2ctenant.b2clogin.com/11111111-1111-1111-1111-111111111111/v2.0/",
"sub": "baee575c-0936-4afa-9fb4-92198c6ab2b2",
"aud": "4dc1e1f8-e42d-46df-a73f-ddca5616658d",
"exp": 1688725206,
"iat": 1688721606,
"auth_time": 1688721596,
"email": "******@email.com",
"name": "test user",
"given_name": "test",
"family_name": "user",
"tid": "11111111-1111-1111-1111-111111111111"
"buildId": "20230621.1_Release-191",
"tfp": "B2C_1A_HRDSignIn_v2",
"nbf": 1688721606
}
Hence, the token validation fails due to issuer mismatch
"Exception": {
"Kind": "Handled",
"HResult": "80131500",
"Message": "IDX10205: Issuer validation failed. Issuer: 'https://sampleb2ctenant.b2clogin.com/11111111-1111-1111-1111-111111111111/v2.0/'. Did not match: validationParameters.ValidIssuer: 'null' or validationParameters.ValidIssuers: 'https://SampleB2CTenant.b2clogin.com/11111111-1111-1111-1111-111111111111/v2.0/' or validationParameters.ConfigurationManager.CurrentConfiguration.Issuer: 'Null'. For more details, see https://aka.ms/IdentityModel/issuer-validation. ",
"Data": {}
}