aws-amplify / amplify-category-api

The AWS Amplify CLI is a toolchain for simplifying serverless web and mobile development. This plugin provides functionality for the API category, allowing for the creation and management of GraphQL and REST based backends for your amplify project.
https://docs.amplify.aws/
Apache License 2.0
89 stars 79 forks source link

Field level @auth rules on plain types, and weird behavoir on authenticating API-key requests #1703

Open parvusville opened 1 year ago

parvusville commented 1 year ago

How did you install the Amplify CLI?

nåm

If applicable, what version of Node.js are you using?

No response

Amplify CLI Version

12.1.1

What operating system are you using?

Pop Os

Did you make any manual changes to the cloud resources managed by Amplify? Please describe the changes made.

no

Describe the bug

There is weird behavor, where I get Authorization error on API-key authentication if plain type has no @auth rules. If I have just one @auth rule, it seems to somehow work?

Example schema

type Query {
  authTestNoAuth(test: String): AuthTestNoAuths
    @auth(rules: [{ allow: public }, { allow: private }])
    @function(name: "controller-${env}")
  authTestSingleAuth(test: String): AuthTestSingleAuth
    @auth(rules: [{ allow: public }, { allow: private }])
    @function(name: "controller-${env}")
  authTest(test: String): AuthTest
    @auth(rules: [{ allow: public }, { allow: private }])
    @function(name: "controller-${env}")
}

type AuthTestNoAuths {
  var1: String
  var2: String
  var3: String
  var4: String
  var5: String
}
type AuthTestSingleAuth {
  var1: String @auth(rules: [{ allow: public }, { allow: private }])
  var2: String
  var3: String
  var4: String
  var5: String
}
type AuthTest {
  var1: String @auth(rules: [{ allow: public }, { allow: private }])
  var2: String @auth(rules: [{ allow: public }, { allow: private }])
  var3: String @auth(rules: [{ allow: public }, { allow: private }])
  var4: String @auth(rules: [{ allow: public }, { allow: private }])
  var5: String @auth(rules: [{ allow: public }, { allow: private }])
}

Lambda

  if (
    ["authTest", "authTestNoAuth", "authTestSingleAuth"].includes(
      event.fieldName
    )
  ) {
    return {
      var1: "1",
      var2: "2",
      var3: "3",
      var4: "4",
      var5: "5",
    };
  } 

Generated resolvers

These generate the following Resolvers:

AuthTest.var1.req.vtl
AuthTest.var1.res.vtl
AuthTest.var2.req.vtl
AuthTest.var2.res.vtl
AuthTest.var3.req.vtl
AuthTest.var3.res.vtl
AuthTest.var4.req.vtl
AuthTest.var4.res.vtl
AuthTest.var5.req.vtl
AuthTest.var5.res.vtl
AuthTestSingleAuth.var1.req.vtl
AuthTestSingleAuth.var1.res.vtl

# req.vtl:
{
  "version": "2018-05-29",
  "payload": {}
}

# res.vtl
$util.toJson($context.source.var1)

Querying the API

With "public" API-key authentication

As you can see below, is there are no field level @auth rules configured, the query fails with Unauthorized problems. However if there is at least one @auth rule on the type (AuthTestSingleAuth), somehow it works? Is this intented behavior? Can I safely use only only @auth field rule to reduce the amount of resolvers generated? I want to do this, because I have observed that having less resolvers on the build process on amplify push might allow me to bypass this issue: #1197

query MyQuery {
  authTest {
    var1
    var2
    var3
  }
  authTestNoAuth {
    var3
    var2
    var1
  }
  authTestSingleAuth {
    var3
    var2
    var1
  }
}

# Response
{
  "data": {
    "authTest": {
      "var1": "1",
      "var2": "2",
      "var3": "3"
    },
    "authTestNoAuth": {
      "var3": null,
      "var2": null,
      "var1": null
    },
    "authTestSingleAuth": {
      "var3": "3",
      "var2": "2",
      "var1": "1"
    }
  },
  "errors": [
    {
      "path": [
        "authTestNoAuth",
        "var3"
      ],
      "data": null,
      "errorType": "Unauthorized",
      "errorInfo": null,
      "locations": [
        {
          "line": 8,
          "column": 5,
          "sourceName": null
        }
      ],
      "message": "Not Authorized to access var3 on type AuthTestNoAuths"
    }
    #... AND SAME ERROR FOR var1 and var2
  ]
}

With "private" Cognito user pool authentication

Not quite sure why does this work out of the box? The Default authorization mode of my API is Cognito user pool.

# Query is the same as above

# Response
{
  "data": {
    "authTest": {
      "var1": "1",
      "var2": "2",
      "var3": "3"
    },
    "authTestNoAuth": {
      "var3": "3",
      "var2": "2",
      "var1": "1"
    },
    "authTestSingleAuth": {
      "var3": "3",
      "var2": "2",
      "var1": "1"
    }
  }
}

Expected behavior

Not sure what is expected behavior in this case, but the behavior I'm seeing here seems a little off. Using @auth rules on plain types is not to well covered in the documentation.

Reproduction steps

  1. Use the provided schema
  2. Have API with primary auth set to Cognito
  3. Do the provided example queries
  4. Observe the behavior

Project Identifier

f59e77335650fce92677ec2970143a9b

Log output

``` # Put your logs below this line ```

Additional information

No response

Before submitting, please confirm:

AnilMaktala commented 1 year ago

Hey @parvusville, Thank you for bringing this to our attention and providing the necessary details. We will investigate the issue and keep you informed of our progress.