Stanley
Stanley

Reputation: 5491

How to implement developer-authenticated identities in cognito in JavaScript SDK v3 - getting 403 InvalidSignatureException response in Client

I am implementing developer-authenticated identities in an Angular app that uses the "Enhanced Workflow" from the official documentation. I followed the official guide for implementing this and am using GetOpenIdTokenForDeveloperIdentityRequest() on the server-side to request a token for my end-user and I'm returning it to my Angular Web Client so that the Web Client can fetch its temporary credentials from Cognito. Unfortunately the guide isn't updated to illustrate how to achieve this in SDK version 3 (and most online questions and solutions also refer to older versions of the SDK) but I'm managing to get a set of credentials back from Cognito. (In the code below I do a console.log that writes out the credentials I receive. Perfect up to that point.)

The problem is that I can't figure out how to properly construct a Service Client to now use these credentials. Below is my attempt. I am constructing a Service Client (in this case LocationClient) and sending through a command on this client (GetDevicePositionCommand). This, however, throws an error and if I inspect the network call that was made I see that the network response when making this call was a 403 error with X-Amzn-Errortype "InvalidSignatureException". The error message is:

"The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method." 

The Canonical String for this request should have been....

Am I using the temporary credentials returned from Cognito correctly to construct the Service Client (LocationClient)? Any ideas on how to resolve this problem? (I have already consulted this troubleshooting guide but I haven't found anything helpful there.) Below is my client-side code from my Angular Web App.

const cognitoIdentity = new CognitoIdentityClient({
    credentials : fromCognitoIdentity({
        identityId: 'IDENTITY_ID_RETURNED_FROM_MY_DEVELOPER_PROVIDER', //IdentityId returned from calling GetOpenIdTokenForDeveloperIdentityRequest() on my server-side
        logins: {
        'cognito-identity.amazonaws.com': 'TOKEN_RETURNED_FROM_MY_DEVELOPER_PROVIDER' //Token returned from calling GetOpenIdTokenForDeveloperIdentityRequest() on my server-side
        },
        clientConfig: {region: "eu-west-1"},
    }),
});

const credentials = await cognitoIdentity.config.credentials()
console.log(credentials) //There's output! So this part works.
  // {
  //    identityId: 'eu-west-1:XXXX',
  //    accessKeyId: 'ALA...',
  //    secretAccessKey: '/XXXXxxxXXXXxxXXXxXXXXX',
  //    sessionToken: 'IQoJb3JpZ2luX2VjEJj//////////...', // sessionToken cut for brevity
  //    expiration: 2024-02-13T08:58:10.000Z
  //  }

const trackingClient = new LocationClient({
    region: 'eu-west-1',
    credentials: credentials,
});

const input = {
    TrackerName: "xxxxx",
    DeviceId: "xxxxxxx",
  };
const posCommand = new GetDevicePositionCommand(input);

try
{
  const response = await trackingClient.send(posCommand); //This line throws an error
}
catch(error){
    console.log('error') //Error caught
};

Upvotes: 0

Views: 120

Answers (1)

Stanley
Stanley

Reputation: 5491

I managed to resolve this.

While setting up a small code snippet to illustrate the problem to someone I found that when I create a "vanilla" NodeJS or "vanilla" Angular app, everything works perfectly with my code and the AWS libraries exactly as they are.

Digging into the framework that our particular app is built on (ASP.NET Zero) I found that it overrides the standard JavaScript Date methods for .toISOString() and .toString(). The AWS SDK obviously does not expect such a customised format, but the result is that the date format on which it calculates the signature does not match with what AWS expects. (SignatureV4 expects the x-amz-date header in an ISO 8601 "basic" format whereas the overriding method in the framework we're using overrides the date format to be the ISO 8601 "extended" format.) The x-amz-date header MUST be of the form YYYYMMDDTHHMMSSZ (for example, 20220830T123600Z) but the overriding code caused all date conversions to be like 20240226T093306.631+0000.

Both the AWS SDK libraries as well as how we use it in our code is 100% correct. The issue was because a (standard) method on which the SDK relies has been overridden by the ASP.NET Zero framework (on which our app is built).

I solved the problem by removing the override customization so that the date functions can function like normal! (Because overriding such a standard function will obviously impact on other libraries that one might use in their app as well!)

Upvotes: 0

Related Questions