aws-amplify / amplify-js

A declarative JavaScript library for application development using cloud services.
https://docs.amplify.aws/lib/q/platform/js
Apache License 2.0
9.42k stars 2.12k forks source link

Using custom identity claim for authorization fails to retrieve related objects. #13877

Open masarliev opened 1 week ago

masarliev commented 1 week ago

Before opening, please confirm:

JavaScript Framework

Vue

Amplify APIs

GraphQL API

Amplify Version

v6

Amplify Categories

api

Backend

Amplify Gen 2 (Preview)

Environment information

``` System: OS: Linux 6.8 Ubuntu 24.04.1 LTS 24.04.1 LTS (Noble Numbat) CPU: (12) x64 Intel(R) Core(TM) i7-10750H CPU @ 2.60GHz Memory: 21.85 GB / 31.18 GB Container: Yes Shell: 5.2.21 - /bin/bash Binaries: Node: 20.17.0 - ~/.nvm/versions/node/v20.17.0/bin/node Yarn: 1.22.22 - ~/.nvm/versions/node/v20.17.0/bin/yarn npm: 10.8.2 - ~/.nvm/versions/node/v20.17.0/bin/npm Browsers: Brave Browser: 129.1.70.119 npmGlobalPackages: corepack: 0.29.3 http-server: 14.1.1 npm: 10.8.2 ts-node: 10.9.2 typescript: 5.6.2 uuid: 10.0.0 yarn: 1.22.22 ```

Describe the bug

Using custom identity claim for authorization fails to retrieve related objects. https://docs.amplify.aws/vue/build-a-backend/data/customize-authz/configure-custom-identity-and-group-claim/ When calling API for each separate everything works as expected, but when I query

await client.models.Class.list({
  selectionSet: ["id", "name", "school.*"],
})

API returns "Not Authorized to access school on type Class.". When authenticated user is teacher it works as expected and school object is returned

Expected behavior

return related object

Reproduction steps

  1. Setup relation between models
  2. Add authorization with custom identity claim
  3. Query with relation

Code Snippet

School: a
.model({
  name: a.string().required(),
  teachers: a.id().array(),
  classes: a.hasMany("Class", "schoolId"),
})
.authorization((allow) => [
  allow.groupDefinedIn("id").withClaimIn("read_schools"),
  allow.ownersDefinedIn("teachers"),
]),
Class: a
.model({
  schoolId: a.id().required(),
  name: a.string().required(),
  teacher: a.id().required(),
  school: a.belongsTo("School", "schoolId"),
})
.authorization((allow) => [
  allow.groupDefinedIn("schoolId").withClaimIn("read_schools"),
  allow.ownerDefinedIn("teacher"),
]),

.....
export const data = defineData({
  name: "schools",
  schema,
  authorizationModes: {
    defaultAuthorizationMode: "userPool",
  },
});

Log output

``` // Put your logs below this line ```

aws-exports.js

No response

Manual configuration

No response

Additional configuration

No response

Mobile Device

No response

Mobile Operating System

No response

Mobile Browser

No response

Mobile Browser Version

No response

Additional information and screenshots

No response

chrisbonifacio commented 1 week ago

Hi @masarliev 👋 thanks for raising this issue!

Have you checked the access token for the custom claims? I'm afraid they're probably not present and you will probably be able to see them on the ID token. At the moment, custom claims are only available on ID tokens.

A potential workaround might be to use the ID token in the Authorization header using a custom graphql header in the Amplify configuration but this is not recommended because ID tokens are not intended to serve authorization purposes like Access tokens are. However, it is possible to customize access tokens to include the same claims as the ID token, the downside is this comes with an extra cost from AWS Cognito.

For more information on customizing access tokens: https://aws.amazon.com/about-aws/whats-new/2023/12/amazon-cognito-user-pools-customize-access-tokens/

masarliev commented 1 week ago

Hi @chrisbonifacio I use V2_0 pre token generation lambda that modifies both tokens and ad custom claims. https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-pre-token-generation.html

chrisbonifacio commented 1 week ago

Ah okay, so you are already leveraging the advanced security features of Cognito.

In that case, can you confirm that the claims are indeed on the access token?

If so, what is the format of the claim? Is it an array of school ids?

masarliev commented 1 week ago

yes they are in the claim and list/get of both models works, but when I want to include school.* in classes list it throws error described in issue

chrisbonifacio commented 3 days ago

Okay, thanks for confirming! I will attempt to reproduce and report back with any findings.