Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NextJS Unknown: an unknown error has occurred. underlyingError: tA [Error]: Cookies can only be modified in a Server Action or Route Handler. #14200

Closed
3 tasks done
Ammar-Raneez opened this issue Feb 10, 2025 · 6 comments
Assignees
Labels
Auth Related to Auth components/category Next.js question General question SSR Issues related to Server Side Rendering

Comments

@Ammar-Raneez
Copy link

Ammar-Raneez commented Feb 10, 2025

Before opening, please confirm:

JavaScript Framework

Next.js

Amplify APIs

Authentication

Amplify Version

v6

Amplify Categories

auth

Backend

CDK

Environment information

# Put output below this line

  System:
    OS: macOS 15.3
    CPU: (8) arm64 Apple M1
    Memory: 126.03 MB / 8.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 18.13.0 - ~/.nvm/versions/node/v18.13.0/bin/node
    Yarn: 1.22.22 - ~/.yarn/bin/yarn
    npm: 8.19.3 - ~/.nvm/versions/node/v18.13.0/bin/npm
  Browsers:
    Chrome: 132.0.6834.162
    Safari: 18.3
  npmPackages:
    @ampproject/toolbox-optimizer:  undefined ()
    @ant-design/nextjs-registry: ^1.0.2 => 1.0.2 
    @aws-amplify/adapter-nextjs: ^1.4.2 => 1.4.2 
    @aws-amplify/adapter-nextjs/api:  undefined ()
    @aws-amplify/adapter-nextjs/data:  undefined ()
    @aws-sdk/client-cognito-identity-provider: ^3.741.0 => 3.738.0 
    @aws-sdk/client-s3: 3.726.1 => 3.726.1 
    @aws-sdk/client-ses: 3.726.1 => 3.726.1 
    @aws-sdk/s3-request-presigner: 3.726.1 => 3.726.1 
    @babel/core: ^7.14.5 => undefined (7.26.0, )
    @babel/preset-react: ^7.14.5 => 7.26.3 
    @babel/runtime:  7.22.5 
    @edge-runtime/cookies:  5.0.0 
    @edge-runtime/ponyfill:  3.0.0 
    @edge-runtime/primitives:  5.0.0 
    @eslint/compat: 1.2.5 => 1.2.5 
    @eslint/js: 9.18.0 => 9.18.0 
    @hapi/accept:  undefined ()
    @mswjs/interceptors:  undefined ()
    @napi-rs/triples:  undefined ()
    @next/font:  undefined ()
    @nx/devkit: 20.3.1 => 20.3.1 
    @nx/esbuild: 20.3.1 => 20.3.1 
    @nx/eslint: 20.3.1 => 20.3.1 
    @nx/eslint-plugin: 20.3.1 => 20.3.1 
    @nx/express: 20.3.1 => 20.3.1 
    @nx/jest: 20.3.1 => 20.3.1 
    @nx/js: 20.3.1 => 20.3.1 
    @nx/next: 20.3.1 => 20.3.1 
    @nx/node: 20.3.1 => 20.3.1 
    @nx/playwright: 20.3.1 => 20.3.1 
    @nx/react: 20.3.1 => 20.3.1 
    @nx/web: 20.3.1 => 20.3.1 
    @nx/webpack: 20.3.1 => 20.3.1 
    @nx/workspace: 20.3.1 => 20.3.1 
    @opentelemetry/api:  undefined ()
    @playwright/test: ^1.36.0 => 1.49.1 
    @pmmmwh/react-refresh-webpack-plugin: ^0.5.7 => 0.5.15 
    @svgr/webpack: ^8.0.1 => 8.1.0 
    @swc-node/register: 1.10.9 => 1.10.9 
    @swc/core: 1.10.7 => 1.10.7 
    @swc/helpers: ~0.5.11 => 0.5.15 (0.5.5)
    @testing-library/react: 16.1.0 => 16.1.0 
    @types/bcryptjs: ^2.4.6 => 2.4.6 
    @types/express: 5.0.0 => 5.0.0 (4.17.21)
    @types/jest: ^29.5.12 => 29.5.14 
    @types/js-cookie: ^3.0.6 => 3.0.6 
    @types/jsonwebtoken: ^9.0.7 => 9.0.7 
    @types/morgan: ^1.9.9 => 1.9.9 
    @types/node: 22.10.5 => 22.10.5 (22.10.2)
    @types/react: 19.0.5 => 19.0.5 
    @types/react-dom: 19.0.3 => 19.0.3 
    @vercel/nft:  undefined ()
    @vercel/og:  0.6.3 
    acorn:  undefined ()
    ajv: ^8.17.1 => 8.17.1 (6.12.6)
    ajv-formats: ^3.0.1 => 3.0.1 (2.1.1)
    amphtml-validator:  undefined ()
    anser:  undefined ()
    antd: 5.23.0 => 5.23.0 
    arg:  undefined ()
    assert:  undefined ()
    async-retry:  undefined ()
    async-sema:  undefined ()
    autoprefixer: 10.4.20 => 10.4.20 
    aws-amplify: ^6.12.2 => 6.12.2 
    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 ()
    axios: ^1.6.0 => 1.7.9 
    babel-jest: ^29.7.0 => 29.7.0 
    babel-packages:  undefined ()
    bcryptjs: ^2.4.3 => 2.4.3 
    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 ()
    cors: ^2.8.5 => 2.8.5 
    cross-spawn:  undefined ()
    crypto-browserify:  undefined ()
    css.escape:  undefined ()
    data-uri-to-buffer:  undefined ()
    date-fns: ^4.1.0 => 4.1.0 
    debug:  undefined ()
    devalue:  undefined ()
    domain-browser:  undefined ()
    dotenv: ^16.4.7 => 16.4.7 
    edge-runtime:  undefined ()
    env-cmd: ^10.1.0 => 10.1.0 
    esbuild: 0.24.2 => 0.24.2 
    eslint: 9.18.0 => 9.18.0 
    eslint-config-airbnb: ^19.0.4 => 19.0.4 
    eslint-config-airbnb-typescript: ^18.0.0 => 18.0.0 
    eslint-config-next: 15.1.4 => 15.1.4 
    eslint-config-prettier: ^9.0.0 => 9.1.0 
    eslint-plugin-import: 2.31.0 => 2.31.0 
    eslint-plugin-jsx-a11y: 6.10.2 => 6.10.2 
    eslint-plugin-playwright: 2.1.0 => 2.1.0 
    eslint-plugin-react: 7.37.3 => 7.37.3 (7.37.2)
    eslint-plugin-react-hooks: 5.1.0 => 5.1.0 
    eslint-plugin-simple-import-sort: ^12.1.1 => 12.1.1 
    events:  undefined ()
    express: ^4.21.2 => 4.21.2 
    find-cache-dir:  undefined ()
    find-up:  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.1.7 => 9.1.7 
    icss-utils:  undefined ()
    ignore-loader:  undefined ()
    image-size:  undefined ()
    is-animated:  undefined ()
    is-docker:  undefined ()
    is-wsl:  undefined ()
    jest: ^29.7.0 => 29.7.0 
    jest-environment-jsdom: ^29.7.0 => 29.7.0 
    jest-environment-node: ^29.7.0 => 29.7.0 
    jest-worker:  undefined ()
    js-cookie: ^3.0.5 => 3.0.5 
    json5:  undefined ()
    jsonwebtoken: ^9.0.2 => undefined (9.0.2, )
    jwt-decode: ^4.0.0 => 4.0.0 
    lint-staged: 15.3.0 => 15.3.0 
    loader-runner:  undefined ()
    loader-utils:  undefined ()
    lodash.curry:  undefined ()
    lru-cache:  undefined ()
    mini-css-extract-plugin:  undefined ()
    morgan: ^1.10.0 => 1.10.0 
    nanoid:  undefined ()
    native-url:  undefined ()
    neo-async:  undefined ()
    next: 14.2.23 => 14.2.23 
    next-intl: ^3.26.3 => 3.26.3 
    node-fetch:  undefined ()
    node-html-parser:  undefined ()
    nx: 20.2.2 => 20.2.2 (20.3.1)
    ora:  undefined ()
    os-browserify:  undefined ()
    p-limit:  undefined ()
    passport: ^0.7.0 => 0.7.0 
    passport-jwt: ^4.0.1 => 4.0.1 
    path-browserify:  undefined ()
    pg: ^8.13.1 => 8.13.1 
    picomatch:  undefined ()
    platform:  undefined ()
    postcss: 8.4.49 => 8.4.49 (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.4.2 => 3.4.2 
    process:  undefined ()
    punycode:  undefined ()
    querystring-es3:  undefined ()
    raw-body:  undefined ()
    react: 19.0.0 => 19.0.0 
    react-builtin:  undefined ()
    react-dom: 19.0.0 => 19.0.0 
    react-dom-builtin:  undefined ()
    react-dom-experimental-builtin:  undefined ()
    react-experimental-builtin:  undefined ()
    react-icons: ^5.4.0 => 5.4.0 
    react-is:  18.2.0 
    react-refresh: 0.16.0 => 0.16.0 (0.12.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 ()
    reflect-metadata: ^0.2.2 => 0.2.2 
    regenerator-runtime:  0.13.4 
    rotating-file-stream: ^3.2.5 => 3.2.5 
    sass-loader:  undefined ()
    scheduler-builtin:  undefined ()
    scheduler-experimental-builtin:  undefined ()
    schema-utils:  undefined ()
    semver:  undefined ()
    send:  undefined ()
    sequelize: ^6.37.5 => 6.37.5 
    sequelize-typescript: ^2.1.6 => 2.1.6 
    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 ()
    tailwindcss: 3.4.17 => 3.4.17 
    tar:  undefined ()
    terser:  undefined ()
    text-table:  undefined ()
    timers-browserify:  undefined ()
    ts-jest: ^29.1.0 => 29.2.5 
    ts-node: 10.9.2 => 10.9.2 (10.9.1)
    tslib: ^2.3.0 => 2.8.1 
    tty-browserify:  undefined ()
    typescript: 5.7.3 => 5.7.3 (5.6.3)
    typescript-eslint: 8.19.1 => 8.19.1 
    ua-parser-js:  undefined ()
    unistore:  undefined ()
    util:  undefined ()
    vm-browserify:  undefined ()
    watchpack:  undefined ()
    web-vitals:  undefined ()
    webpack:  undefined ()
    webpack-cli: 6.0.1 => 6.0.1 
    webpack-sources:  undefined ()
    winston: ^3.17.0 => 3.17.0 
    winston-daily-rotate-file: ^5.0.0 => 5.0.0 
    ws:  undefined ()
    zod:  undefined ()
    zustand: 5.0.3 => 5.0.3 
  npmGlobalPackages:
    @aws-amplify/cli: 12.8.2
    @nestjs/cli: 10.3.0
    corepack: 0.15.2
    mkcert: 3.2.0
    npm: 8.19.3
    typescript: 5.3.3
    verdaccio: 5.29.0
    yarn: 1.22.19



Describe the bug

I'm trying to connect Amplify auth with my NextJS app and have run into multiple issues.

Using Amplify v6, I initially tested out via Gen 2, and ran into this same issue that is currently open: #13966

The issue I'm facing right now is that authentication works, but the server user returns undefined, due to the below error.

I end up getting the following error

Error fetching session: Unknown: An unknown error has occurred.
    at assertServiceError (webpack-internal:///(rsc)/../../node_modules/@aws-amplify/auth/dist/esm/errors/utils/assertServiceError.mjs:16:15)
    at TokenOrchestrator.handleErrors (webpack-internal:///(rsc)/../../node_modules/@aws-amplify/auth/dist/esm/providers/cognito/tokenProvider/TokenOrchestrator.mjs:131:97)
    at TokenOrchestrator.refreshTokens (webpack-internal:///(rsc)/../../node_modules/@aws-amplify/auth/dist/esm/providers/cognito/tokenProvider/TokenOrchestrator.mjs:127:25)
    at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
    at async TokenOrchestrator.getTokens (webpack-internal:///(rsc)/../../node_modules/@aws-amplify/auth/dist/esm/providers/cognito/tokenProvider/TokenOrchestrator.mjs:99:22)
    at async eval (webpack-internal:///(rsc)/./src/services/auth.server.service.ts:26:35)
    at async runWithAmplifyServerContext (webpack-internal:///(rsc)/../../node_modules/aws-amplify/dist/esm/adapter-core/runWithAmplifyServerContext.mjs:25:24)
    at async AppSidebar (webpack-internal:///(rsc)/./src/components/sidebar/appSidebar.tsx:13:32) {
  underlyingError: tA [Error]: Cookies can only be modified in a Server Action or Route Handler. Read more: https://nextjs.org/docs/app/api-reference/functions/cookies#cookiessetname-value-options

I understand it seems to be a cookie modification issue as mentioned in the underlyingError; however, I haven't been able to diagnose this yet.

The user is authenticated, as a client login returns UserAlreadyAuthenticatedException: There is already a signed in user.

Help would be very much appreciated!!

Expected behavior

Simple expectation: the cookie flow must work as expected in the client and server side. Client side seems to be flawless, but it's the server side giving the headache.

Reproduction steps

  1. Initiate a NextJS application (I'm using CDK with Cognito so the Amplify configurations are given through an env file).
  2. Create the Amplify server config file (provided in code section).
  3. The code provided should trigger the issue.

Code Snippet

// Put your code below this line.
// middleware.ts

import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

import { checkAuthentication } from '@client/services/auth.server.service';

export default async function middleware(request: NextRequest) {
  const response = NextResponse.next();
  const { pathname } = request.nextUrl;

  const loginUrl = new URL(ROUTES.LOGIN, request.url);

  if (isPublicRoute) {
    return response;
  }

  // Allow only authenticated users from accessing the application
  const { isAuthenticated } = await checkAuthentication();
  if (!isAuthenticated) {
    return NextResponse.redirect(loginUrl);
  }

  return response;
}

export const config = {
  matcher: ['/((?!api|_next/static|_next/image|.*\\.png$).*)'],
};




// auth.server.service.ts
const getServerSession = async () =>
  runWithAmplifyServerContext(
    amplifyConfig,
    {
      Auth: { tokenProvider, credentialsProvider },
    },
    async (contextSpec) => {
      try {
        const currentTokens = await tokenProvider.getTokens({ forceRefresh: true });
        if (!currentTokens) {
          return { currentSession: null, tokens: null, isAdmin: false };
        }

        const currentSession = await fetchAuthSession(contextSpec);
        const tokens = currentSession.tokens;
        const { email, groups, isAdmin } = extractUserDetails(tokens);
        return { email, groups, isAdmin, tokens };
      } catch (error) {
        console.error('Error fetching session:', error);
        return { currentSession: null, tokens: null, isAdmin: false };
      }
    },
  );

const checkAuthentication = async () => {
  const { tokens, isAdmin } = await getServerSession();
  return {
    tokens,
    isAdmin,
    isAuthenticated: !!tokens,
  };
};

const extractUserDetails = (tokens?: AuthTokens) => {
  const idToken = tokens?.idToken;
  const groups = idToken?.payload['cognito:groups']?.toString();
  const email = idToken?.payload['email']?.toString();
  const isAdmin = groups?.includes('Admins');
  return { email, groups, isAdmin };
};



// layout.tsx
import React from 'react';

import AppSidebar from '@client/components/sidebar/appSidebar';
import { AmplifyClientProvider } from '@client/providers/amplifyClientProvider';

export default async function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang={locale}>
      <body className={`font-sans antialiased ${notoSans.variable} bg-background`}>
        <AmplifyClientProvider />
        <AppSidebar />
      </body>
    </html>
  );
}



// appSidebar.tsx
import { getServerSession } from '@client/services/auth.server.service';

import { DesktopSidebar } from './sidebarItems/desktopSidebar';

const AppSidebar = async () => {
  const { isAdmin, email } = await getServerSession();        <-------------------------- what throws the error

  return (
    <DesktopSidebar isAdmin={isAdmin} userEmail={email} />
  );
};

export default AppSidebar;

Lastly, the client and server providers:

// amplifyClientProvider.tsx
'use client';

import { Amplify } from 'aws-amplify';

import { authConfig } from '@client/utils/amplifyConfig.utils';

Amplify.configure(authConfig, { ssr: true });

export const AmplifyClientProvider = () => {
  return null;
}



// amplifyServerProvider.ts
import { cookies } from 'next/headers';
import {
  createKeyValueStorageFromCookieStorageAdapter,
  createUserPoolsTokenProvider,
  createAWSCredentialsAndIdentityIdProvider,
} from 'aws-amplify/adapter-core';
import { parseAmplifyConfig } from 'aws-amplify/utils';

import { authConfig } from '@client/utils/amplifyConfig.utils';

const amplifyConfig = parseAmplifyConfig(authConfig);

const keyValueStorage = createKeyValueStorageFromCookieStorageAdapter({
  get(name) {
    return { name, value: cookies().get(name)?.value };
  },
  getAll() {
    return cookies()
      .getAll()
      .map(({ name, value }) => ({ name, value }));
  },
  set(name, value) {
    cookies().set(name, value, { path: '/', httpOnly: true, secure: true, sameSite: 'lax' });
  },
  delete(name) {
    cookies().delete(name);
  },
});

export const tokenProvider = createUserPoolsTokenProvider(amplifyConfig.Auth!, keyValueStorage);

export const credentialsProvider = createAWSCredentialsAndIdentityIdProvider(
  amplifyConfig.Auth!,
  keyValueStorage,
);



// amplifyConfig.utils
import { USER_POOL_ID, USER_POOL_CLIENT_ID, REGION } from '@workspace/types/constants/config';

export const authConfig = {
  Auth: {
    Cognito: {
      userPoolId: USER_POOL_ID!,
      userPoolClientId: USER_POOL_CLIENT_ID!,
      region: REGION!,
    },
  },
};

Log output

// Put your logs below this line
Error fetching session:  [Unknown: An unknown error has occurred.] {
  name: 'Unknown',
  underlyingError: [Error: Cookies can only be modified in a Server Action or Route Handler. Read more: https://nextjs.org/docs/app/api-reference/functions/cookies#cookiessetname-value-options],
  recoverySuggestion: undefined,
  constructor: [Function: AuthError]
}
Error fetching session: Unknown: An unknown error has occurred.
    at assertServiceError (webpack-internal:///(rsc)/../../node_modules/@aws-amplify/auth/dist/esm/errors/utils/assertServiceError.mjs:16:15)
    at TokenOrchestrator.handleErrors (webpack-internal:///(rsc)/../../node_modules/@aws-amplify/auth/dist/esm/providers/cognito/tokenProvider/TokenOrchestrator.mjs:131:97)
    at TokenOrchestrator.refreshTokens (webpack-internal:///(rsc)/../../node_modules/@aws-amplify/auth/dist/esm/providers/cognito/tokenProvider/TokenOrchestrator.mjs:127:25)
    at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
    at async TokenOrchestrator.getTokens (webpack-internal:///(rsc)/../../node_modules/@aws-amplify/auth/dist/esm/providers/cognito/tokenProvider/TokenOrchestrator.mjs:99:22)
    at async eval (webpack-internal:///(rsc)/./src/services/auth.server.service.ts:26:35)
    at async runWithAmplifyServerContext (webpack-internal:///(rsc)/../../node_modules/aws-amplify/dist/esm/adapter-core/runWithAmplifyServerContext.mjs:25:24)
    at async AppSidebar (webpack-internal:///(rsc)/./src/components/sidebar/appSidebar.tsx:13:32) {
  underlyingError: tA [Error]: Cookies can only be modified in a Server Action or Route Handler. Read more: https://nextjs.org/docs/app/api-reference/functions/cookies#cookiessetname-value-options
      at Proxy.callable (/Users/ammar/Documents/Work/SoftSora/Osaka Gas/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:36:13455)
      at Object.delete (webpack-internal:///(rsc)/./src/providers/amplifyServerProvider.ts:39:71)
      at Object.setItem (webpack-internal:///(rsc)/../../node_modules/aws-amplify/dist/esm/adapter-core/storageFactories/createKeyValueStorageFromCookieStorageAdapter.mjs:27:40)
      at DefaultTokenStore.storeTokens (webpack-internal:///(rsc)/../../node_modules/@aws-amplify/auth/dist/esm/providers/cognito/tokenProvider/TokenStore.mjs:75:41)
      at TokenOrchestrator.setTokens (webpack-internal:///(rsc)/../../node_modules/@aws-amplify/auth/dist/esm/providers/cognito/tokenProvider/TokenOrchestrator.mjs:146:37)
      at TokenOrchestrator.refreshTokens (webpack-internal:///(rsc)/../../node_modules/@aws-amplify/auth/dist/esm/providers/cognito/tokenProvider/TokenOrchestrator.mjs:122:24)
      at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
      at async TokenOrchestrator.getTokens (webpack-internal:///(rsc)/../../node_modules/@aws-amplify/auth/dist/esm/providers/cognito/tokenProvider/TokenOrchestrator.mjs:99:22)
      at async eval (webpack-internal:///(rsc)/./src/services/auth.server.service.ts:26:35)
      at async runWithAmplifyServerContext (webpack-internal:///(rsc)/../../node_modules/aws-amplify/dist/esm/adapter-core/runWithAmplifyServerContext.mjs:25:24)
      at async AppSidebar (webpack-internal:///(rsc)/./src/components/sidebar/appSidebar.tsx:13:32),
  recoverySuggestion: undefined,
  constructor: [class AuthError extends AmplifyError]
}

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

@github-actions github-actions bot added pending-triage Issue is pending triage pending-maintainer-response Issue is pending a response from the Amplify team. labels Feb 10, 2025
@HuiSF
Copy link
Member

HuiSF commented Feb 10, 2025

Hi @Ammar-Raneez thanks for opening this issue.

First of all, any particular reason that you are using the generic runWithAmplifyServerContext function exported from aws-amplify/adapter-core instead of the prebuilt Amplify JS adapter for Next.js (@aws-amplify/adapter-nextjs)? If there is no specific requirement, you should always use @aws-amplify/adapter-nextjs with your Next.js app. See this documentation for more details.

Regarding the error you encountered: looking at your own implementation of the keyValueStorage, you are using Next.js provided cookies header API to implement the set method:

  set(name, value) {
    cookies().set(name, value, { path: '/', httpOnly: true, secure: true, sameSite: 'lax' });
  },

According to Next.js requirements, you can only call cookies().set() from a server action handler or an API route handler. Otherwise it will throw error. So you need to handle that by yourself.

@HuiSF HuiSF added question General question SSR Issues related to Server Side Rendering Next.js labels Feb 10, 2025
@github-actions github-actions bot removed pending-maintainer-response Issue is pending a response from the Amplify team. pending-triage Issue is pending triage labels Feb 10, 2025
@cwomack cwomack self-assigned this Feb 10, 2025
@cwomack cwomack added the Auth Related to Auth components/category label Feb 10, 2025
@Ammar-Raneez
Copy link
Author

Ammar-Raneez commented Feb 11, 2025

Thank you for the response,

I tried migrating over to use the nextJS adapter, which is when I get #13966

import { getServerUser } from '@client/services/auth.server.service';

import { DesktopSidebar } from './sidebarItems/desktopSidebar';

const AppSidebar = async () => {
  const { email, isAdmin } = await getServerUser(); <--------- Issue

  return (
    <DesktopSidebar isAdmin={isAdmin} userEmail={email} />
  );
};

export default AppSidebar;



const getServerUser = async () => {
  try {
    const currentUser = await serverRunner.runWithAmplifyServerContext({
      nextServerContext: { cookies },
      operation: (contextSpec) => getCurrentUser(contextSpec),
    });

    return { email: currentUser.signInDetails?.loginId, isAdmin: true };
  } catch (error) {
    console.error(error);
    return { email: undefined, groups: undefined, isAdmin: false };
  }
};

The appSidebar is present in RootLayout.

When I refresh the page it seems to be working, on login completion this is what happens:

  const navigateUser = async () => {
    const { isAdmin } = await getSession();
    if (isAdmin) {
      router.push(ROUTES.ADMIN_ACCOUNT_MANAGEMENT);
    }

    router.push(ROUTES.ACCOUNT);
  };

const getSession = async () => {
  const currentSession = await fetchAuthSession();     <----------- Imported from amplify/auth 
  const tokens = currentSession.tokens;
  const isAdmin = tokens?.accessToken.payload['cognito:groups']?.toString()?.includes('Admins');
  return { currentSession, isAdmin };
};

@github-actions github-actions bot added the pending-maintainer-response Issue is pending a response from the Amplify team. label Feb 11, 2025
@HuiSF
Copy link
Member

HuiSF commented Feb 11, 2025

Hi @Ammar-Raneez thanks for following up. Re:

When I refresh the page it seems to be working, on login completion this is what happens:

Could you provide details about how are you implementing the sign-in?

In general, since the sign-in is performed on the client side - exchanging auth tokens and writing them into cookie store are also done on the client side. So after signing in, and before the auth token cookies are written into the cookie store, if you access a route that invokes server-side getCurrentUser() the request won't have any cookie header so it will throw the error you encountered.

To mitigate this, you can use client-side getCurrentUser or fetchAuthSession to ensure the tokens are already written into the cookie store, then redirect to the route you desire to use the server-side Amplify APIs.

@github-actions github-actions bot removed the pending-maintainer-response Issue is pending a response from the Amplify team. label Feb 11, 2025
@Ammar-Raneez
Copy link
Author

Ammar-Raneez commented Feb 12, 2025

Hi, yea sure:

Sign in is simply a client side call to amplify/auth signIn:

const signin = async (username: string, password: string): Promise<SignInOutput> => {
  return signIn({
    username,
    password,
  });
};

The above is called in a LoginForm component as follows:

  const onLogin = async (values: LoginFormFields) => {
      const res = await signin(values.email, values.password);
  }

Since the appSidebar is called from the RootLayout (which gets triggered even when in the login page):

import { getServerUser } from '@client/services/auth.server.service';

import { DesktopSidebar } from './sidebarItems/desktopSidebar';

const AppSidebar = async () => {
  const { email, isAdmin } = await getServerUser();

  return (
    <DesktopSidebar isAdmin={isAdmin} userEmail={email} />
  );
};

export default AppSidebar;

Do you suggest using client side get user and session converting the into a client component? Or another way I could could about this is by having two separate layouts?

@github-actions github-actions bot added the pending-maintainer-response Issue is pending a response from the Amplify team. label Feb 12, 2025
@HuiSF
Copy link
Member

HuiSF commented Feb 12, 2025

Hi @Ammar-Raneez since your appSidebar is a part of the RootLayout, you may want to make it renders gracefully by catching the error:

  1. when server-side getCurrentUser throws, render a non-signed-in state
  2. when you can get the user from the server-side, render a signed-in state

In addition, you can refresh the page after calling the client-side signIn() API, to ensure the token cookies are received by your server. e.g.

const router = useRouter();

const onSignIn = async () => {
  const result = await signIn({ username: 'username', password: 'password' });

  if (result.isSignedIn) {
    router.reload();
    // or your can redirect to a new route e.g. `/home` which will send token cookies to your server
  }
}

@github-actions github-actions bot removed the pending-maintainer-response Issue is pending a response from the Amplify team. label Feb 12, 2025
@Ammar-Raneez
Copy link
Author

Ammar-Raneez commented Feb 13, 2025

I went ahead with the refreshing approach and handling the error of the sidebar - seems to be working fine for now ❤️ Thank you for your time!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Auth Related to Auth components/category Next.js question General question SSR Issues related to Server Side Rendering
Projects
None yet
Development

No branches or pull requests

3 participants