amplify-js: Error: "No Credentials" on GraphQL Request Via Amplify in NextJs 14 (with App Router) SSR for Stripe Webhook
Before opening, please confirm:
- I have searched for duplicate or closed issues and discussions.
- I have read the guide for submitting bug reports.
- 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
api
Backend
Amplify CLI
Environment information
# Put output below this line
System:
OS: macOS 13.6
CPU: (10) arm64 Apple M1 Pro
Memory: 839.03 MB / 32.00 GB
Shell: 5.9 - /bin/zsh
Binaries:
Node: 16.14.2 - ~/.nvm/versions/node/v16.14.2/bin/node
Yarn: 1.22.18 - ~/.nvm/versions/node/v16.14.2/bin/yarn
npm: 9.6.7 - ~/.nvm/versions/node/v16.14.2/bin/npm
Browsers:
Chrome: 120.0.6099.234
Safari: 17.0
npmPackages:
@ampproject/toolbox-optimizer: undefined ()
@apollo/client: ^3.8.8 => 3.8.8
@apollo/client/cache: undefined ()
@apollo/client/core: undefined ()
@apollo/client/dev: undefined ()
@apollo/client/errors: undefined ()
@apollo/client/link/batch: undefined ()
@apollo/client/link/batch-http: undefined ()
@apollo/client/link/context: undefined ()
@apollo/client/link/core: undefined ()
@apollo/client/link/error: undefined ()
@apollo/client/link/http: undefined ()
@apollo/client/link/persisted-queries: undefined ()
@apollo/client/link/remove-typename: undefined ()
@apollo/client/link/retry: undefined ()
@apollo/client/link/schema: undefined ()
@apollo/client/link/subscriptions: undefined ()
@apollo/client/link/utils: undefined ()
@apollo/client/link/ws: undefined ()
@apollo/client/react: undefined ()
@apollo/client/react/components: undefined ()
@apollo/client/react/context: undefined ()
@apollo/client/react/hoc: undefined ()
@apollo/client/react/hooks: undefined ()
@apollo/client/react/parser: undefined ()
@apollo/client/react/ssr: undefined ()
@apollo/client/testing: undefined ()
@apollo/client/testing/core: undefined ()
@apollo/client/utilities: undefined ()
@apollo/client/utilities/globals: undefined ()
@aws-amplify/adapter-nextjs: ^1.0.10 => 1.0.10
@aws-amplify/adapter-nextjs/api: undefined ()
@aws-amplify/adapter-nextjs/data: undefined ()
@babel/core: undefined ()
@babel/runtime: 7.22.5
@chakra-ui/icons: ^2.1.1 => 2.1.1
@chakra-ui/react: ^2.8.2 => 2.8.2
@edge-runtime/cookies: 4.0.2
@edge-runtime/ponyfill: 2.4.1
@edge-runtime/primitives: 4.0.2
@emotion/react: ^11.11.3 => 11.11.3
@emotion/styled: ^11.11.0 => 11.11.0
@hapi/accept: undefined ()
@mswjs/interceptors: undefined ()
@napi-rs/triples: undefined ()
@next/font: undefined ()
@next/react-dev-overlay: undefined ()
@opentelemetry/api: undefined ()
@segment/ajv-human-errors: undefined ()
@stripe/react-stripe-js: ^2.4.0 => 2.4.0
@stripe/stripe-js: ^2.3.0 => 2.3.0
@types/node: ^20 => 20.10.6
@types/react: ^18 => 18.2.46
@types/react-dom: ^18 => 18.2.18
@vercel/nft: undefined ()
@vercel/og: 0.5.15
acorn: undefined ()
amphtml-validator: undefined ()
anser: undefined ()
apollo-link: ^1.2.14 => 1.2.14 (1.2.5)
apollo-link-http: ^1.5.17 => 1.5.17 (1.5.8)
arg: undefined ()
assert: undefined ()
async-retry: undefined ()
async-sema: undefined ()
aws-amplify: ^6.0.10 => 6.0.10
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/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 ()
aws-appsync: ^4.1.9 => 4.1.9
babel-packages: undefined ()
browserify-zlib: undefined ()
browserslist: undefined ()
buffer: undefined ()
bytes: undefined ()
ci-info: undefined ()
cli-select: undefined ()
client-only: 0.0.1
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 ()
data-uri-to-buffer: undefined ()
debug: undefined ()
devalue: undefined ()
domain-browser: undefined ()
edge-runtime: undefined ()
eslint: ^8 => 8.56.0
eslint-config-next: 14.0.4 => 14.0.4
events: undefined ()
find-cache-dir: undefined ()
find-up: undefined ()
framer-motion: ^10.17.9 => 10.17.9
fresh: undefined ()
get-orientation: undefined ()
glob: undefined ()
gzip-size: undefined ()
http-proxy: undefined ()
http-proxy-agent: undefined ()
https-browserify: undefined ()
https-proxy-agent: undefined ()
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 ()
loader-runner: undefined ()
loader-utils: undefined ()
lodash.curry: undefined ()
lru-cache: undefined ()
micromatch: undefined ()
mini-css-extract-plugin: undefined ()
nanoid: undefined ()
native-url: undefined ()
neo-async: undefined ()
next: 14.0.4 => 14.0.4
node-fetch: undefined ()
node-html-parser: undefined ()
ora: undefined ()
os-browserify: undefined ()
p-limit: undefined ()
path-browserify: undefined ()
platform: undefined ()
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 ()
process: undefined ()
punycode: undefined ()
querystring-es3: undefined ()
raw-body: undefined ()
react: ^18 => 18.2.0
react-builtin: undefined ()
react-dom: ^18 => 18.2.0
react-dom-builtin: undefined ()
react-dom-experimental-builtin: undefined ()
react-experimental-builtin: undefined ()
react-icons: ^4.12.0 => 4.12.0
react-is: 18.2.0
react-refresh: 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 ()
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 ()
stacktrace-parser: undefined ()
stream-browserify: undefined ()
stream-http: undefined ()
string-hash: undefined ()
string_decoder: undefined ()
strip-ansi: undefined ()
stripe: ^14.12.0 => 14.12.0
superstruct: undefined ()
tar: undefined ()
terser: undefined ()
text-table: undefined ()
timers-browserify: undefined ()
tty-browserify: undefined ()
typescript: ^5 => 5.3.3
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.10.0
apollo: 2.34.0
avo: 3.2.1
corepack: 0.10.0
graphql: 16.6.0
n: 9.2.0
npm: 9.6.7
yarn: 1.22.18
Describe the bug
I’m trying to setup a route.ts to listen for Stripe webhooks then make a graphql request to log details of the transaction in dynamo db. I’ve tried many different approaches following fragments of the Amplify documentation, although I can’t find any docs that seem to follow this exact use case? Some of the docs refer to the old NextApiResponse as opposed to the NextResponse in the App Router approach.
It sounds like “cookies” from next/header is suppose to include the auth information, but how should this be passed in the graphql query? My cookies are always nil in this ssr route. I’m setting the “ssr” to true when I configure amplify in my layout.tsx.
Help greatly appreciated! Should it be possible to use Amplify with Next 14?
Expected behavior
The most basic functionality of a graphql query to work and be documented.
Reproduction steps
I can use the Stripe CLI tool to trigger the payment_intent.succeeded. My code executes but the graphql query fails with the error “No Credentials”.
Code Snippet
// Put your code below this line.
import { NextRequest, NextResponse } from "next/server";
import Stripe from 'stripe';
// import { generateClient } from 'aws-amplify/api';
import { createTransaction } from '../../../graphql/mutations';
import { TransactionInput } from '../../../graphql/API';
// Amplify ssr
import { runWithAmplifyServerContext } from '../../../utils/amplifyServerUtils';
import { generateServerClientUsingCookies } from '@aws-amplify/adapter-nextjs/api';
import { cookies } from 'next/headers';
import amplifyConfig from '../../../deployment/amplify-config';
// TODO: put in utils
export const cookieBasedClient = generateServerClientUsingCookies({
config: amplifyConfig,
cookies
});
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
// @ts-ignore
apiVersion: '2022-11-15',
});
export async function POST(req: NextRequest) {
if (req.method !== 'POST') {
return new NextResponse(JSON.stringify({ error: 'Method not allowed' }), {
status: 405,
headers: {
'Content-Type': 'application/json',
},
});
}
// Cookie debug
const rawCookies = req.headers.get('cookie');
console.log('Raw Cookie String:', rawCookies);
const sig = req.headers.get('stripe-signature');
let event;
try {
const body = await readRawBody(req);
event = stripe.webhooks.constructEvent(body, sig!, process.env.STRIPE_WEBHOOK_SECRET!);
} catch (err: any) {
return new NextResponse(JSON.stringify({ error: `Webhook Error: ${err.message}` }), {
status: 400,
headers: {
'Content-Type': 'application/json',
},
});
}
switch (event.type) {
case 'charge.succeeded':
console.log('Handling charge.succeeded');
break;
case 'payment_intent.created':
console.log('Handling payment_intent.created');
break;
case 'payment_intent.canceled':
console.log('Handling payment_intent.canceled');
break;
case 'payment_intent.succeeded':
console.log('Handling payment_intent.succeeded');
const paymentIntentSucceeded = event.data.object as Stripe.PaymentIntent;
console.log('paymentIntentSucceeded = ', paymentIntentSucceeded);
const transactionInput: TransactionInput = {
transactionId: paymentIntentSucceeded.id,
userId: '1234', // TODO: get this
amount: paymentIntentSucceeded.amount,
currency: paymentIntentSucceeded.currency,
timestamp: new Date().toISOString(),
status: paymentIntentSucceeded.status,
paymentIntentId: paymentIntentSucceeded.id,
priceId: 'priceId', // TODO: set this
};
console.log('cookies = ', cookies().getAll());
try {
const result = await runWithAmplifyServerContext({
nextServerContext: { cookies },
operation: () =>
cookieBasedClient.graphql({
query: createTransaction,
variables: {
transaction: transactionInput
},
}),
});
console.log("createTransaction result transactionId = ", result.data.createTransaction?.transactionId);
} catch (error) {
console.log("createTransaction failed with error: ", error);
}
break;
default:
console.log('Unhandled Stripe webhook event type:', event.type);
break;
}
return new NextResponse(JSON.stringify({ received: true }), {
status: 200,
headers: {
'Content-Type': 'application/json',
},
});
}
// Helper function to read raw request body
async function readRawBody(req: NextRequest): Promise<string> {
if (!req.body) {
throw new Error("Request body is null");
}
const reader = req.body.getReader();
let receivedValue = '';
let done = false;
while (!done) {
const { value, done: readerDone } = await reader.read();
done = readerDone;
if (value) {
receivedValue += new TextDecoder().decode(value, { stream: true });
}
}
return receivedValue;
}
Log output
// Put your logs below this line
aws-exports.js
No response
Manual configuration
const amplifyConfig: ResourcesConfig = {
Auth: {
Cognito: {
userPoolClientId: config.USER_POOL_CLIENT_ID,
userPoolId: config.USER_POOL_ID,
loginWith: { // Optional
oauth: {
domain: 'https://my_domain.auth.us-east-1.amazoncognito.com',
scopes: ['email', 'openid', 'aws.cognito.signin.user.admin'],
redirectSignIn: [config.REDIRECT_SIGN_IN],
redirectSignOut: [config.REDIRECT_SIGN_OUT],
responseType: 'code',
},
username: true, // note: username is their email
email: false, // Optional
phone: false, // Optional
}
}
},
API: {
GraphQL: {
endpoint: config.GRAPHQL_ENDPOINT,
defaultAuthMode: 'iam',
region: config.REGION, // Optional
}
},
};
export default amplifyConfig;
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 5 months ago
- Reactions: 2
- Comments: 25 (12 by maintainers)
Yes, it works nice @chrisbonifacio . Thanks.
I’ve test that in server-side and it works OK.
Based on the testing with the stack that @jojemapa provided, this is a bug that using
iamauth mode is not working as expected on the server side. We are currently working on a fix.Hi, i use Amplkify CLI.
amplify add auth amplidy add api
in my schema i just put allow: private and provider: iam.
The last part amplify add the iam permission to appsync in the auth role.
mmm, i finally i get that error, i still searching for a fix.