2
votes

I am trying to create an application where a user can sign in and then have access to certain api resources based on their roles.

Users are moved into groups in the user pool and each group has a custom IAM role.

I have used to amplify CLI tools to create the authentication, api gateway and lambda function. This is the API set up in amplify

? Please select from one of the below mentioned services: REST
? Please select the REST API you would want to update standardApi
? What would you like to do Update path
? Please select the path you would want to edit /std
? Provide a path (e.g., /book/{isbn}): /std
? Choose a Lambda source Use a Lambda function already added in the current Ampl
ify project
? Choose the Lambda function to invoke by this path standardFunction
? Restrict API access Yes
? Restrict access by? Individual Groups
? Select groups: standard
? What kind of access do you want for standard users? create, read, update, dele
te
Successfully updated resource

The resources are created as expected when checked in the console.

The trouble is that when attempting to call the API, I am receiving a MissingAuthenticationTokenException

This is the call

const apiName = 'standardApi';
const path = '/std';
const myInit = {
    headers: {},
    response: false
};
API.get(apiName, path, myInit)
.then(response => {
    console.log(response);
})
.catch(error => {
    console.log(error.response);
});

My understanding is that the Amplify sdk should automatically populate the request headers with the correct authentication values.

If I attempt passing in the access token manually,

headers: {
    Authorization: (await Auth.currentSession()).getIdToken().getJwtToken()
},

I get IncompleteSignatureException, with the 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.

Trying

headers: {
    Authorization: `Bearer ${(await Auth.currentSession()).getIdToken().getJwtToken()}
},

results in IncompleteSignatureException with no message.

Other posts have suggested that the endpoint may no be specified correctly, if I remove auth from the api in the console and redeploy, the endpoint is hit as expected. Futhermore, if I create a custom authorizer with the cognito user pool, the endpoint is hit correctly when signed in and a bearer token in passed.

It's just the IAM case that is not working.

Inspecting the ID token shows that the correct username, groups and roles are being passed in.

"cognito:groups": Array [ "standard" ]
"cognito:preferred_role": "arn:aws:iam::************:role/region-*_*********-standardGroupRole"
"cognito:roles": Array [ "arn:aws:iam::************:role/region-*_*********-standardGroupRole"]
"cognito:username": "0a******-****-****-****-************"

The Amplify configure step is being done with auto-generated aws-exports file, which contains correct entries for user pool, identity pool and client app.

1
You have to sign your request as described in the [docs][1] [1]: docs.amplify.aws/lib/graphqlapi/graphql-from-nodejs/q/platform/…Oscar Nevarez
@OscarNevarez Thanks for this. It looks like it does what I need. I ended up using a lambda authorizer to do the job. link that I borrowed from a lotJohan van Rooyen

1 Answers

1
votes

I know this can be a little bit late, but I just wanted to do the same thing that you were trying to do.

This is what I had to do to make it work:

  • Include authentication components in your UI so your API call is done with the credentials of the authenticated user.
  • Be sure to do the API call once you have been authenticated against Cognito (with a user that belong to the group that you specified).
  • Don't include any 'Authorization' header (I looked in the code and I found out that no AWS Signature is generated when Authorization header is set).
  • Make sure that your lambda code returns CORS headers (I was having an InternalServerErrorException from CloudFront because of this).

Doing this I could see in the Developer console of my Browser that the request was signed and had all the headers needed for the IAM authorization validation that API Gateway does.

I hope this cloud be useful to somebody as it took me a lot of time to figure it out.

Regards, Andres Llanos