question

JasonOlsan-4678 avatar image
0 Votes"
JasonOlsan-4678 asked JasonOlsan-4678 answered

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://<function-name>.azurewebsites.net/.auth/login/aad/callback is in the Redirect URIs for the "Web" platform confict of the app registration.

  • <function-name> 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.





azure-functionsazure-ad-authenticationazure-ad-myapps
· 2
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

@JasonOlsan-4678 Can parse your access token and share a screenshot?

0 Votes 0 ·

That one question actually solved the problem. I attempted to grab a new access token and parse it to send, when I noticed that the token wasn't validating.

After a bit of testing, I realized that the token I had gotten to validate was the id_token. On a hunch, I sent the id_token as the access token and then I was authenticated immediately with a 200 + authenticationToken. :)

0 Votes 0 ·

1 Answer

JasonOlsan-4678 avatar image
0 Votes"
JasonOlsan-4678 answered

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.

5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.