Amplify-js: Receiving {"message":"Unauthorized"} on API call

Created on 14 May 2018  路  14Comments  路  Source: aws-amplify/amplify-js

Do you want to request a feature or report a bug?
Bug

What is the current behavior?
The initialization looks like:

Amplify.configure({
    Auth: {
        mandatorySignIn: true,
        region: config.cognito.REGION,
        userPoolId: config.cognito.USER_POOL_ID,
        identityPoolId: config.cognito.IDENTITY_POOL_ID,
        userPoolWebClientId: config.cognito.APP_CLIENT_ID
    },
    API: {
        endpoints: [
            {
                name: 'api_platform',
                endpoint: config.apiGateway.URL,
                region: config.apiGateway.REGION
            }
        ]
    }
});

I can successfully singin and get aws session with all the tokens. However, wen I run the following code

API.post('api_platform', '/ping');
I am getting {"message":"Unauthorized"} .

When I pass the Authorization header

const options = {
headers: {
Authorization: "--token-"
}
}

API.post('api_platform', '/ping, options');
This works fine.

Is this expected behavior? Shell I pass Authorization header explicitly or the API should do that automaticly?

API documentation feature-request

Most helpful comment

The documentation isn't clear about that.
If I understood well, Amplify use the Identity Pool token to sign the API requests. If you want to use this default behavior you need to use IAM Authorization in API Gateway and set the appropriate policy to the Identity Pool role.

To use the User Pool Authorizer you need to set the Authorization header with the User Pool token (like OP did).

/**
 * Return the Cognito User Pool token of the authenticated user.
 */
export function currentUserToken() {
  return Auth.currentAuthenticatedUser().then((user) => {
    return user.signInUserSession.idToken.jwtToken;
  });
}

I think Amplify should provide a way to choose between Identity Pool or User Pool for API request authentication.

All 14 comments

@luseengithub are you using a custom authorizer on your api gateway in this case?

No, the Authorizer is Cognito User Pool type. The Token Source: is set to "Authorization", Token Validation is empty, Type is "Cognito".
The web app example I use is: https://github.com/mavi888/web-client-cognito

I'm having the same problem.

I can sign-up, sign-in, forgot password etc. However, when I try to call my api gateway endpoint

https://codesandbox.io/s/ppz9q16647 (Log in with the credentials shown at the bottom)

The call to API.get() gets a status code 401 response.

The endpoint is configured as....

image

image

The documentation isn't clear about that.
If I understood well, Amplify use the Identity Pool token to sign the API requests. If you want to use this default behavior you need to use IAM Authorization in API Gateway and set the appropriate policy to the Identity Pool role.

To use the User Pool Authorizer you need to set the Authorization header with the User Pool token (like OP did).

/**
 * Return the Cognito User Pool token of the authenticated user.
 */
export function currentUserToken() {
  return Auth.currentAuthenticatedUser().then((user) => {
    return user.signInUserSession.idToken.jwtToken;
  });
}

I think Amplify should provide a way to choose between Identity Pool or User Pool for API request authentication.

I don't see a way to use IAM Authorization

screen shot 2018-05-15 at 15 16 02

screen shot 2018-05-15 at 15 21 25

It is only lambda and Cognito, I use congnito with user pool.

On each API Method Request settings.
image

Many thanks @Hugodby, then the Amplify should provide a way to configure it to use User Pool Authorizer. I can confirm that this kind of works, but after second request I am getting

{"message":"The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details."}

@luseengithub are you still using a custom Authorization header? With AWS_IAM configured on the API you should not need to add additional headers to the Amplify API.post() request.

@L226 I gave up with AWS_IAM configuration due to error:
{"message":"The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details."}

The final code that works for me is:

async testApiCall() {
        Auth.currentAuthenticatedUser().then((user) => {
            let jwtToken = user.signInUserSession.idToken.jwtToken;
            const options = {
                headers: {
                    Authorization: jwtToken
                }
            }
            API.post('....', '...', options).then(response => {
                this.setState({
                  xyz: response.message
                });
                return response;
            }).catch(error => {
                console.log(error.response)
            });

        });
    }

The documentation isn't clear about that.
If I understood well, Amplify use the Identity Pool token to sign the API requests. If you want to use this default behavior you need to use IAM Authorization in API Gateway and set the appropriate policy to the Identity Pool role.

To use the User Pool Authorizer you need to set the Authorization header with the User Pool token (like OP did).

/**
 * Return the Cognito User Pool token of the authenticated user.
 */
export function currentUserToken() {
  return Auth.currentAuthenticatedUser().then((user) => {
    return user.signInUserSession.idToken.jwtToken;
  });
}

I think Amplify should provide a way to choose between Identity Pool or User Pool for API request authentication.

You have saved my day, man. Thanks a lot!

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

This might help... you can configure it to use the IdToken JWT when defining your API endpoint

API: { endpoints: [ { name, endpoint, custom_header: async () => { // With Cognito User Pools use this: return { Authorization:Bearer ${(await Auth.currentSession()).getIdToken().getJwtToken()}} } } ] }

Yes the documentation is now pretty clear about this issue:

This should be closed

yes except I think it should be getIdToken(), I agree this could be close...I was just updating the comment so people might find this when looking for the problem

Was this page helpful?
0 / 5 - 0 ratings