AndreaM16
AndreaM16

Reputation: 3975

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?

Upvotes: 3

Views: 2274

Answers (2)

AndreaM16
AndreaM16

Reputation: 3975

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.

Upvotes: 0

user4676340
user4676340

Reputation:

I don't get your issue so I will rely on the title of your question.

If a header is missing, it's because Angular simplifies the headers before giving your the response.

If you want to get the header and put it in your request, you will have to expose it.

This is done with the Access Control Expose Headers header.

By default, Angular only handle a couple of headers and erase the other ones. You probably didn't get your token because it was in a non exposed header.

Upvotes: 1

Related Questions