'Attempting to authenticate Azure AD in Azure Function returns 401, "IDX10516: Signature validation failed."

I'm attempting to build an SSO prototype using an Azure Function web API and a react-based SPA connected to Azure AD. The goal is to use "Easy Auth" (aka Azure Function integrated authentication) for my authentication on the Azure Function (https://docs.microsoft.com/en-us/azure/app-service/overview-authentication-authorization) with Microsoft Identity Platform as my provider.

First off, I created a React SPA using the following tutorial: https://docs.microsoft.com/en-us/azure/active-directory/develop/tutorial-v2-react This seemed to authenticate just fine and I was able to consume the sample Graph API call.

However, once I attempted to then add the Azure Function to the mix, I ran into a problem. I used the POST call for "Client-directed sign-in" (https://docs.microsoft.com/en-us/azure/app-service/configure-authentication-customize-sign-in-out#client-directed-sign-in) to submit my access token, but it failed.

I created a new button in the page that calls the following function:

export async function callExampleService(idToken, accessToken) {
    const headers = new Headers();

    headers.append("Content-Type", "application/json");

    const options = {
        method: 'POST',
        headers: headers,
        body: JSON.stringify({ access_token: `${accessToken}` })
    };

    return fetch(exampleDataServiceConfig.exampleDataServiceBase.concat(exampleDataServiceConfig.postAuth), options)
        .then(response => response.json())
        .catch(error => console.log(error));
}

Judging from the Fiddler response, it looks as though the call matched the expected POST:

POST https://<function-name>/.auth/login/aad HTTP/1.1
Host: func-dotnetssoprototype-dev-westus2-001.azurewebsites.net
Connection: keep-alive
Content-Length: 1942
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="101", "Microsoft Edge";v="101"
sec-ch-ua-mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.41 Safari/537.36 Edg/101.0.1210.32
sec-ch-ua-platform: "Windows"
content-type: application/json
Accept: */*
Origin: http://localhost:3000
Sec-Fetch-Site: cross-site
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://localhost:3000/
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9

{"access_token":"<valid JWT token from client app auth, tested on jwt.io>"}

But returned the following error:

HTTP/1.1 401 Unauthorized
Content-Type: application/json
Vary: Origin
Server: Kestrel
WWW-Authenticate: Bearer realm="<function-name>.azurewebsites.net"
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: http://localhost:3000
Request-Context: appId=cid-v1:5c2eaf04-be8a-4b4d-baca-bd047b53cfb0
Strict-Transport-Security: max-age=31536000; includeSubDomains
Date: Thu, 05 May 2022 00:03:00 GMT
Content-Length: 716

{"code":401,"message":"IDX10516: Signature validation failed. Unable to match key: \nkid: '[PII of type 'System.String' is hidden. For more details, see https:\/\/aka.ms\/IdentityModel\/PII.]'. \nNumber of keys in TokenValidationParameters: '0'. \nNumber of keys in Configuration: '6'. \nExceptions caught:\n '[PII of type 'System.Text.StringBuilder' is hidden. For more details, see https:\/\/aka.ms\/IdentityModel\/PII.]'. \ntoken: '[PII of type 'System.IdentityModel.Tokens.Jwt.JwtSecurityToken' is hidden. For more details, see https:\/\/aka.ms\/IdentityModel\/PII.]'. Valid Lifetime: 'True'. Valid Issuer: '[PII of type 'System.Boolean' is hidden. For more details, see https:\/\/aka.ms\/IdentityModel\/PII.]'"}

It should be noted that both the react client app and the azure function are both using the same Registered App credentials for authentication. I haven't found any details about whether that is the correct practice or that both need separate Registered Apps.

Here are a few related pieces of info to narrow down the problem:

  • http://localhost:3000 is in the CORS for the function.
  • http://localhost:3000 is in the Redirect URIs for the "Single Page Application" platform config of the app registration.
  • https://.azurewebsites.net/.auth/login/aad/callback is in the Redirect URIs for the "Web" platform confict of the app registration.
  • is just the placeholder for the actual name of the azure function, in case you think I actually used that for the name in the variables. ;)
  • Both "Access tokens" and "ID tokens" are not checked in the "Implicit grant and hybrid flows" since we're using msal.js 2.0

Since the auth is done in a black box container, I'm not sure what steps I can take to get specifics on this issue. I have the following questions:

  1. Is there a way to "un-hide" the PII on the function? I saw the link in the error and it references adding "IdentityModelEventSource.ShowPII = true;" to the code, but this source isn't in the Azure packages and I think it's an error from the auth container.
  2. What could be causing this failed signature validation/how I can I fix this issue? I looked at the "kid" in the JWT and at the well known config. It exists in the returned manifest.

Any help would be appreciated.



Solution 1:[1]

The issue was pretty simple after I narrowed it down.

The problem was that I was using the accessToken to authenticate instead of the idToken. The fact that the json property was called "access_token" was a misnomer.

The code change is:

body: JSON.stringify({ access_token: `${idToken}` })

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Jason Olsan