Amplify-js: API 401 "No Access-Control-Allow-Origin header" response

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

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

Bug

What is the current behavior?

Hi, thanks for the library! I'm attempting to use the API component in my react app to connect to an API gateway lambda API service using a custom domain name:

async getData() {
  let apiName = 'media';
  let path = '/';
  let myInit = {
    response: true
  };
  return await API.get(apiName, path, myInit);
}

componentDidMount() {
  this.getData().then(response => {
    this.setState({
      data: response.json,
     });
  }).catch(error => {
    console.log(error)
  });
}

this results in:

Failed to load https://$MY_DOMAIN: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. The response had HTTP status code 401.
Error: Network Error
    at createError (createError.js:16)
    at XMLHttpRequest.handleError (xhr.js:87)

CORS is enabled on the API. I tried both setting

cors: true

in zappa settings, as well as using the AWS console to manually set CORS for the API.
As far as I can tell, Auth is configured correctly as the rest of the auth UI works fine.


Amplify.configure({
    Auth: {
        // REQUIRED - Amazon Cognito Identity Pool ID
            identityPoolId: process.env.REACT_APP_identityPoolId,
        // REQUIRED - Amazon Cognito Region
            region: process.env.REACT_APP_region,
        // OPTIONAL - Amazon Cognito User Pool ID
            userPoolId: process.env.REACT_APP_userPoolId,
        // OPTIONAL - Amazon Cognito Web Client ID (26-char alphanumeric string)
            userPoolWebClientId: process.env.REACT_APP_userPoolWebClientId,
        // OPTIONAL - Enforce user authentication prior to accessing AWS resources or not
            mandatorySignIn: false,
        // OPTIONAL - Configuration for cookie storage
            cookieStorage: {
            // REQUIRED - Cookie domain (only required if cookieStorage is provided)
                domain: '.$APP_DOMAIN',
            // OPTIONAL - Cookie path
                path: '/',
            // OPTIONAL - Cookie expiration in days
                expires: 30,
            // OPTIONAL - Cookie secure flag
                secure: true
            }
        },
    API: {
        endpoints: [
            {
            name: "media",
            endpoint: "https://$MY_DOMAIN",
            region: 'ap-southeast-2',
            service: 'lambda'
            },
        ]
    }
});

The IAM AuthRole for Cognito:

    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "mobileanalytics:PutEvents",
                "cognito-sync:*",
                "cognito-identity:*"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "execute-api:Invoke"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}

If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem. Your bug will get fixed much faster if we can run your code and it doesn't have dependencies other than AWS Amplify.

What is the expected behavior?

The API returns a 200 response.

I can see the auth headers (e.g. X-Amz-Security-Token) in the request, I assume I don't need to add additional jwt headers in the request.... I feel like I'm missing something obvious, but for the life of me can't figure it out (javascript noob). Thanks in advance.

Which versions of Amplify, and which browser / OS are affected by this issue? Did this work in previous versions?

amplify version 0.3.3
npm version 6.0.1
react version 16.3.2

You can turn on the debug mode to provide more info for us by setting window.LOG_LEVEL = 'DEBUG'; in your app.

bug investigating

All 9 comments

@L226 In addition to setting cors on the API you also need to make sure that your API returns the CORS headers. If you're using lambda proxy integration it will look something like:

        return {
            body: JSON.stringify(YOUR-API-RESPONSE),
            headers: {
                "Access-Control-Allow-Credentials" : true,
                "Access-Control-Allow-Origin": "*",
                // PUT MORE HEADERS HERE
            },
            statusCode: 200,
        };

Without those headers you get the message you're reporting.

Hi @L226 if you are invoking api gateway you don't need this service: 'lambda' parameter on Amplify configuration because you are invoking API gateway directly. You only need specify name and endpoint

Thanks for the replies.

Yeah I added those headers and the "Failed to load https://$MY_DOMAIN: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. The response had HTTP status code 401." error has gone away.

I'm still getting a 401 response however:

Error: Request failed with status code 401
    at createError (createError.js:16)
    at settle (settle.js:18)
    at XMLHttpRequest.handleLoad (xhr.js:77)

I believe this is due to my backend not handling the authorization correctly (python Flask + zappa). I will investigate further and update this ticket accordingly.

My investigations yielded nothing re. authorization in my backend itself. Zappa should just handle it automatically with my configuration.

Perhaps either my Cognito user pool or identity pool hasn't been configured correctly. I followed the documentation here. But I get these responses before sign-in:

POST https://cognito-identity.ap-southeast-2.amazonaws.com/ 400 (Bad Request)

and

x-amzn-ErrorMessage: Access to Identity 'ap-southeast-2:67fc67c1-921a-4484-8aac-198013eafd64' is forbidden.

After sign-in:

Error: Request failed with status code 401
    at createError (createError.js:16)
    at settle (settle.js:18)
    at XMLHttpRequest.handleLoad (xhr.js:77)

from the API.get method, and the cognito login:

Request URL: https://cognito-idp.ap-southeast-2.amazonaws.com/
Request Method: POST
Status Code: 200 OK
Remote Address: 13.55.234.51:443
Referrer Policy: no-referrer-when-downgrade
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: x-amzn-RequestId,x-amzn-ErrorType,x-amzn-ErrorMessage,Date
Connection: keep-alive
Content-Length: 35
Content-Type: application/x-amz-json-1.1
Date: Sat, 12 May 2018 09:55:21 GMT
x-amzn-RequestId: 95c9e049-55ca-11e8-87b8-2f573fb8980e
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8
Cache-Control: max-age=0
Connection: keep-alive
Content-Length: 1869
Content-Type: application/x-amz-json-1.1
DNT: 1
Host: cognito-idp.ap-southeast-2.amazonaws.com
Origin: http://localhost:3000
Referer: http://localhost:3000/
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36
X-Amz-Target: AWSCognitoIdentityProviderService.ConfirmDevice
X-Amz-User-Agent: aws-amplify/0.1.x js
{DeviceKey: "ap-southeast-2_***********",鈥
AccessToken
:
"***********"
DeviceKey
:
"ap-southeast-2_***********"
DeviceName
:
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36"
DeviceSecretVerifierConfig
:
{Salt: "***********",鈥
PasswordVerifier
:
"***********"
Salt
:
"***********"

Which I guess means the sign in worked.

I also attempted to log the current session after sign in just to have a look:

    Auth.currentSession().then(creds => {
            console.log(creds.getIdToken().getJwtToken());
        }).catch(err => {console.log('unable to get token:', err)})

but I just get

unable to get token: No current user

Cognito config:

  • enabled "Enable sign-in API for server-based authentication (ADMIN_NO_SRP_AUTH)" in App client settings
  • checked Cognito pool in App Client Enabled Identity Providers
  • provided callback URLs and sign out URLs
  • enabled Authorization code grant and Implicit Grant in OAuth 2.0
  • Allowed all OAuth scopes

Do the responses I'm getting mean that somewhere the auth flow is broken and/or I've borked my Cognito config? Sorry for the noob questions, first time Cognito user. Thanks

@L226 can you paste a code snippet of your sign-in call?

You should do something like this https://aws.github.io/aws-amplify/media/authentication_guide#sign-up

I'm using the withAuthenticator HOC on the App component. EDIT - Auth.currentCredentials() actually returns a valid CognitoIdentityCredentials object. Auth.currentSession() does not.

Ok, I found it. My API gateway was configured to use COGNITO_USER_POOLS as the authorizer, however it actually needed to be set to IAM_AUTH to utilise the AWS v4 signing used in Amplify. Thanks for your help!

Ok, I found it. My API gateway was configured to use COGNITO_USER_POOLS as the authorizer, however it actually needed to be set to IAM_AUTH to utilise the AWS v4 signing used in Amplify. Thanks for your help!

Hey @L226 I am using Cognito with a manual config on Amplify, and I'm getting that nasty CORS issue despite following your steps as well...

You mentioned that your authorizer was configured for Cognito, isn't it supposed to be configured like that in my case if I'm using Cognito with Amplify?

@waldothedeveloper need to set the Authorization header when calling API, as part of Amplify.configire -

Amplify.configure({
    API: {
    endpoints: [
        {
        name: "my-api",
        endpoint: "https://XXXXXXXXX.execute-api.eu-west-1.amazonaws.com",
        custom_header: async () => { 
            return { Authorization: `Bearer ${(await Auth.currentSession()).getIdToken().getJwtToken()}` };
        }
        }
    ]
    }
});

https://docs.amplify.aws/lib/restapi/authz/q/platform/js#request-headers

Was this page helpful?
0 / 5 - 0 ratings

Related issues

DougWoodCDS picture DougWoodCDS  路  3Comments

romainquellec picture romainquellec  路  3Comments

ddemoll picture ddemoll  路  3Comments

ldgarcia picture ldgarcia  路  3Comments

TheRealRed7 picture TheRealRed7  路  3Comments