Search code examples
angularamazon-web-servicesamazon-dynamodbamazon-cognitoaws-amplify

Missing Headers aws-amplify + angular 5.x


I'm building a project using angular 5.x and aws-amplify. I successfully managed to sign-up, confirm and sign-in my users via aws-cognito and now, I would like to retrieve user's jwt to add it at requests header to perform CRUD operations on my dynamoDb collection.

Unluckily, when I try to perform such operation on dynamo I get the following error:

{
    "message": "Authorization header requires 'Credential' parameter. Authorization header requires 'Signature' parameter. Authorization header requires 'SignedHeaders' parameter. Authorization header requires existence of either a 'X-Amz-Date' or a 'Date' header. Authorization=xxxxx"
}

I get user's token using the following Cognito.service:

import { Injectable } from '@angular/core';

/** rxjs **/
import { fromPromise } from 'rxjs/observable/fromPromise';
import { Observable } from 'rxjs/Observable';
import { of } from 'rxjs/observable/of';

/** 3rd party **/
import { Auth } from 'aws-amplify';

@Injectable()
export class CognitoService {

    getJwtToken(): Observable<any> {
        return this.getCurrentSession()
            .switchMap((token) => {
                return of(token.getIdToken().getJwtToken());
            })
    }

    private getCurrentSession(): Observable<any> {
        return fromPromise(Auth.currentSession());
    }

}

That get's called by:

this.cognitoService.getJwtToken()
    .subscribe((token: string) => {
        this.dynamoService.get(
            'testResource?id=someValue',
            {
                Authorization: token
            }
         )
    })

And where Dynamo.service is the following:

import { Injectable } from '@angular/core';

/** rxjs **/
import { fromPromise } from 'rxjs/observable/fromPromise';
import { Observable } from 'rxjs/Observable';

/** 3rd party **/
import { API } from 'aws-amplify';

/** App Environment **/
import { environment } from '../../../environments/environment';

@Injectable()
export class DynamoDBService {

    apiName = environment.amplify.API.endpoints[0].name;

    get(path: string, headers: any): Observable<any> {
        return fromPromise(
            API.get(
                this.apiName,
                path,
                {
                    headers: headers
                }
            )
        );
    }
}

My environment looks like:

export const environment = {
    production: false,
    amplify: {
        Auth: {
            region: 'eu-central-1',
            identityPoolId: 'eu-central-1:xxx',
            userPoolId: 'eu-central-1_xxx',
            userPoolWebClientId: 'xxxx'
        },
        API: {
            endpoints: [
                {
                    name: "someName,
                    endpoint: "xxxxx"
                }
            ]
        }
    }
};

And of course, at the startup of my application I'm configuring amplify like:

...
/** App Environment **/
import { environment } from '../../environments/environment';
...
Amplify.configure(environment.amplify);
...

On my api-gatway I enabled standard CORS, Authorization Required and no Token validation. I feel like I'm doing everything alright and I don't get what I'm doing wrong.

EDIT:

Authorization header gets properly set when using API.get(...) and passing it an header object like:

{
    Authorization: 'myToken'
}

More can be read at the following link aws.github.io/aws-amplify

Any Suggestion?


Solution

  • I managed to find out what was causing the problem. The error was caused not by headers nor by code but by the route called. In api-gateway, you can define resources and methods.

    I had an api-gateway structure like:

    /
    ----testResource/
        ----/{id}
            ---- GET
    

    And I was calling testResource?id=someValue and it was wrong. The right way to call the same resource by id is testResource/someValue.

    For some reason, the gateway, instead of give me a sensed error, gave me:

    {
        "message": "Authorization header requires 'Credential' parameter. Authorization header requires 'Signature' parameter. Authorization header requires 'SignedHeaders' parameter. Authorization header requires existence of either a 'X-Amz-Date' or a 'Date' header. Authorization=xxxxx"
    }
    

    And I tought it was caused by headers in general. For those struggling with the same problem:

    • Make sure you are calling the correct route
    • Make sure you are not using AWS_IAM Authorization but one coming from your cognito user pool
    • Make sure to get the current jwt and pass it to all your API requests like I've shown in the code above.