Amplify-cli: @auth not working for custom Query and resolvers

Created on 7 Nov 2019  Â·  37Comments  Â·  Source: aws-amplify/amplify-cli

I have implemented multi asuthentication systems into my amploify project, with Cognito pools are the default and IAM as the secondary.

All works fine for the authentication on amplify generated queries and mutation, however my custom queries always return the following when called:

GraphQL Error: message: "Request failed with status code 401"

My queries:

type Query {
  searchElasticEvents(input: SearchEventsInput): EventConnection @aws_iam @aws_cognito_user_pools
  searchElasticPlaces(input: SearchPlacesInput): EntityConnection
}

I have tried with adding the ' @aws_iam @aws_cognito_user_pools' directives, and without and both error.

I can't add the auth directive as that requires the @model directive to be present.

The custom resolvers contain no authentication checks as I wish them to be public, so why is it giving me an authentication error:

Front end call:

` const { data } = await this.amplify.api().graphql({
        query: searchElasticPlaces, 
        variables: { input },
        authMode: 'AWS_IAM'
       });`
feature-request graphql-transformer

Most helpful comment

+1

Same problem with a mutation method, I have tried @auth @aws_iam @aws_api_key, both without success. It works just with group User with Cognito.

type Mutation {
  startProposal(input: StartProposalInput): String
    @function(name: "func-${env}")
    @auth(
      rules: [
        { allow: groups, groups: ["User"] }
        { allow: private, provider: iam, operations: [read, create, update] },
      ]
    )
    @aws_iam @aws_api_key
}

All 37 comments

@oliverandersencox could you please clear this up for me:

I have tried with adding the ' @aws_iam @aws_cognito_user_pools' directives, and without and both error.

What do you mean "and without and both error" ?

as in, I have tried add the directives like this:

type Query @aws_iam @aws_cognito_user_pools { }

And I have tried adding them add field level as well like this:

`type Query {
  searchElasticEvents(input: SearchEventsInput): EventConnection @aws_iam @aws_cognito_user_pools
  searchElasticPlaces(input: SearchPlacesInput): EntityConnection
}`

Nothing has worked and non eof the custom queries work. They always return a 401 error

@oliverandersencox Can you send us the entire schema you have? Does the EntityConnection type has @auth rules?

@kaustavghosh06 yes they do:

`type EventConnection @aws_iam @aws_cognito_user_pools  {
  items: [Event]
  nextToken: String
}

type RepeatEventConnection @aws_iam @aws_cognito_user_pools  {
  items: [RepeatEvent]
  nextToken: String
}

type EntityConnection @aws_iam @aws_cognito_user_pools  {
  items: [Entity]
  nextToken: String
}
`

And the Query schema:

`type Query @aws_iam @aws_cognito_user_pools {
  searchElasticEvents(input: SearchEventsInput): EventConnection @aws_iam @aws_cognito_user_pools 
  searchElasticRepeatedEvents(input: SearchRepeatEventsInput): RepeatEventConnection  @aws_iam @aws_cognito_user_pools 
  searchElasticPlaces(input: SearchPlacesInput): EntityConnection  @aws_iam @aws_cognito_user_pools 
  searchElasticSpecialOffers(input: SearchOffersInput): OffersConnection @aws_iam @aws_cognito_user_pools 
}`

and all the failing types follow the same auth as this model:

`type Event @model @searchable 
  @auth(rules: [
    { allow: owner },
    { allow: groups, groups: ["admin"] },
    { allow: groups, groups: ["users"], operations: [read] },
    { allow: public, provider: iam, operations: [read] }
  ])
  @key(name: "byEntity", fields: ["entityId", "dateTime"], queryField: "eventsByEntity") {
  id: ID!
  title: String!
  entityId: String!
  subtitle: String
  description: String
  type: String
  address: Address
  categories: [String]
  dateTime: Float!
  startDate: AWSDateTime!
  endDate: AWSDateTime!
  closingTime: Float!
  showWeather: Boolean
  buyTicketUrl: String
  scheduleId: String
  listId: String
  canBook: Boolean
  video: String
  images: [String]
  location: Location
  price: String
  city: String!
  attending: Int
  views: Int
  status: String
  entity: Entity @connection(name: "EventEntitiy")
  createdAt: Float!
  updatedAt: Float!
}`

I have no tried everything and still it returns a 401 for the custom search queries. My resolvers involve no authentication at all and worked absolutely fine before adding auth rules.

I'm sitting right now fighting something similar. I have a few custom queries and mutations that resolves to a Lambda function but no matter what I do, I cannot get a connection through. 401 constantly. The only one that works is one where I have a field on a @model which maps to the query which is calling the Lambda.

I have added @aws_iam and @aws_cognito_user_pools in every possible place but I just cannot get a request through. I've tried figuring out where it happens but debugging is hard because not all parts of the request are logged. It would be great with more real-life examples for these new features, but I honestly doubt if my case is supported. I've read both that it is and that it is not in various Github issues, so I'm more confused than ever.

@houmark considering a custom query is a very common case, this should be documented as you said. Simple uses cases for all new features would be great

Hello!
I have the same problem.
Created a simple geolocation search with custom resolver link, all goes well with Cognito auth, but now I want to make it public... and there is no way...
I also try to put in the IAM unauth role the custom query, but without success...
Please, document and give feedback: my web app is on hold.

Thanks

@kaustavghosh06 I really need to launch soon ans this is the only thing holding us back. Any solution?

interestingly if I run a query to any of the custom resolvers from the appsync console with AWS_IAM as the auth type, they work just fine

I also have a new feature on our platform being held back due to this which should have been released already. The only really annoying workaround seems to be making a REST endpoint and directing that to the same pipeline function but it’s extra work for something that may work as expected in just few days (hopefully?).

And yes @oliverandersencox my same experience. In the appsync console these custom queries works just fine with IAM authentication selected. This should be really simple to fix @kaustavghosh06

@houmark how would i direct it to the pipeline function. I have the API gateway up but not exactly sure what ton point it at?

thanks

I’m traveling today so on my phone but it should be possible to create a REST end point and select your pipeline function as the function for the REST endpoint. Then you’d tweak the handler to both accept a typeName and fieldName for pipeline usage and if not set then pass the request on to app.js which would be just like a normal amplify REST function. This way you can actually have the same function handle both pipeline calls and API gateway / REST calls as long as you of course send a compatible payload for both of them.

And when you can drop the REST because AWS fixes the custom pipeline function auth, then it would be a matter of removing the REST api in Amplify and maybe also removing the code related to REST in the function. So a bit of overhead which I guess could be okay if there’s no alternative and the feature needs to get released.

Let me know if you progress today. I may be able to paste in some code when I’m back on my Mac at the hotel. I did this on another similar setup where I wanted to do very similar stuff both through REST and a custom mutation / query.

right, thanks so much mate. Ill see if I can get it going.

Very annoying that this is not functional yet

@kaustavghosh06 any update on this?

@oliverandersencox reading through this issue, I think there might be some confusion. This message:

Request failed with status code 401

...means that your HTTP request has hit the service and failed an Authorization check, even before a GraphQL resolver has been invoked. Now it could be that your default Authorization mode is set to something else, or it could be because that GraphQL field you're trying to invoke doesn't have one of the supported annotations set. I would start at the service layer to see what is configured after an $amplify push and confirm that the default auth mode is configured to what you are looking for, and that the field types your using have the proper directives on the schema. At that point you can start looking at your client invocations to see if they are correct or not.

@undefobj This is also happening to me (and several others considering multiple bug reports and people raising this) and I've struggled to find any log on the request.

It may be that it does not hit the resolver, but Amplify should wire this in automatically because it's just a custom query or mutation in the Schema without a field in any model. If it's a pipeline function connected with a field in a model, then it works, but not all use cases allow for that type of usage (especially for mutations).

In addition, I don't see how I am able to do any adjustments to access on this as the graphql end point is not exposed in any way to me in AWS. This is not passing through the API Gateway but goes directly to the AppSync Console, but in there, you cannot tweak any of this to the best of my knowledge.

I've tried adjusting CustomResources.json as it was suggested in https://github.com/aws-amplify/amplify-cli/issues/2540#issuecomment-540152006 but that broke more than it fixed, so I had to drop that. Then I saw that both authRole and unAuthRole needs to be added in https://github.com/aws-amplify/amplify-cli/issues/2711#issuecomment-552499936 but I did not have time yet to try that (I hope to give it a shot tonight). When I tried this last time, all the other IAM based auth directives were removed from the final role (or policy) so it seems modifying this file may not be safe.

Can we please have someone at the AWS team review this with a simple test case and see if there's something Amplify can do better here — I am confident this is a (simple) bug in something that's not being wired in correctly in Amplify.

@oliverandersencox I looked at your schema again, and I see that you were using an IAM provider for Event which worked but didn't work when you tried to run the custom queries which you used @aws_iam. One thing to note is that when using the @auth rules with provider: iam Amplify will automatically update the IAM role which you are using in Cognito for that type, however if you're just using the schema directives for AppSync (like @aws_iam and @aws_cognito_user_pools) these are simply passed through to the schema and you must update the policy yourself since it's a custom query. That's possibly why you're getting a 401.

So to clarify:

  • Management of policies is done automatically with @auth only on @model types
  • You can use the AppSync schema directives @aws_iam and @aws_cognito_user_pools on a custom type either annotated with @function or using a custom resolver, however Amplify will not update policies in this case as it's your own custom stack

@houmark We can mark this as a feature enhancement for @auth to add IAM policies for non @model types.

@undefobj I have tried every combination of @aws_iam and @aws_cognito_pools on the query, type and on the function — all without success.

@undefobj and this updating of the policies is done through the IAM console right, and not the amplify part?

If this is the case, then why is this not documented anywhere and the error gives absolutely no information.

as @houmark says, we've added the combination of @aws_iam and @aws_cognito_pools on the query, type and function all without success.

If we therefore have to add a policy to them, how exactly do we do this, I cant find documentation anywhere

I've seem to have made some progress. It's too early to tell if it full works all around or if I opened up too much, but doing as suggested in https://github.com/aws-amplify/amplify-cli/issues/2711#issuecomment-552499936 got me rid of the 401 and returned the value from the pipeline function. I think I missed the unAuthRole policy the last time.

This seems to be a workaround and may have unwanted side effects and Amplify should automatically create these policies for custom queries and mutations in my opinion.

@houmark so am i correct in saying if i add unauth and auth policies to the customresources json, then it will combine the current policies with the custom ones rather than overwrite them.

I am currently pushing one custom policy atm to see if it has an effect

@oliverandersencox I think the trick is to make sure the name ends on "-custom" or something unique as that will keep the original policy and attach the custom policy in addition like here:
Image

Still testing and will update here if I find anything interesting to add.

@houmark - yes my push failed so I will try that. Appreciate the help mate!

@houmark you sir are a legend. All those methods now work.

in case anyone else has problems, add the policies to your customresource.json:

` "UnauthRolePolicyCustom": { "Type": "AWS::IAM::Policy", "Properties": { "PolicyName": "appsync-unauthrole-policy-custom", "Roles": [ { "Ref": "unauthRoleName" } ], "PolicyDocument": { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "appsync:GraphQL" ], "Resource": [ { "Fn ::Sub": [
"arn:aws:appsync:${AWS::Region}:${AWS::AccountId}:apis/${apiId}/types/${typeName}/*",
{
"apiId": {
"Ref": "AppSyncApiId"
},
"typeName": "Query",
"fieldName": "searchElasticPlaces"
}
]
},`

Great to hear you also got it working @oliverandersencox.

I'd like to reiterate that doing only unAuthRole in my testing, can effectively lock down logged in requests, so if there's a chance a user is logged in while doing the query, this can be an undesired side effect, so adding authRole in the same CustomResources.json is most likely the best option.

@oliverandersencox glad that you got this working. Since there's also an a request in this thread to give this capability to non-@model created types, we'll leave the issue open to address this in a future release.

Great @undefobj — Yes, I think Amplify should take care of this out of the box when one adds @aws_iam to the custom query/mutation - basically just removing the need for modifying CustomResources.json as that's a bit complex to understand and get working correctly.

My requirement was that default auth by user pool and got a custom query protected by api key. So just adding @aws_api_key to it in schema.graphql was enough:

type Query {
  customQuery: [MyObject] @function(name: "myfunction-${env}") @aws_api_key
}

+1

Same problem with a mutation method, I have tried @auth @aws_iam @aws_api_key, both without success. It works just with group User with Cognito.

type Mutation {
  startProposal(input: StartProposalInput): String
    @function(name: "func-${env}")
    @auth(
      rules: [
        { allow: groups, groups: ["User"] }
        { allow: private, provider: iam, operations: [read, create, update] },
      ]
    )
    @aws_iam @aws_api_key
}

Related to #2711 and #3590 contains support for this functionality for custom queries backed by functions or custom resolvers.

Given the following schema:

input SearchEventsInput {
  text: String!
}

type EventConnection @aws_iam {
  result: [String!]!
}

type Query {
  searchElasticEvents(input: SearchEventsInput): EventConnection
    @auth(rules: [
      { allow: public, provider: iam }
    ])
}

This will be the output schema the CLI will generate:

input SearchEventsInput {
  text: String!
}

type EventConnection @aws_iam {
  result: [String!]!
}

type Query {
  searchElasticEvents(input: SearchEventsInput): EventConnection @aws_iam
}

It will add the @aws_iam directive to the query with the @auth rule and also generate the appropriate entry in AuthRolePolicynn or UnauthRolePolicynn:

{
    "Effect": "Allow",
    "Action": [
        "appsync:GraphQL"
    ],
    "Resource": [
        {
            "Fn::Sub": [
                "arn:aws:appsync:${AWS::Region}:${AWS::AccountId}:apis/${apiId}/types/${typeName}/fields/${fieldName}",
                {
                    "apiId": {
                        "Fn::GetAtt": [
                            "GraphQLAPI",
                            "ApiId"
                        ]
                    },
                    "typeName": "Query",
                    "fieldName": "searchElasticEvents"
                }
            ]
        }
    ]
}

Notice that since EventConnection has no @model directive - for now - it requires the @aws_iam directive to be in place and also the policy entry for that type.

After following @attilah's instructions and getting excited I unfortunately immediately ran into a related or at least follow-on issue #5289. My custom query is backed by a Lambda so not sure if that's the reason it's not working for me.

I'm going to try removing the @auth annotations and manually update my CustomResources.json instead as recommended by @houmark above and see if that works around the issue.

Manually updating my CustomResources.json also didn't work as I ran into #5892 doing that.

However I did manage to get it working by removing the @auth Amplify-supplied annotation entirely and using AppSync's @aws_iam and @aws_cognito_user_pools annotations instead.

I didn't need to add anything to my CustomResources.json it just worked when switching to AppSync's @aws_iam and @aws_cognito_user_pools annotations instead

I hadn't used those annotations before as thought that would cause issues with Amplify in not using its @auth annotation, but this was the only thing that has worked for me so far.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jeanpaulcozzatti picture jeanpaulcozzatti  Â·  3Comments

davo301 picture davo301  Â·  3Comments

jexh picture jexh  Â·  3Comments

ffxsam picture ffxsam  Â·  3Comments

onlybakam picture onlybakam  Â·  3Comments