amplify-js: Auth.currentAuthenticatedUser does not work in NextJs API routes

Before opening, please confirm:

JavaScript Framework

React, Next.js

Amplify APIs

Authentication

Amplify Categories

auth

Environment information

@aws-amplify/api: ^5.0.7 => 5.0.7 
@aws-amplify/auth: ^5.1.1 => 5.1.1 
@aws-amplify/core: ^5.0.7 => 5.0.7 
@aws-amplify/storage: ^5.0.7 => 5.0.7 

Describe the bug

The authenticated user is not returned in an API route, even though it is returned on client side and getServerSideProps

Expected behavior

When used as

export async function getServerSideProps(context) {
    const { API, Auth } = withSSRContext(context);

on a nextJs page, this works as expected. However, in API routes, it seems to return an error.

Reproduction steps

Set up a route in API/anyRoute.

Hit the API from nextJs client side.

See that the authenticated user is not returned.

Code Snippet

import { buffer } from "micro";
import Cors from "micro-cors";
import { NextApiRequest, NextApiResponse } from "next";
import { withSSRContext } from "aws-amplify";
import Amplify from "@aws-amplify/core";
import aws_exports from "@/aws_exports";

import Stripe from "stripe";
import { oauth, STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET } from "@/deploy_constants";
const stripe = new Stripe(STRIPE_SECRET_KEY, {
    // https://github.com/stripe/stripe-node#configuration
    apiVersion: "2020-08-27",
});

const webhookSecret: string = STRIPE_WEBHOOK_SECRET;
// Amplify SSR configuration needs to be enabled within each API route
Amplify.configure({
    ...aws_exports,
    oauth: {
        ...oauth,
    },
    ssr: true,
});
// Stripe requires the raw body to construct the event.
export const config = {
    api: {
        bodyParser: false,
    },
};

const cors = Cors({
    allowMethods: ["POST", "HEAD"],
});

const webhookHandler = async (req: NextApiRequest, res: NextApiResponse) => {
    console.log("REQ", req.cookies);
    const { Auth } = withSSRContext({ req });
    try {
        const user = await Auth.currentAuthenticatedUser();
        console.log("GOT", user);
    } catch (e) {
        console.log("ERERER", e);
    }
    if (req.method === "POST") {
        const buf = await buffer(req);
        const sig = req.headers["stripe-signature"]!;

        let event: Stripe.Event;

        try {
            event = stripe.webhooks.constructEvent(buf.toString(), sig, webhookSecret);
        } catch (err) {
            const errorMessage = err instanceof Error ? err.message : "Unknown error";
            // On error, log and return the error message.
            if (err! instanceof Error) console.log(err);
            console.log(`❌ Error message: ${errorMessage}`);
            res.status(400).send(`Webhook Error: ${errorMessage}`);
            return;
        }

        // Successfully constructed event.
        console.log("✅ Success:", event.id);

        // Cast event data to Stripe object.
        if (event.type === "invoice.payment_failed") {
            // TODO: grant user access until checkoutSession.expires_at
            const invoice = event.data.object as Stripe.Invoice;
            console.log(`❌ Payment failed:  ${invoice.subscription}`);
        } else if (event.type === "invoice.paid") {
            // TODO: grant user access until invoice.period_end
            const invoice = event.data.object as Stripe.Invoice;
            console.log(
                `💵 Paid successfully. ${invoice.subscription}: FROM ${invoice.period_start} TO ${invoice.period_end}`
            );
        } else {
            console.warn(`🤷‍♀️ Unhandled event type: ${event.type}`);
        }

        // Return a response to acknowledge receipt of the event.
        res.json({ received: true });
    } else {
        res.setHeader("Allow", "POST");
        res.status(405).end("Method Not Allowed");
    }
};

export default cors(webhookHandler as any);

Log output

REQ {}
ERERER The user is not authenticated

Seems like req.cookies are not set.

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

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Comments: 26 (12 by maintainers)

Most upvoted comments

bumping again as it is happening again for me.

On client side, all Auth calls work as expected, but from SSR,

SSR.Auth.currentAuthenticatedUser throws the error The user is not authenticated

The developer preview for v6 of Amplify has officially been released with improvements to SSR support and much more! Please check out our announcement and updated documentation to see what has changed.

This issue should be resolved within the dev preview and upcoming General Availability for Amplify v6, but let us know with a comment if there are further issues.

still occurring. next-js app router middleware. cannot use even with SSR enabled in Amplify config

I’m also seeing this in a Nextjs API route. I’ve configured Amplify with:

import awsConfig from 'src/aws-exports';
Amplify.configure({ ...awsConfig, ssr: true });

but I’m still seeing unauthenticated credentials:

{
  identityId: '...',
  accessKeyId: '...',
  secretAccessKey: '...',
  sessionToken: '...',
  expiration: 2023-07-05T16:10:59.000Z,
  authenticated: false
}

I had the same issue. After hours of debugging, we found that we have two places of code where Auth.configure was called differently.

In one route (with usage of getServerSideProps):

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

In another (where we used only client side):

Auth.configure({ ...authConfig.Auth });

After adding ssr: true into the second case, it resolved the problem. The issue was not reproducible on local dev env with next.js. Only the production version had this issue. I assume it is somehow related to page preloading in nextjs.

I’m getting this also when using server side components with the new app router that is about to be released.

Here’s the code I’m using

import "@aws-amplify/ui-react/styles.css";

import { Amplify, Auth } from "aws-amplify";
import { redirect } from "next/navigation";

import awsExports from "../../aws-exports";

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

export const metadata = {
  title: "Create Next App",
  description: "Generated by create next app",
};

async function checkAuth() {
  try {
    const user = await Auth.currentAuthenticatedUser();
    console.log(user);

    return true;
  } catch (e) {}

  return false;
}

export default async function ShowcaseLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  const isAuthenticated = await checkAuth();

  if (!isAuthenticated) {
    redirect("/login");
  }

  return children;
}

and the logs when it fails.

error - node_modules/@aws-amplify/auth/lib/OAuth/oauthStorage.js (6:0) @ exports.setState
error - unhandledRejection: Error [ReferenceError]: window is not defined
    at exports.setState (webpack-internal:///(sc_client)/./node_modules/@aws-amplify/auth/lib/OAuth/oauthStorage.js:6:5)
    at OAuth.oauthSignIn (webpack-internal:///(sc_client)/./node_modules/@aws-amplify/auth/lib/OAuth/OAuth.js:46:22)
    at AuthClass.eval (webpack-internal:///(sc_client)/./node_modules/@aws-amplify/auth/lib/Auth.js:2184:48)
    at step (webpack-internal:///(sc_client)/./node_modules/@aws-amplify/auth/node_modules/tslib/tslib.es6.js:126:23)
    at Object.eval [as next] (webpack-internal:///(sc_client)/./node_modules/@aws-amplify/auth/node_modules/tslib/tslib.es6.js:107:53)
    at eval (webpack-internal:///(sc_client)/./node_modules/@aws-amplify/auth/node_modules/tslib/tslib.es6.js:100:71)
    at new Promise (<anonymous>)
    at Module.__awaiter (webpack-internal:///(sc_client)/./node_modules/@aws-amplify/auth/node_modules/tslib/tslib.es6.js:96:12)
    at AuthClass.federatedSignIn (webpack-internal:///(sc_client)/./node_modules/@aws-amplify/auth/lib/Auth.js:2150:24)
    at Login (webpack-internal:///(sc_client)/./src/app/login/page.tsx:17:51)
    at renderWithHooks (/local/home/woolumc/scratch/test2/test/node_modules/next/dist/compiled/react-dom/cjs/react-dom-server.browser.development.js:8367:16)
    at renderIndeterminateComponent (/local/home/woolumc/scratch/test2/test/node_modules/next/dist/compiled/react-dom/cjs/react-dom-server.browser.development.js:8441:15)
    at renderElement (/local/home/woolumc/scratch/test2/test/node_modules/next/dist/compiled/react-dom/cjs/react-dom-server.browser.development.js:8676:7)
    at renderLazyComponent (/local/home/woolumc/scratch/test2/test/node_modules/next/dist/compiled/react-dom/cjs/react-dom-server.browser.development.js:8656:3)
    at renderElement (/local/home/woolumc/scratch/test2/test/node_modules/next/dist/compiled/react-dom/cjs/react-dom-server.browser.development.js:8766:11)
    at renderNodeDestructiveImpl (/local/home/woolumc/scratch/test2/test/node_modules/next/dist/compiled/react-dom/cjs/react-dom-server.browser.development.js:8843:11)
    at renderNodeDestructive (/local/home/woolumc/scratch/test2/test/node_modules/next/dist/compiled/react-dom/cjs/react-dom-server.browser.development.js:8815:14)
    at renderNode (/local/home/woolumc/scratch/test2/test/node_modules/next/dist/compiled/react-dom/cjs/react-dom-server.browser.development.js:9020:12)
    at renderChildrenArray (/local/home/woolumc/scratch/test2/test/node_modules/next/dist/compiled/react-dom/cjs/react-dom-server.browser.development.js:8972:7)
    at renderNodeDestructiveImpl (/local/home/woolumc/scratch/test2/test/node_modules/next/dist/compiled/react-dom/cjs/react-dom-server.browser.development.js:8880:7)
    at renderNodeDestructive (/local/home/woolumc/scratch/test2/test/node_modules/next/dist/compiled/react-dom/cjs/react-dom-server.browser.development.js:8815:14)
    at renderContextProvider (/local/home/woolumc/scratch/test2/test/node_modules/next/dist/compiled/react-dom/cjs/react-dom-server.browser.development.js:8640:3)
    at renderElement (/local/home/woolumc/scratch/test2/test/node_modules/next/dist/compiled/react-dom/cjs/react-dom-server.browser.development.js:8754:11)
    at renderNodeDestructiveImpl (/local/home/woolumc/scratch/test2/test/node_modules/next/dist/compiled/react-dom/cjs/react-dom-server.browser.development.js:8843:11)
    at renderNodeDestructive (/local/home/woolumc/scratch/test2/test/node_modules/next/dist/compiled/react-dom/cjs/react-dom-server.browser.development.js:8815:14)
    at finishClassComponent (/local/home/woolumc/scratch/test2/test/node_modules/next/dist/compiled/react-dom/cjs/react-dom-server.browser.development.js:8397:3)
    at renderClassComponent (/local/home/woolumc/scratch/test2/test/node_modules/next/dist/compiled/react-dom/cjs/react-dom-server.browser.development.js:8405:3)
    at renderElement (/local/home/woolumc/scratch/test2/test/node_modules/next/dist/compiled/react-dom/cjs/react-dom-server.browser.development.js:8673:7)
    at renderNodeDestructiveImpl (/local/home/woolumc/scratch/test2/test/node_modules/next/dist/compiled/react-dom/cjs/react-dom-server.browser.development.js:8843:11)
    at renderNodeDestructive (/local/home/woolumc/scratch/test2/test/node_modules/next/dist/compiled/react-dom/cjs/react-dom-server.browser.development.js:8815:14)
    at renderIndeterminateComponent (/local/home/woolumc/scratch/test2/test/node_modules/next/dist/compiled/react-dom/cjs/react-dom-server.browser.development.js:8495:7)
    at renderElement (/local/home/woolumc/scratch/test2/test/node_modules/next/dist/compiled/react-dom/cjs/react-dom-server.browser.development.js:8676:7)
    at renderNodeDestructiveImpl (/local/home/woolumc/scratch/test2/test/node_modules/next/dist/compiled/react-dom/cjs/react-dom-server.browser.development.js:8843:11)
    at renderNodeDestructive (/local/home/woolumc/scratch/test2/test/node_modules/next/dist/compiled/react-dom/cjs/react-dom-server.browser.development.js:8815:14)
    at finishClassComponent (/local/home/woolumc/scratch/test2/test/node_modules/next/dist/compiled/react-dom/cjs/react-dom-server.browser.development.js:8397:3)
    at renderClassComponent (/local/home/woolumc/scratch/test2/test/node_modules/next/dist/compiled/react-dom/cjs/react-dom-server.browser.development.js:8405:3)
    at renderElement (/local/home/woolumc/scratch/test2/test/node_modules/next/dist/compiled/react-dom/cjs/react-dom-server.browser.development.js:8673:7)
    at renderNodeDestructiveImpl (/local/home/woolumc/scratch/test2/test/node_modules/next/dist/compiled/react-dom/cjs/react-dom-server.browser.development.js:8843:11)
    at renderNodeDestructive (/local/home/woolumc/scratch/test2/test/node_modules/next/dist/compiled/react-dom/cjs/react-dom-server.browser.development.js:8815:14)
    at renderIndeterminateComponent (/local/home/woolumc/scratch/test2/test/node_modules/next/dist/compiled/react-dom/cjs/react-dom-server.browser.development.js:8495:7)
    at renderElement (/local/home/woolumc/scratch/test2/test/node_modules/next/dist/compiled/react-dom/cjs/react-dom-server.browser.development.js:8676:7)
    at renderNodeDestructiveImpl (/local/home/woolumc/scratch/test2/test/node_modules/next/dist/compiled/react-dom/cjs/react-dom-server.browser.development.js:8843:11)
    at renderNodeDestructive (/local/home/woolumc/scratch/test2/test/node_modules/next/dist/compiled/react-dom/cjs/react-dom-server.browser.development.js:8815:14)
    at renderElement (/local/home/woolumc/scratch/test2/test/node_modules/next/dist/compiled/react-dom/cjs/react-dom-server.browser.development.js:8702:9)
    at renderNodeDestructiveImpl (/local/home/woolumc/scratch/test2/test/node_modules/next/dist/compiled/react-dom/cjs/react-dom-server.browser.development.js:8843:11)
    at renderNodeDestructive (/local/home/woolumc/scratch/test2/test/node_modules/next/dist/compiled/react-dom/cjs/react-dom-server.browser.development.js:8815:14)
    at renderIndeterminateComponent (/local/home/woolumc/scratch/test2/test/node_modules/next/dist/compiled/react-dom/cjs/react-dom-server.browser.development.js:8495:7)
    at renderElement (/local/home/woolumc/scratch/test2/test/node_modules/next/dist/compiled/react-dom/cjs/react-dom-server.browser.development.js:8676:7)
    at renderNodeDestructiveImpl (/local/home/woolumc/scratch/test2/test/node_modules/next/dist/compiled/react-dom/cjs/react-dom-server.browser.development.js:8843:11)
    at renderNodeDestructive (/local/home/woolumc/scratch/test2/test/node_modules/next/dist/compiled/react-dom/cjs/react-dom-server.browser.development.js:8815:14) {
  digest: undefined
}

I am having the same problem as well.

The authentication works fine on the client-side, but as soon as any page is redirected after a successful authentication and the SSR enters in action, the user is undefined.

dependency:

 "dependencies": {
    "@aws-amplify/cache": "^5.0.16",
    "@aws-amplify/ui-react": "^4.3.8",
   
    "@types/aws-lambda": "^8.10.82",
    "@vendia/serverless-express": "^4.3.11",
    "aws-amplify": "^5.0.16",
    "aws-lambda": "^1.0.6",
    "react": "^17.0.2",

  }

_app.js


Amplify.configure(
  ssr: true,
  Auth: {
    region: 'eu-west-2',
    userPoolId: process.env.NEXT_PUBLIC_USER_POOL_ID,
    userPoolWebClientId: process.env.NEXT_PUBLIC_USER_POOL_WEB_CLIENT_ID,
    mandatorySignIn: true,
    authenticationFlowType: 'USER_PASSWORD_AUTH',
  },
});

internal page:

export async function getServerSideProps(context: GetServerSidePropsContext): Promise<void | any> {
  const { Auth } = withSSRContext(context);

  //Auth.configure(authConfiguration.Auth);
  let user;
  try {
    console.log('will get the use');
    user = await Auth.currentAuthenticatedUser();
  } catch (err) {
    console.log('🚀 ~ file: auth.helpers.tsx:16 ~ serverSideRedirectNoAuth ~ err:', err);
  }

  if (!user) {
    return {
      redirect: {
        permanent: false,
        destination: `/login`,
      },
    };
  }

  return { props: {} };
}

Same issue

@nadetastic Also one more thing, calling API.graphql (from SSR) from seems to also return an Error: No current user, even though

import { withSSRContext } from "aws-amplify";

export async function getServerSideProps(context) {
    const { API, Auth } = withSSRContext(context);
    
    // runs successfully, prints all data
    console.log(await Auth.currentAuthenticatedUser());
    console.log(await Auth.currentSession());
    
    // throws error 
    API.graphql({
            query: gql(getCurrentUser),
            variables: {
                input: {
                    userId,
                },
            },
            limit: 1000,
            authMode: "AMAZON_COGNITO_USER_POOLS"
        });
}

both console logs work properly, but calling the API throws the errors