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
88 stars 75 forks source link

Can't set field-level authorization in amplify gen2 #2786

Open binarycombinatrix opened 3 weeks ago

binarycombinatrix commented 3 weeks ago

Environment information

System:
  OS: Windows 10 10.0.19045
  CPU: (8) x64 Intel(R) Core(TM) i5-8300H CPU @ 2.30GHz
  Memory: 1.06 GB / 7.86 GB
Binaries:
  Node: 20.16.0 - C:\Program Files\nodejs\node.EXE   
  Yarn: 1.22.10 - ~\AppData\Roaming\npm\yarn.CMD     
  npm: 10.8.1 - C:\Program Files\nodejs\npm.CMD      
  pnpm: undefined - undefined
NPM Packages:
  @aws-amplify/backend: 1.0.4
  @aws-amplify/backend-cli: 1.1.1
  aws-amplify: 6.5.0
  aws-cdk: 2.149.0
  aws-cdk-lib: 2.149.0
  typescript: 5.5.3
AWS environment variables:
  AWS_NODEJS_CONNECTION_REUSE_ENABLED = 1
  AWS_SDK_LOAD_CONFIG = 1
  AWS_STS_REGIONAL_ENDPOINTS = regional
No CDK environment variables

Description

Even after specifying field level authorization for all required fields, it says required fields missing field-level authorization rules: below is the schema file amplify/data/resource.ts

import { type ClientSchema, a, defineData } from "@aws-amplify/backend";

const schema = a.schema({
  Comment: a.customType({
    content: a
      .string()
      .required()
      .authorization((allow) => [
        allow.publicApiKey().to(["read"]),
        allow.authenticated(),
      ]),
    username: a
      .string()
      .required()
      .authorization((allow) => [
        allow.publicApiKey().to(["read"]),
        allow.authenticated(),
      ]),
    dp: a
      .string()
      .required()
      .authorization((allow) => [
        allow.publicApiKey().to(["read"]),
        allow.authenticated(),
      ]),
    dn: a
      .string()
      .required()
      .authorization((allow) => [
        allow.publicApiKey().to(["read"]),
        allow.authenticated(),
      ]),
  }),
  Video: a
    .model({
      partitionKey: a
        .string()
        .required()
        .authorization((allow) => [
          allow.publicApiKey().to(["read"]),
          allow.owner(),
        ]),
      sortKey: a
        .string()
        .required()
        .authorization((allow) => [
          allow.publicApiKey().to(["read"]),
          allow.owner(),
        ]), ////video title or username   + uuidv1
      type: a
        .string()
        .required()
        .authorization((allow) => [
          allow.publicApiKey().to(["read"]),
          allow.owner(),
        ]), ///specify type to avoid confusion
      category: a.string(), /// category which is partition key for video entry
      debate: a.json().array(), ///debate of the video
      description: a.string(), ///channel or video description
      url: a.string(), ///video url
      thumbnail: a.string(), ///video thumbnail
      dp: a.string(), ///user dp can store in both cases,
      comment: a
        .ref("Comment")
        .array()
        .authorization((allow) => [
          allow.publicApiKey().to(["read"]),
          allow.authenticated(),
        ]), ///only in case of video
      dn: a.string(), //display name
      username: a.string(),
    })
    .identifier(["partitionKey", "sortKey"])
    .authorization((allow) => [
      // allow.publicApiKey(),
      allow.publicApiKey().to(["read"]),
      // Allow signed-in user to create, read, update,
      // and delete their __OWN__ posts.
      allow.owner(),
    ]),
});

export type Schema = ClientSchema<typeof schema>;

export const data = defineData({
  schema,
  authorizationModes: {
    defaultAuthorizationMode: "apiKey",
    // API Key is used for a.allow.public() rules
    apiKeyAuthorizationMode: {
      expiresInDays: 30,
    },
  },
});

The error from the terminal is as below:

Failed to instantiate data construct

Caused By: When using field-level authorization rules you need to add rules to all of the model's required fields with at least read permissions. Found model "Video" with required fields ["partitionKey","sortKey","type"] missing field-level authorization rules.\n\nFor more information visit https://docs.amplify.aws/ction-rules
ykethan commented 3 weeks ago

Hey,👋 thanks for raising this! I'm going to transfer this over to our API repository for better assistance 🙂

AnilMaktala commented 3 weeks ago

Hey @binarycombinatrix, When using field-level authorization, you must grant at least read permissions to the remaining fields. I've noticed that the category, debate, description, url, thumbnail, dp, dn, and username fields in the Video model are missing permissions. Please modify the fields as shown below and let me know if this resolves your issue.

Video: a
    .model({
      partitionKey: a
        .string()
        .required()
        .authorization((allow) => [
          allow.publicApiKey().to(["read"]),
          allow.owner(),
        ]),
      sortKey: a
        .string()
        .required()
        .authorization((allow) => [
          allow.publicApiKey().to(["read"]),
          allow.owner(),
        ]), ////video title or username   + uuidv1
      type: a
        .string()
        .required()
        .authorization((allow) => [
          allow.publicApiKey().to(["read"]),
          allow.owner(),
        ]), ///specify type to avoid confusion
      category: a
        .string()
        .authorization((allow) => [allow.publicApiKey().to(["read"])]),
      debate: a
        .json()
        .array()
        .authorization((allow) => [allow.publicApiKey().to(["read"])]), ///debate of the video
      description: a
        .string()
        .authorization((allow) => [allow.publicApiKey().to(["read"])]), ///channel or video description
      url: a
        .string()
        .authorization((allow) => [allow.publicApiKey().to(["read"])]), ///video url
      thumbnail: a
        .string()
        .authorization((allow) => [allow.publicApiKey().to(["read"])]), ///video thumbnail
      dp: a
        .string()
        .authorization((allow) => [allow.publicApiKey().to(["read"])]), ///user dp can store in both cases,
      comment: a
        .ref("Comment")
        .array()
        .authorization((allow) => [
          allow.publicApiKey().to(["read"]),
          allow.authenticated(),
        ]), ///only in case of video
      dn: a
        .string()
        .authorization((allow) => [allow.publicApiKey().to(["read"])]), //display name
      username: a
        .string()
        .authorization((allow) => [allow.publicApiKey().to(["read"])]),
    })
    .identifier(["partitionKey", "sortKey"])
    .authorization((allow) => [
      // allow.publicApiKey(),
      allow.publicApiKey().to(["read"]),
      // Allow signed-in user to create, read, update,
      // and delete their __OWN__ posts.
      allow.owner(),
    ]),
binarycombinatrix commented 2 weeks ago

Hi @AnilMaktala did you try running your version? Those other fields are not required fields and so do not require field level auth, as the model level authorization applies to them and I added publicApi read to it already.

The error too says the issue is with required fields.