amplify-js
amplify-js copied to clipboard
"No current user" error when calling graphql api endpoints in Next.js v14 project
Before opening, please confirm:
- [X] I have searched for duplicate or closed issues and discussions.
- [X] I have read the guide for submitting bug reports.
- [X] I have done my best to include a minimal, self-contained set of instructions for consistently reproducing the issue.
JavaScript Framework
Next.js
Amplify APIs
Authentication, GraphQL API
Amplify Version
v6
Amplify Categories
auth, api
Backend
Amplify CLI
Environment information
System:
OS: Windows 11 10.0.22631
CPU: (12) x64 12th Gen Intel(R) Core(TM) i5-12400F
Memory: 9.12 GB / 31.84 GB
Binaries:
Node: 20.10.0 - C:\Program Files\nodejs\node.EXE
Yarn: 1.22.21 - ~\AppData\Roaming\npm\yarn.CMD
npm: 10.2.3 - C:\Program Files\nodejs\npm.CMD
pnpm: 8.13.1 - ~\AppData\Roaming\npm\pnpm.CMD
Browsers:
Edge: Chromium (121.0.2277.112)
Internet Explorer: 11.0.22621.1
npmPackages:
@changesets/changelog-github: ^0.5.0 => 0.5.0
@changesets/cli: ^2.27.1 => 2.27.1
@commitlint/cli: ^18.4.3 => 18.4.3
@commitlint/config-conventional: ^18.4.3 => 18.4.3
@knocklabs/node: ^0.5.0 => 0.5.0
@repo/aws-types: workspace:^ => 0.1.0
@repo/prettier-config: workspace:^0.1.0 => 0.1.0
@repo/types: workspace:^ => 0.1.0
@segment/analytics-next: ^1.62.0 => 1.62.0
@segment/analytics-node: ^1.1.4 => 1.1.4
@turbo/gen: ^1.11.2 => 1.11.2
@types/node: ^20.10.5 => 20.10.5
chalk: ^5.3.0 => 5.3.0
husky: ^8.0.3 => 8.0.3
lint-staged: ^15.2.0 => 15.2.0
prettier: ^3.1.1 => 3.1.1
prompts: ^2.4.2 => 2.4.2
turbo: ^1.11.2 => 1.11.2
typescript: ^5.3.3 => 5.3.3
npmGlobalPackages:
@aws-amplify/cli: 12.0.3
@thejumba/auditable-transformer: 1.3.3
eas-cli: 6.1.0
pnpm: 8.13.1
vercel: 33.0.2
yarn: 1.22.21
Describe the bug
Recently, I've been getting this consistent error No current user
on our Next.js v14 application. It appears ever so randomly and always when trying to invoke the amplify GraphQL API from a server component. I've tried multiple solutions such as checking that Amplify.configure
or Auth.configure
is only called in one place and also checking for duplicate amplify version as described here.
Since the app is running on Amplify v6, there's a utility constant ssrClient
that is used to make all graphql api calls on server components as shown in the snippets below.
Expected behavior
The GraphQL API call should be made successfully without any errors being thrown
Reproduction steps
- Create a Next.js v14 application
- Setup amplify version 6
- Configure an amplify graphql api endpoint
- Setup SSR functionality for amplify
- Call said graphql api endpoint from a server component/server action using utilities provided from
aws-amplify/adapter-nextjs
package
Code Snippet
Amplify is configured in a file which exports a Providers
component that wraps everything else in the app in the root layout.tsx
// app/providers.tsx
"use client";
import { Amplify } from "aws-amplify";
import { parseAmplifyConfig } from "aws-amplify/utils";
import amplifyConfig from "@repo/aws-exports";
Amplify.configure(parseAmplifyConfig(amplifyConfig), { ssr: true });
// ... rest of code
We then have some utilities exported for amplify ssr interactions:
// @/lib/amplify-ssr.tsx
import { cookies } from "next/headers";
import { createServerRunner } from "@aws-amplify/adapter-nextjs";
import { generateServerClientUsingCookies } from "@aws-amplify/adapter-nextjs/api";
import { parseAmplifyConfig } from "aws-amplify/utils";
import config from "@repo/aws-exports";
export const ssrClient = generateServerClientUsingCookies({
cookies,
config: parseAmplifyConfig(config),
authMode: "userPool",
});
export const { runWithAmplifyServerContext } = createServerRunner({
config: parseAmplifyConfig(config),
});
And then we use the ssrClient
const res = await ssrClient.graphql({
query: "someQuery",
variables: {
// query variables
},
})
Log output
// Put your logs below this line
aws-exports.js
const awsmobile = {
"aws_appsync_authenticationType": "AMAZON_COGNITO_USER_POOLS",
"aws_appsync_graphqlEndpoint": "https://XXXXXXXXXXXXXX.appsync-api.us-east-1.amazonaws.com/graphql",
"aws_appsync_region": "us-east-1",
"aws_cognito_identity_pool_id": "us-east-1:XXXXXXXXXXXXXX",
"aws_cognito_mfa_configuration": "ON",
"aws_cognito_mfa_types": [
"SMS"
],
"aws_cognito_password_protection_settings": {
"passwordPolicyCharacters": [],
"passwordPolicyMinLength": 8
},
"aws_cognito_region": "us-east-1",
"aws_cognito_signup_attributes": [
"EMAIL",
"NAME",
"PHONE_NUMBER"
],
"aws_cognito_social_providers": [],
"aws_cognito_username_attributes": [
"PHONE_NUMBER"
],
"aws_cognito_verification_mechanisms": [
"PHONE_NUMBER"
],
"aws_project_region": "us-east-1",
"aws_user_files_s3_bucket": "XXXXXXXXXXXXXX",
"aws_user_files_s3_bucket_region": "us-east-1",
"aws_user_pools_id": "XXXXXXXXXXXXXX",
"aws_user_pools_web_client_id": "XXXXXXXXXXXXXX",
"oauth": {}
}
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
This is what keeps getting captured by sentry
Have you tried doing Amplify.configure(awsConfig) on both the client components and server components or are you already doing that?
According to the latest v6 docs,
Hi @ndaba1 👋 I was able to reproduce the "No current user" error when using the cookie based client on the server side. However, I realized that I had old credentials in Local Storage. I cleared them and then started getting Unauthorized errors.
I simply logged in again and was able to retrieve data with the userPool
auth mode again.
So, it seems this is reproducible if you have expired tokens (including refresh), preventing Amplify from refreshing the cognito access token and resulting in the "No current user" error.
Can you confirm that your credentials are not expired and that you are able to reproduce this issue with a recently logged in user?
This is the schema I had while reproducing (using Amplify Gen 2 to build the backend)
const schema = a.schema({
CommunityPost: a
.model({
title: a.string().required(),
poll: a.hasOne("CommunityPoll"),
})
.authorization([a.allow.private()]),
CommunityPoll: a
.model({
question: a.string().required(),
answers: a.hasMany("CommunityPollAnswer").arrayRequired().valueRequired(),
})
.authorization([a.allow.private()]),
CommunityPollAnswer: a
.model({
answer: a.string().required(),
votes: a.hasMany("CommunityPollVote").arrayRequired().valueRequired(),
})
.authorization([a.allow.private()]),
CommunityPollVote: a
.model({ name: a.string() })
.authorization([a.allow.private()]),
});
@chrisbonifacio thank you for taking the time to look into this. Yes, the issue occurs even for recently logged in users. To your point, I do think its related to the tokens not being refreshed correctly for whatever reason. Some users actually get randomly redirected to the sign in page when trying to access an SSR page(with RSC) but upon inputting credentials, the error "There is already a signed in user" is returned. And if you refresh the page, then you seem to be logged in again.
Since I am able to reproduce the issue, I marked this as a bug for the team to investigate further. Seems more auth related than GraphQL related.
To be more confident that we can reproduce it under the same conditions as your application, can you share more details about your auth resource such as the expiration for your tokens?
If you are building a Gen 1 Amplify app, using the Amplify CLI, you can also run the following command and provide us the project identifier in the output. This will let us recreate your exact auth resource.
amplify diagnose --send-report
Hey @chrisbonifacio
The project identifier is 1ce1eff4cf18e0517708247971fa723f
Hello, is there any feedback ? The issue is still persistent
Hi @ndaba1 By reading "It appears ever so randomly and always when trying to invoke the amplify GraphQL API from a server component" I suspect that the issue was caused by a failure of fetchAuthSession()
call internally triggered by .graphql()
. This failure is specifically Cognito Rate Limit error. Every fetchAuthSession
call in an isolated server context makes three different service calls. This is known and adjustable limitation from Cognito (See the callout in this section of documentation).
If you are using ssrClient
to make multiple GraphQL API calls within one Server Component on one incoming request, there is a way to optimize it.
In the meantime, we are actively exploring a better solution to make fetchAuthSession more efficient. In addition, we have improved error throwing from the GraphQL APIs, the error
object now contains a underlyingError
property. You may log this property to record the underlying error that caused No current user
or No federated jwt
errors, so you can confirm and determine whether you need to adjust Cognito quotas accordingly.
Hey @HuiSF , Thank you for your well detailed response. Let me try it then get back to you
@HuiSF we tried your suggested solution and unfortunately, it doesn't seem to work
import type { GraphQLOptionsV6 } from "@aws-amplify/api-graphql";
import { cookies } from "next/headers";
import { createServerRunner } from "@aws-amplify/adapter-nextjs";
import { generateClient } from "aws-amplify/api/server";
import { parseAmplifyConfig } from "aws-amplify/utils";
import awsExports from "@repo/aws-exports";
const config = parseAmplifyConfig(awsExports);
const client = generateClient({ config });
export const { runWithAmplifyServerContext } = createServerRunner({
config,
});
export const ssrClient = {
graphql: async <TQuery = unknown>(options: GraphQLOptionsV6<TQuery>) => {
const res = await runWithAmplifyServerContext({
nextServerContext: { cookies },
operation: async (contextSpec) => {
return client.graphql<TQuery>(contextSpec, {
query: options.query,
variables: options.variables,
authMode: options.authMode,
});
},
});
return res;
},
};
This is how we refactored the ssrClient
. Are we missing anything here ?
Hi @ndaba1 thanks for following up.
Looking at your implementation, it's actually no difference from calling runWithAmplifyServerContext()
multiple times in order to client.graphql()
in a context.
The above linked comment, suggested that to make multiple client.graphql()
within a single call of runWithAmplifyServerContext()
. Where the calls of client.graphql()
require creating the context only once.
Hey @HuiSF, thank you for getting back to me so quickly.
I think I see what you mean: The optimization can only be made for multiple GraphQL API calls made within the same incoming request for a server component but a new server context would still get created for any additional requests, right ? (Please correct me if I'm wrong)
And if that's the case, wouldn't still we risk running into the issue if there are a high number of concurrent requests for a server rendered page (from different users) ?
Also, would you kindly offer some more insights on which Cognito Service Quotas we'd try adjusting to help with this issue ? The callback in the docs doesn't specify which limits one would need to adjust. You mentioned
Every fetchAuthSession call in an isolated server context makes three different service calls.
but I'm not sure which service calls this would be
That's correct @ndaba1 the optimization was only for multiple GraphQL calls within one incoming request.
fetchAuthSession()
on the server side now requires InitiateAuth
(if client sent tokens are expired), GetId
and GetCredentialsForIdentity
these 3 service calls to assume a user session on the server side.
For your use case, I'd recommend first to monito the underlyingError
of No current user
or No federated jwt
errors to ensure they are caused by the rate limit.