Closed bluetoken-luke closed 10 months ago
So been digging into this as we badly want this feature. What I have found is that in the networkMonitor in Reachability there is a check for if this is running in node (which being on the server it should be). However, that check is coming back false. This allows the networkMonitor to continue on in its code thinking presumably its in a browser. isWebWorker() winds up returning false which makes the globalObj window which then doesn't exist on the server.
So went looking for why this isNode call is coming back false. Looking at browserOrNode() it is checking the node version in process in order to determine if this is node on the server. However process.versions is empty when running the middleware (it is not when running gSSP).
This seems to be the cause of the window undefined error seen above when using amplify in nextjs middleware. Im uncertain on if the fix should be on amplify's end or next's. It feels like next should probably be setting that version. But unsure. Im doing all I can to try and work around this without having to fork amplify and make changes but without being able to modify whats in process, its looking bleak.
Very interesting. I ran into the same problem and couldn't understand why the function for node required a window, but your pursuit has cleared up that question for me.
The sandbox for running Next.js middleware is quite limited in its functionality (probably to ensure the performance of running Edge), so I hope that amplify will change its implementation to one that does not depend on process.versions.
Incidentally, I temporarily work around this problem by decoding the token (JWT) on the cookie directly.
https://github.com/aiji42/next-fortress/blob/main/src/cognito.ts https://github.com/aiji42/next-fortress#control-by-amazon-cognito
Very interesting. I ran into the same problem and couldn't understand why the function for node required a window, but your pursuit has cleared up that question for me.
The sandbox for running Next.js middleware is quite limited in its functionality (probably to ensure the performance of running Edge), so I hope that amplify will change its implementation to one that does not depend on process.versions.
Incidentally, I temporarily work around this problem by decoding the token (JWT) on the cookie directly.
https://github.com/aiji42/next-fortress/blob/main/src/cognito.ts https://github.com/aiji42/next-fortress#control-by-amazon-cognito
Thank you for this. It helped become the base of us being able to work around this for now.
@chrisbonifacio any updates over this ?
I am experiencing this issue as well.
I was able to get withSSRContext
working fine in getServerSideProps
but I can't use it with middleware because of no window
.
@chrisbonifacio any updates / solutions found?
+1, would like to see a solution here. At the moment, I'm toying with the idea of saving the id token to a cookie upon login and parsing the token in the middleware. Seems like a hacky alternative to the solution provided in this document.
Instead, I get this:
event - compiled client and server successfully in 292 ms (3660 modules)
wait - compiling /portal...
event - compiled client and server successfully in 253 ms (3668 modules)
error - node_modules/@aws-amplify/core/lib-esm/Util/Reachability.js (21:0) @ <unknown>
ReferenceError: window is not defined
+1 , being able to use the new NextJS middleware with Amplify Auth without workarounds will be really great.
I had the same problem and next-fortress didn't quite do that trick for me, but I was able to take some of their code to create the solution below.
// _middleware.js
import { NextResponse } from 'next/server';
import { decodeProtectedHeader, importJWK, jwtVerify } from 'jose';
// Middleware that prevents unauthenticated users from accessing protected resources
async function handler(req) {
const url = req.nextUrl.clone();
try {
// Define paths that don't require authentication
const unauthenticatedPaths = [
'/',
'/login',
'/password-reset',
'/pricing',
'/signup',
'/support',
];
// Allow users to continue for pages that don't require authentication
if (unauthenticatedPaths.includes(url.pathname)) {
return NextResponse.next();
} else {
// Authenticate users for protected resources
// Cognito data
const region = process.env.AWS_REGION;
const poolId = process.env.AWS_COGNITO_USER_POOL_ID;
const clientId = process.env.AWS_USER_POOLS_WEB_CLIENT_ID;
// Get the user's token
const token = Object.entries(req.cookies).find(([key]) =>
new RegExp(
`CognitoIdentityServiceProvider\\.${clientId}\\..+\\.idToken`
).test(key)
)?.[1];
if (token) {
// Get keys from AWS
const { keys } = await fetch(
`https://cognito-idp.${region}.amazonaws.com/${poolId}/.well-known/jwks.json`
).then((res) => res.json());
// Decode the user's token
const { kid } = decodeProtectedHeader(token);
// Find the user's decoded token in the Cognito keys
const jwk = keys.find((key) => key.kid === kid);
if (jwk) {
// Import JWT using the JWK
const jwtImport = await importJWK(jwk);
// Verify the users JWT
const jwtVerified = await jwtVerify(token, jwtImport)
.then((res) => res.payload.email_verified)
.catch(() => failedToAuthenticate);
// Allow verified users to continue
if (jwtVerified) return NextResponse.next();
}
}
}
} catch (err) {
console.log('err', err);
}
// Send 401 when an unauthenticated user trys to access API endpoints
if (url.pathname.includes('api')) {
return new Response('Auth required', { status: 401 });
} else {
// Redirect unauthenticated users to the login page when they attempt to access protected pages
return NextResponse.redirect(`${url.origin}/login`);
}
}
export default handler;
Unfortunately, still no updates on this one. We don't officially support Next.js 12 and its new features such as middleware yet.
Is there an update available?
I am also looking forward to the update.
Hi there, any updates? We'd love to use Next 12 and their middleware.
Regards,
+1
Hello everyone, we are currently exploring what it would take for our Auth category for Amplify to function consistently with NextJS 12 Middleware. We will update this issue when we have more feedback!
@abdallahshaban557, thanks for the update. So this means the Amplify team is looking into officially supporting NextJS 12? Or are you just looking at the "Auth in Middleware" part right now? Just asking, because there is also this issue which includes more blockers as far as I know: https://github.com/aws-amplify/amplify-hosting/issues/2343 Does the AWS/Amplify internally discuss how to proceed with Next.js support and updates in the future? I'd be really nice to have a bit more clarification here (e.g. it would also be nice to use NextJS 12 support sooner for people who don't need middleware; what will be the strategy for v13; will there ever be an AWS-official CDK construct, etc.).
@donaldpipowitch - these are exactly the types of conversation we are having internally! I would love to have a conversation with you to dive deeper into the different features of NextJS that we should support. Can you please send me an email to awshaban@amazon.com so that I can setup time for us to discuss this further?
Thank you very much for your response. I'll do this 🥰
Middleware feature is a must have! I can't afford to put redirect code in every single page And I can't afford to put the redirect code in client side
I hope this gets supported soon.
Thank you for the feedback @Sodj! We understand this is an important feature for developers using NextJS v12.
Any update on this ?!
Using Next 12.2.3
Using withSSRContext
in middleware:
export const middleware: NextMiddleware = async (req, evt) => {
const { Auth } = withSSRContext({ req })
let data
let user
try {
user = await Auth.currentAuthenticatedUser()
console.log("user is authenticated")
console.log(user)
} catch (err) {
console.log("error: no authenticated user")
return redirecter(req, evt)
}
}
I am getting the following error:
error - Error: The edge runtime does not support Node.js 'buffer' module.
Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime
at <unknown> (webpack-internal:///(middleware)/../../node_modules/next/dist/server/web/adapter.js:156)
at Object.get (webpack-internal:///(middleware)/../../node_modules/next/dist/server/web/adapter.js:156:19)
at eval (webpack-internal:///(middleware)/../../node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/@aws-crypto/util/build/convertToBuffer.js:9:56)
at Object.(middleware)/../../node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/@aws-crypto/util/build/convertToBuffer.js (evalmachine.<anonymous>:7245:1)
at __webpack_require__ (evalmachine.<anonymous>:37:33)
at fn (evalmachine.<anonymous>:281:21)
at eval (webpack-internal:///(middleware)/../../node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/@aws-crypto/util/build/index.js:6:25)
at Object.(middleware)/../../node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/@aws-crypto/util/build/index.js (evalmachine.<anonymous>:7256:1)
at __webpack_require__ (evalmachine.<anonymous>:37:33)
at fn (evalmachine.<anonymous>:281:21)
at eval (webpack-internal:///(middleware)/../../node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/@aws-crypto/sha256-browser/build/webCryptoSha256.js:4:14) {
middleware: true
✗ npm ls @aws-sdk/client-cloudwatch-logs
platform@1.1.1 /Users/cyber/dev/platform
└─┬ frontend@0.5.0 -> ./packages/frontend
└─┬ @aws-amplify/core@4.5.10
└── @aws-sdk/client-cloudwatch-logs@3.6.1
It appears client-cloudwatch-logs uses buffer
from Nodejs which vercel presumably does not support in their edge function API
Another error I get:
info - Creating an optimized production build
Failed to compile.
../../node_modules/@aws-amplify/core/lib-esm/JS.js
Dynamic Code Evaluation (e. g. 'eval', 'new Function', 'WebAssembly.compile') not allowed in Edge Runtime
Import trace for requested module:
../../node_modules/@aws-amplify/core/lib-esm/index.js
../../node_modules/aws-amplify/lib-esm/index.js
./src/middleware.ts
../../node_modules/@aws-amplify/datastore/node_modules/immer/dist/immer.esm.js
Dynamic Code Evaluation (e. g. 'eval', 'new Function', 'WebAssembly.compile') not allowed in Edge Runtime
Import trace for requested module:
../../node_modules/@aws-amplify/datastore/lib-esm/util.js
../../node_modules/@aws-amplify/datastore/lib-esm/index.js
../../node_modules/aws-amplify/lib-esm/index.js
./src/middleware.ts
../../node_modules/amazon-cognito-identity-js/es/Client.js
Dynamic Code Evaluation (e. g. 'eval', 'new Function', 'WebAssembly.compile') not allowed in Edge Runtime
Import trace for requested module:
../../node_modules/amazon-cognito-identity-js/es/CognitoUserPool.js
../../node_modules/amazon-cognito-identity-js/es/index.js
../../node_modules/@aws-amplify/auth/lib-esm/index.js
../../node_modules/aws-amplify/lib-esm/index.js
./src/middleware.ts
../../node_modules/lodash/_root.js
Dynamic Code Evaluation (e. g. 'eval', 'new Function', 'WebAssembly.compile') not allowed in Edge Runtime
Import trace for requested module:
../../node_modules/lodash/isBuffer.js
../../node_modules/lodash/isEmpty.js
../../node_modules/@aws-amplify/analytics/lib-esm/Providers/AmazonPersonalizeProvider.js
../../node_modules/@aws-amplify/analytics/lib-esm/Providers/index.js
../../node_modules/@aws-amplify/analytics/lib-esm/index.js
../../node_modules/aws-amplify/lib-esm/index.js
./src/middleware.ts
../../node_modules/@aws-amplify/api-graphql/node_modules/graphql/error/GraphQLError.mjs
Dynamic Code Evaluation (e. g. 'eval', 'new Function', 'WebAssembly.compile') not allowed in Edge Runtime
Import trace for requested module:
../../node_modules/@aws-amplify/api-graphql/node_modules/graphql/error/index.mjs
../../node_modules/@aws-amplify/api-graphql/node_modules/graphql/index.mjs
../../node_modules/@aws-amplify/api-graphql/lib-esm/GraphQLAPI.js
../../node_modules/@aws-amplify/api-graphql/lib-esm/index.js
../../node_modules/@aws-amplify/api/lib-esm/index.js
../../node_modules/aws-amplify/lib-esm/index.js
./src/middleware.ts
Next docs: https://nextjs.org/docs/api-reference/edge-runtime
@chrisbonifacio I created a reproduction repo here - just go install deps and build it to see the issue in action
https://github.com/revmischa/amplify-ssr-next-middleware-repro
@chrisbonifacio this would be a life saver feature. Do you guys have a plan to fix it? Would you keep us updated on any website? Web page?
Thanks Amir
@Amirbahal - we are still investigating how to properly fix this issue. Can you please inform us what is your use case for middleware?
I was able to work around this by switching from Amplify to next-auth. Here is my next-auth cognito config: https://github.com/jetbridge/sst-prisma/blob/master/web/pages/api/auth/%5B...nextauth%5D.ts
Thanks a lot @revmischa I really appreciate it. Having a look and I think using next auth is a good idea for my project anyway!
Yes @abdallahshaban557 in a nutshell, my intention was to check the current authenticated user in the middle ware + the path of the request. If the authenticated user has access to the path the request gets fulfilled, else, user gets redirected to a different path. :)
Hi @Amirbahal - gotcha! Thank you for sharing the details of your use case! Makes total sense on why you would want to do that in Middleware. We are currently working on fixing this issue! We will provide feedback on this issue when it is resolved.
Hey @abdallahshaban557 . Thanks in advance for addressing this issue. Do you have any idea when it will be fixed? I'm working on an auth flow and need to access the currentAuthenticatedUser data in middleware.
@fernandorosenblit - we've made a bit of progress in figuring out what is going on - but we are still early on in our analysis. Will keep this issue updated as we discover more!
Can anyone help me with this? https://stackoverflow.com/questions/74462640/how-to-handle-dynamic-list-json-of-redirects-on-nextjs-aws-amplify
Any update on this? Any workaround?
@abdallahshaban557 does this page: https://aws.amazon.com/about-aws/whats-new/2022/11/aws-amplify-hosting-support-next-js-12-13/ mean that this issue is resolved?
Hi @Amirbahal - unfortunately, this issue still exists with the Amplify libray for JavaScript. We do not have an exact timeline for fixing this issue - but we will share it here when we do!
Should this issue be unassigned and marked 'feature request"? It blocks using amplify SSR with nextjs middleware.
I want to restrict some pages in my nextjs app to logged-in users
info - Creating an optimized production build
Failed to compile.
../node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_root.js
Dynamic Code Evaluation (e. g. 'eval', 'new Function', 'WebAssembly.compile') not allowed in Edge Runtime
Learn More: https://nextjs.org/docs/messages/edge-dynamic-code-evaluation
Import trace for requested module:
../node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_root.js
../node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/isBuffer.js
../node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/isEmpty.js
../node_modules/.pnpm/@aws-amplify+analytics@6.0.8/node_modules/@aws-amplify/analytics/lib-esm/Providers/AmazonPersonalizeProvider.js
../node_modules/.pnpm/@aws-amplify+analytics@6.0.8/node_modules/@aws-amplify/analytics/lib-esm/Providers/index.js
../node_modules/.pnpm/@aws-amplify+analytics@6.0.8/node_modules/@aws-amplify/analytics/lib-esm/index.js
../node_modules/.pnpm/aws-amplify@5.0.8/node_modules/aws-amplify/lib-esm/index.js
../node_modules/.pnpm/aws-amplify@5.0.8/node_modules/aws-amplify/lib-esm/withSSRContext.js
Hi @abdallahshaban557, this is now a blocker for us and we need to find a solution/alternative . How close are you guys to release a fix? thanks
Ji @cuginoAle - unfortunately we do not have an update yet. I will get back to you when we are closer to identifying the issue here.
I have the same issue, anyone know of an alternative to this while a fix is deployed? I just want to get the:
const { Auth } = withSSRContext({ req });
but trying to avoid the getServerSideProps
on every single file
I made a comment here where I've changed the variable type of SSR to resolve issues I was having with next12
WEB_COMPUTE
getServerSideProps
and Auth
.
Changing
const SSR = withSSRContext({ req });
to
let SSR = withSSRContext({ req });
@abdallahshaban557 any update on this?
We are investigating this right now @jimmysafe. We are trying to see if there is a way for us to enable this without causing breaking changes, but it might be the case that a breaking change really is necessary. We are trying our best to resolve this.
Can you please elaborate a bit on the use cases you have for middleware in your app?
@abdallahshaban557 From me and it looks like many of the folks following this I believe the main use case is to manage auth through middleware so that certain Next.js routes can be protected for logged-in users or for specific user groups.
@abdallahshaban557 From me and it looks like many of the folks following this I believe the main use case is to manage auth through middleware so that certain Next.js routes can be protected for logged-in users or for specific user groups.
This 100%
Perfect - thank you so much for the feedback @jerocosio and @ArturoTorresMartinez !
@abdallahshaban557 Next.js outputs warning messages at build time that may be helpful, listing out the Node.js APIs that are unsupported, as well as which packages are using those APIs.
Unsupported APIs:
url
buffer
process.versions
Package:
@aws-amplify/auth@v5.2.1
Thanks for sharing that @ryanwalters - we have gotten to these same conclusions as well!
@abdallahshaban557 These are promising developments. If your team need help in any way, please shout - lots of us are rooting for this one!
thank you for the encouragement, @harrygreen! We will!
Before opening, please confirm:
JavaScript Framework
Next.js
Amplify APIs
Authentication
Amplify Categories
auth
Environment information
Describe the bug
We are working on updating our application up to NextJS 12. In doing so we are interested in moving the authentication check for protected pages to the new middleware feature available in next 12 (link). This code runs on the server before a request is completed. With that in mind, I went about attempting to use withSSRContext to check the users authentication status in the middleware.
As you can see above, I didn't get too far before this already broke the app. It seems that something underlying is attempting to use window which of course is not present on server. This looks to be happening in Reachablility
Expected behavior
Authentication is checked in the same manner it would be for getServerSideProps
Reproduction steps
In a next 12 application. place a _middleware.ts or _middleware.js file in one of your page directories. In that middleware file, simply import Amplify and that should be enough to draw out the exception.
Code Snippet
Log output
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