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.44k stars 2.13k forks source link

When a client made by generateServerClientUsingCookies is used in a server action it mutates cookies #13787

Closed Aldo-Garza closed 2 months ago

Aldo-Garza commented 2 months ago

Before opening, please confirm:

JavaScript Framework

Next.js

Amplify APIs

GraphQL API, DataStore

Amplify Version

v6

Amplify Categories

storage

Backend

Amplify Gen 2 (Preview)

Environment information

``` # Put output below this line System: OS: Windows 11 10.0.22631 CPU: (8) x64 11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz Memory: 2.85 GB / 15.79 GB Binaries: Node: 20.11.0 - C:\Program Files\nodejs\node.EXE npm: 10.2.4 - C:\Program Files\nodejs\npm.CMD Browsers: Edge: Chromium (127.0.2651.98) Internet Explorer: 11.0.22621.3527 npmPackages: @ampproject/toolbox-optimizer: undefined () @aws-amplify/adapter-nextjs: ^1.2.10 => 1.2.10 @aws-amplify/adapter-nextjs/api: undefined () @aws-amplify/adapter-nextjs/data: undefined () @aws-amplify/backend: ^1.0.4 => 1.0.4 @aws-amplify/backend-cli: ^1.2.2 => 1.2.2 @aws-amplify/ui-react: ^6.1.13 => 6.1.14 @aws-amplify/ui-react-internal: undefined () @aws-sdk/s3-presigned-post: ^3.623.0 => 3.623.0 @aws-sdk/s3-request-presigner: ^3.623.0 => 3.623.0 @azure/storage-blob: ^12.24.0 => 12.24.0 @babel/core: undefined () @babel/runtime: 7.22.5 @edge-runtime/cookies: 4.1.1 @edge-runtime/ponyfill: 2.4.2 @edge-runtime/primitives: 4.1.0 @formatjs/intl-localematcher: ^0.5.4 => 0.5.4 @fortawesome/fontawesome-svg-core: ^6.5.2 => 6.6.0 @fortawesome/free-brands-svg-icons: ^6.5.2 => 6.6.0 @fortawesome/free-regular-svg-icons: ^6.5.2 => 6.6.0 @fortawesome/free-solid-svg-icons: ^6.5.2 => 6.6.0 @fortawesome/react-fontawesome: ^0.2.0 => 0.2.2 @hapi/accept: undefined () @hookform/resolvers: ^3.9.0 => 3.9.0 @hookform/resolvers/ajv: 1.0.0 @hookform/resolvers/arktype: 2.0.0 @hookform/resolvers/class-validator: 1.0.0 @hookform/resolvers/computed-types: 1.0.0 @hookform/resolvers/effect-ts: 1.0.0 @hookform/resolvers/fluentvalidation-ts: 1.0.0 @hookform/resolvers/io-ts: 1.0.0 @hookform/resolvers/joi: 1.0.0 @hookform/resolvers/nope: 1.0.0 @hookform/resolvers/superstruct: 1.0.0 @hookform/resolvers/typanion: 1.0.0 @hookform/resolvers/typebox: 1.0.0 @hookform/resolvers/typeschema: 1.0.0 @hookform/resolvers/valibot: 1.0.0 @hookform/resolvers/vest: 1.0.0 @hookform/resolvers/vine: 1.0.0 @hookform/resolvers/yup: 1.0.0 @hookform/resolvers/zod: 1.0.0 @mswjs/interceptors: undefined () @napi-rs/triples: undefined () @next/font: undefined () @opentelemetry/api: undefined () @sendgrid/mail: ^8.1.3 => 8.1.3 @types/lodash: ^4.17.7 => 4.17.7 @types/luxon: ^3.4.2 => 3.4.2 @types/negotiator: ^0.6.3 => 0.6.3 @types/node: ^20 => 20.14.10 @types/react: ^18 => 18.3.3 @types/react-dom: ^18 => 18.3.0 @vercel/nft: undefined () @vercel/og: 0.6.2 acorn: undefined () amphtml-validator: undefined () anser: undefined () arg: undefined () assert: undefined () async-retry: undefined () async-sema: undefined () autoprefixer: ^10.4.20 => 10.4.20 aws-amplify: ^6.4.0 => 6.4.4 aws-amplify/adapter-core: undefined () aws-amplify/analytics: undefined () aws-amplify/analytics/kinesis: undefined () aws-amplify/analytics/kinesis-firehose: undefined () aws-amplify/analytics/personalize: undefined () aws-amplify/analytics/pinpoint: undefined () aws-amplify/api: undefined () aws-amplify/api/server: undefined () aws-amplify/auth: undefined () aws-amplify/auth/cognito: undefined () aws-amplify/auth/cognito/server: undefined () aws-amplify/auth/enable-oauth-listener: undefined () aws-amplify/auth/server: undefined () aws-amplify/data: undefined () aws-amplify/data/server: undefined () aws-amplify/datastore: undefined () aws-amplify/in-app-messaging: undefined () aws-amplify/in-app-messaging/pinpoint: undefined () aws-amplify/push-notifications: undefined () aws-amplify/push-notifications/pinpoint: undefined () aws-amplify/storage: undefined () aws-amplify/storage/s3: undefined () aws-amplify/storage/s3/server: undefined () aws-amplify/storage/server: undefined () aws-amplify/utils: undefined () babel-packages: undefined () browserify-zlib: undefined () browserslist: undefined () buffer: undefined () bytes: undefined () ci-info: undefined () cli-select: undefined () client-only: 0.0.1 commander: undefined () comment-json: undefined () compression: undefined () conf: undefined () constants-browserify: undefined () content-disposition: undefined () content-type: undefined () cookie: undefined () cross-spawn: undefined () crypto-browserify: undefined () css.escape: undefined () daisyui: ^4.12.10 => 4.12.10 data-uri-to-buffer: undefined () debug: undefined () devalue: undefined () domain-browser: undefined () edge-runtime: undefined () eslint: ^8 => 8.57.0 eslint-config-next: ^14.2.5 => 14.2.5 events: undefined () expo-server-sdk: ^3.10.0 => 3.10.0 find-cache-dir: undefined () find-up: undefined () firebase: ^10.12.5 => 10.12.5 firebase-admin: ^12.3.0 => 12.3.0 firebase/analytics: undefined () firebase/app: undefined () firebase/app-check: undefined () firebase/auth: undefined () firebase/auth/cordova: undefined () firebase/auth/web-extension: undefined () firebase/compat: undefined () firebase/compat/analytics: undefined () firebase/compat/app: undefined () firebase/compat/app-check: undefined () firebase/compat/auth: undefined () firebase/compat/database: undefined () firebase/compat/firestore: undefined () firebase/compat/functions: undefined () firebase/compat/installations: undefined () firebase/compat/messaging: undefined () firebase/compat/performance: undefined () firebase/compat/remote-config: undefined () firebase/compat/storage: undefined () firebase/database: undefined () firebase/firestore: undefined () firebase/firestore/lite: undefined () firebase/functions: undefined () firebase/installations: undefined () firebase/messaging: undefined () firebase/messaging/sw: undefined () firebase/performance: undefined () firebase/remote-config: undefined () firebase/storage: undefined () firebase/vertexai-preview: undefined () fresh: undefined () get-orientation: undefined () glob: undefined () gzip-size: undefined () http-proxy: undefined () http-proxy-agent: undefined () https-browserify: undefined () https-proxy-agent: undefined () husky: ^9.0.11 => 9.1.4 icss-utils: undefined () ignore-loader: undefined () image-size: undefined () is-animated: undefined () is-docker: undefined () is-wsl: undefined () jest-worker: undefined () json5: undefined () jsonwebtoken: undefined () lint-staged: ^15.2.2 => 15.2.7 loader-runner: undefined () loader-utils: undefined () lodash.curry: undefined () lru-cache: undefined () luxon: ^3.5.0 => 3.5.0 mailersend: ^2.2.0 => 2.2.0 mini-css-extract-plugin: undefined () nanoid: undefined () native-url: undefined () negotiator: ^0.6.3 => 0.6.3 neo-async: undefined () next: 14.2.5 => 14.2.5 nextjs-toploader: ^1.6.12 => 1.6.12 node-fetch: undefined () node-html-parser: undefined () ora: undefined () os-browserify: undefined () p-limit: undefined () path-browserify: undefined () picomatch: undefined () platform: undefined () postcss: ^8.4.41 => 8.4.41 (8.4.31) postcss-flexbugs-fixes: undefined () postcss-modules-extract-imports: undefined () postcss-modules-local-by-default: undefined () postcss-modules-scope: undefined () postcss-modules-values: undefined () postcss-preset-env: undefined () postcss-safe-parser: undefined () postcss-scss: undefined () postcss-value-parser: undefined () prettier: ^3.2.5 => 3.3.3 (2.3.2, 2.8.8, 1.19.1) process: undefined () punycode: undefined () querystring-es3: undefined () raw-body: undefined () react: ^18 => 18.3.1 react-builtin: undefined () react-dom: ^18 => 18.3.1 react-dom-builtin: undefined () react-dom-experimental-builtin: undefined () react-experimental-builtin: undefined () react-is: 18.2.0 react-refresh: 0.12.0 react-select: ^5.8.0 => 5.8.0 react-server-dom-turbopack-builtin: undefined () react-server-dom-turbopack-experimental-builtin: undefined () react-server-dom-webpack-builtin: undefined () react-server-dom-webpack-experimental-builtin: undefined () regenerator-runtime: 0.13.4 sass-loader: undefined () scheduler-builtin: undefined () scheduler-experimental-builtin: undefined () schema-utils: undefined () semver: undefined () send: undefined () server-only: 0.0.1 setimmediate: undefined () shell-quote: undefined () source-map: undefined () source-map08: undefined () stacktrace-parser: undefined () stream-browserify: undefined () stream-http: undefined () string-hash: undefined () string_decoder: undefined () strip-ansi: undefined () superstruct: undefined () sweetalert2: ^11.12.4 => 11.12.4 sweetalert2-react-content: ^5.0.7 => 5.0.7 tailwindcss: ^3.4.7 => 3.4.7 tar: undefined () terser: undefined () text-table: undefined () timers-browserify: undefined () tty-browserify: undefined () typescript: <5.5.0 => 5.4.5 (4.4.4, 4.9.5) ua-parser-js: undefined () unistore: undefined () util: undefined () vm-browserify: undefined () watchpack: undefined () web-vitals: undefined () webpack: undefined () webpack-sources: undefined () ws: undefined () zod: undefined () npmGlobalPackages: @aws-amplify/cli: 12.11.1 aws-amplify-gen2: 0.1.0 corepack: 0.23.0 eas-cli: 9.0.3 npm: 10.2.4 ```

Describe the bug

In nextjs, if a server action is called, and such server action fetches any data from a model like for example the following:

export const cookiesClient = generateServerClientUsingCookies<Schema>({
    config: outputs,
    cookies
})

// A server action
export async function getTodos(){
    const todos = await cookiesClient.models.Todo.list()
    return todos.data
}

It causes a mutation on the cookies (it deletes a cookie), such cookie looks like:

com.amplify.Cognito.us-east-1%3A2309ce70-afb6-4804-9d41-51d950601e06.identityId=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT

This causes unexpected behaviours in nextjs, since the cookie is beign mutated it ends up causing a refresh of the server component

Expected behavior

It should not mutate the cookies. I fixed it by patching the delete method of cookies()

            delete(key: string) {
                if (typeof key !== 'string') {
                    throw new Error('key must be a string')
                }
                if (key.startsWith('com.amplify')) {
                    return
                }
                return cookies().delete(key)
            },

Reproduction steps

1- Create a server component which reads some data for display 2- Inside the server component add a button which calls a server action, such server action must use the cookies client for calling list() on a model for example 3- When calling the server action it will cause the cookies to be mutated which will make the server component to re-render (refresh) even though nothing was changed.

Code Snippet

// Put your code below this line.

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 2 months ago

Hi @Aldo-Garza 👋 thanks for raising this issue and providing reproduction steps!

I will attempt to reproduce the behavior and update this issue accordingly for the team to take action

HuiSF commented 2 months ago

Hi all, this cookie mutation is an expected behavior given current implementation of the credentials fetching logic. We will look into this.

cwomack commented 2 months ago

To add to what @HuiSF said, this appears to be expected behavior. However, we'll mark this as a feature request at this point to explore other/better options for how we're handling the Identity Id every time the credentials are refreshed.

HuiSF commented 2 months ago

Hi @Aldo-Garza we've released a change to remove this redundant Set-Cookie header, you can gain the fix by installing aws-amplify@6.6.3 and @aws-amplify/adapter-nextjs@1.2.20.