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

getCurrentUser won't work in Next js 14 #13183

Closed blackpatton17 closed 7 months ago

blackpatton17 commented 7 months ago

Before opening, please confirm:

JavaScript Framework

React, Next.js

Amplify APIs

Authentication

Amplify Version

v6

Amplify Categories

auth

Backend

Amplify CLI

Environment information

``` # Put output below this line UserUnAuthenticatedException: User needs to be authenticated to call this API. at assertAuthTokens (webpack-internal:///(rsc)/./node_modules/@aws-amplify/auth/dist/esm/providers/cognito/utils/types.mjs:26:15) at getCurrentUser (webpack-internal:///(rsc)/./node_modules/@aws-amplify/auth/dist/esm/providers/cognito/apis/internal/getCurrentUser.mjs:17:71) at async runWithAmplifyServerContext (webpack-internal:///(rsc)/./node_modules/aws-amplify/dist/esm/adapterCore/runWithAmplifyServerContext.mjs:23:24) at async GET (webpack-internal:///(rsc)/./src/app/apis/get-current-user/route.js:14:18) at async E:\violett\violett-m-unit-testing-application\node_modules\next\dist\compiled\next-server\app-route.runtime.dev.js:6:63809 at async eU.execute (E:\violett\violett-m-unit-testing-application\node_modules\next\dist\compiled\next-server\app-route.runtime.dev.js:6:53964) at async eU.handle (E:\violett\violett-m-unit-testing-application\node_modules\next\dist\compiled\next-server\app-route.runtime.dev.js:6:65062) at async doRender (E:\violett\violett-m-unit-testing-application\node_modules\next\dist\server\base-server.js:1333:42) at async cacheEntry.responseCache.get.routeKind (E:\violett\violett-m-unit-testing-application\node_modules\next\dist\server\base-server.js:1555:28) at async DevServer.renderToResponseWithComponentsImpl (E:\violett\violett-m-unit-testing-application\node_modules\next\dist\server\base-server.js:1463:28) at async DevServer.renderPageComponent (E:\violett\violett-m-unit-testing-application\node_modules\next\dist\server\base-server.js:1856:24) at async DevServer.renderToResponseImpl (E:\violett\violett-m-unit-testing-application\node_modules\next\dist\server\base-server.js:1894:32) at async DevServer.pipeImpl (E:\violett\violett-m-unit-testing-application\node_modules\next\dist\server\base-server.js:911:25) at async NextNodeServer.handleCatchallRenderRequest (E:\violett\violett-m-unit-testing-application\node_modules\next\dist\server\next-server.js:271:17) at async DevServer.handleRequestImpl (E:\violett\violett-m-unit-testing-application\node_modules\next\dist\server\base-server.js:807:17) at async E:\violett\violett-m-unit-testing-application\node_modules\next\dist\server\dev\next-dev-server.js:331:20 at async Span.traceAsyncFn (E:\violett\violett-m-unit-testing-application\node_modules\next\dist\trace\trace.js:151:20) at async DevServer.handleRequest (E:\violett\violett-m-unit-testing-application\node_modules\next\dist\server\dev\next-dev-server.js:328:24) at async invokeRender (E:\violett\violett-m-unit-testing-application\node_modules\next\dist\server\lib\router-server.js:163:21) at async handleRequest (E:\violett\violett-m-unit-testing-application\node_modules\next\dist\server\lib\router-server.js:342:24) at async requestHandlerImpl (E:\violett\violett-m-unit-testing-application\node_modules\next\dist\server\lib\router-server.js:366:13) at async Server.requestListener (E:\violett\violett-m-unit-testing-application\node_modules\next\dist\server\lib\start-server.js:140:13) { underlyingError: undefined, recoverySuggestion: 'Sign in before calling this API again.', constructor: [class AuthError extends AmplifyError] } { "name": "name", "version": "0.1.0", "private": true, "scripts": { "dev": "next dev", "build": "next build", "start": "next start", "lint": "next lint" }, "dependencies": { "@aws-amplify/adapter-nextjs": "^1.0.23", "@aws-amplify/ui-react": "^6.1.4", "@emotion/react": "^11.11.3", "@emotion/styled": "^11.11.0", "@mui/icons-material": "^5.15.10", "@mui/material": "^5.15.10", "@mui/x-data-grid": "^6.19.5", "aws-amplify": "^6.0.17", "jwt-decode": "^4.0.0", "next": "14.1.0", "react": "^18", "react-dom": "^18", "zustand": "^4.5.1" } } ```

Describe the bug

https://docs.amplify.aws/javascript/build-a-backend/server-side-rendering/nextjs/ The code in In Route Handlers section doesn't work. With a fetch operation, the route hanlder api can only throw error with UserUnAuthenticatedException

Expected behavior

Return correct current payload.

Reproduction steps

According to the doc, I create a route.js file under @/app/apis/get-current-user

import { getCurrentUser } from 'aws-amplify/auth/server';
import { cookies } from 'next/headers';
import { NextResponse } from 'next/server';
import { runWithAmplifyServerContext } from '@/utils/amplifyServerUtils';

export async function GET() {
  const user = await runWithAmplifyServerContext({
    nextServerContext: { cookies },
    operation: (contextSpec) => getCurrentUser(contextSpec)
  });

  return NextResponse.json({ user });
}

Also, I create amplifyServerUtils.js under @/utils

import { createServerRunner } from '@aws-amplify/adapter-nextjs';
import config from '@/amplifyconfiguration.json';

export const { runWithAmplifyServerContext } = createServerRunner({
  config
});

However, this function won't work with fetch('/apis/get-current-user') with an error

 UserUnAuthenticatedException: User needs to be authenticated to call this API.
    at assertAuthTokens (webpack-internal:///(rsc)/./node_modules/@aws-amplify/auth/dist/esm/providers/cognito/utils/types.mjs:26:15)
    at getCurrentUser (webpack-internal:///(rsc)/./node_modules/@aws-amplify/auth/dist/esm/providers/cognito/apis/internal/getCurrentUser.mjs:17:71)
    at async runWithAmplifyServerContext (webpack-internal:///(rsc)/./node_modules/aws-amplify/dist/esm/adapterCore/runWithAmplifyServerContext.mjs:23:24)
    at async GET (webpack-internal:///(rsc)/./src/app/apis/get-current-user/route.js:14:18)
    at async E:\violett\violett-m-unit-testing-application\node_modules\next\dist\compiled\next-server\app-route.runtime.dev.js:6:63809
    at async eU.execute (E:\violett\violett-m-unit-testing-application\node_modules\next\dist\compiled\next-server\app-route.runtime.dev.js:6:53964)
    at async eU.handle (E:\violett\violett-m-unit-testing-application\node_modules\next\dist\compiled\next-server\app-route.runtime.dev.js:6:65062)
    at async doRender (E:\violett\violett-m-unit-testing-application\node_modules\next\dist\server\base-server.js:1333:42)
    at async cacheEntry.responseCache.get.routeKind (E:\violett\violett-m-unit-testing-application\node_modules\next\dist\server\base-server.js:1555:28)
    at async DevServer.renderToResponseWithComponentsImpl (E:\violett\violett-m-unit-testing-application\node_modules\next\dist\server\base-server.js:1463:28)
    at async DevServer.renderPageComponent (E:\violett\violett-m-unit-testing-application\node_modules\next\dist\server\base-server.js:1856:24)
    at async DevServer.renderToResponseImpl (E:\violett\violett-m-unit-testing-application\node_modules\next\dist\server\base-server.js:1894:32)
    at async DevServer.pipeImpl (E:\violett\violett-m-unit-testing-application\node_modules\next\dist\server\base-server.js:911:25)
    at async NextNodeServer.handleCatchallRenderRequest (E:\violett\violett-m-unit-testing-application\node_modules\next\dist\server\next-server.js:271:17)
    at async DevServer.handleRequestImpl (E:\violett\violett-m-unit-testing-application\node_modules\next\dist\server\base-server.js:807:17)
    at async E:\violett\violett-m-unit-testing-application\node_modules\next\dist\server\dev\next-dev-server.js:331:20    
    at async Span.traceAsyncFn (E:\violett\violett-m-unit-testing-application\node_modules\next\dist\trace\trace.js:151:20)
    at async DevServer.handleRequest (E:\violett\violett-m-unit-testing-application\node_modules\next\dist\server\dev\next-dev-server.js:328:24)
    at async invokeRender (E:\violett\violett-m-unit-testing-application\node_modules\next\dist\server\lib\router-server.js:163:21)
    at async handleRequest (E:\violett\violett-m-unit-testing-application\node_modules\next\dist\server\lib\router-server.js:342:24)
    at async requestHandlerImpl (E:\violett\violett-m-unit-testing-application\node_modules\next\dist\server\lib\router-server.js:366:13)
    at async Server.requestListener (E:\violett\violett-m-unit-testing-application\node_modules\next\dist\server\lib\start-server.js:140:13) {
  underlyingError: undefined,
  recoverySuggestion: 'Sign in before calling this API again.',
  constructor: [class AuthError extends AmplifyError]        
}

The fetch has been called in below component

"use client";
import { useState, useEffect } from 'react'
import styles from "./page.module.css";
import { useRouter } from "next/navigation";
// import { withAdminProtect } from '@/utils/amplifyServerUtils';

function Admin() {
  const [user, setUser] = useState(null);
  const router = useRouter();

  useEffect(() => {
    fetch('/apis/get-current-user')
    .then(res => res.json())
    // setUser
  }, []);

  try {
    return (
      <main className={styles.main}>
        <p>{JSON.stringify(user)}</p>
      </main>
    )
  } catch {
    router.replace("/");
  }

}

export default Admin;

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

blackpatton17 commented 7 months ago

I would like to close the issue, but please re-write the doc to mark that developer shuold setup cookie storage as a pre-requiste for the ssr feature.

cwomack commented 7 months ago

Hey, @blackpatton17 👋. Glad you were able to unblock yourself, but feel free to suggest any documentation improvement we could make here on the docs repo. We'd love the input since you've recently gone through it!