Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for aws-amplify? #806

Closed
misantronic opened this issue Nov 30, 2021 · 44 comments
Closed

Support for aws-amplify? #806

misantronic opened this issue Nov 30, 2021 · 44 comments
Labels
enhancement New feature or request

Comments

@misantronic
Copy link

misantronic commented Nov 30, 2021

Which Remix packages are impacted?

  • remix (Remix core)

What version of Remix are you using?

1.0.6

Steps to Reproduce

Install aws-amplify: npm i aws-amplify

Use it in the project:

import Amplify from 'aws-amplify';

export default function App() {
    useEffect(() => {
       Amplify.configure({...});
    }, []);

    return (
        <Document>
            <Layout>
                <Outlet />
            </Layout>
        </Document>
    );
}

Expected Behavior

It should work, just like before.

Actual Behavior

I am pretty new to remix and ssr altogether.
Also aws states that aws-amplify supports ssr, I cannot get it to work.
Whenever I am executing the code above, I get an error:

Uncaught TypeError: Failed to resolve module specifier "url". Relative references must start with either "/", "./", or "../".

I am also curious: Is that code I put into the useEffect actually executed on the server or in the browser?
I just would like to run aws-amplify in the browser, to get my old app-logic going...

@misantronic misantronic added the bug Something isn't working label Nov 30, 2021
@LukasGerm
Copy link
Contributor

I have the same error but with the "path" package at the moment.

@LukasGerm
Copy link
Contributor

Okay, hear me out. :)

I think you can't use that module inside the routes path. I just moved my helper function out of the routes folder and now the app is running for me.

@misantronic
Copy link
Author

Okay, hear me out. :)

I think you can't use that module inside the routes path. I just moved my helper function out of the routes folder and now the app is running for me.

I have it like this:

/app/root.tsx

import { configureAuth } from './aws/auth';

export default function App() {
    useEffect(() => {
        configureAuth();
    }, []);
  ...
}

/app/aws/auth.ts

import Amplify from 'aws-amplify';

export function configureAuth() {
    console.log(Amplify); // causes error
}

so that structure shouldn't cause any troubles... still it does :(

@chanan
Copy link

chanan commented Dec 18, 2021

I have a similar problem trying to use the Authenticator control from @aws-amplify/ui-react.

Just by adding the import to index.jsx:

import { Authenticator } from "@aws-amplify/ui-react";

I get the following error:

Uncaught TypeError: Failed to resolve module specifier "url". Relative references must start with either "/", "./", or "../".

TypeError: Cannot read properties of undefined (reading 'root')
    at RemixRoute (http://localhost:3000/build/_shared/chunk-O3PPVUTT.js:3035:19)
    at renderWithHooks (http://localhost:3000/build/_shared/chunk-MHFS6D7O.js:11065:26)
    at mountIndeterminateComponent (http://localhost:3000/build/_shared/chunk-MHFS6D7O.js:13185:21)
    at beginWork (http://localhost:3000/build/_shared/chunk-MHFS6D7O.js:13972:22)
    at HTMLUnknownElement.callCallback2 (http://localhost:3000/build/_shared/chunk-MHFS6D7O.js:3675:22)
    at Object.invokeGuardedCallbackDev (http://localhost:3000/build/_shared/chunk-MHFS6D7O.js:3700:24)
    at invokeGuardedCallback (http://localhost:3000/build/_shared/chunk-MHFS6D7O.js:3734:39)
    at beginWork$1 (http://localhost:3000/build/_shared/chunk-MHFS6D7O.js:17081:15)
    at performUnitOfWork (http://localhost:3000/build/_shared/chunk-MHFS6D7O.js:16309:20)
    at workLoopSync (http://localhost:3000/build/_shared/chunk-MHFS6D7O.js:16263:13)

Doing a quick debug, when the import is present then routeModules is undefined on line 179 of components.js.

@ryanflorence ryanflorence changed the title [Bug]: support for aws-amplify? [Feature]: support for aws-amplify? Dec 20, 2021
@ryanflorence ryanflorence added enhancement New feature or request and removed bug Something isn't working labels Dec 20, 2021
@ryanflorence ryanflorence changed the title [Feature]: support for aws-amplify? Support for aws-amplify? Dec 20, 2021
@ryanflorence
Copy link
Member

ryanflorence commented Dec 20, 2021

Somebody who knows AWS Amplify will need to help out here. Remix is pretty simple to host. To deploy a Remix app the server needs to:

  1. Serve static assets out of public/
  2. Route all other requests to a lambda

That lambda would have a Remix adapter that adapts the AWS Amplify request into a web fetch Request. I'm sure the adapter will be pretty much identical to the remix-architect and remix-netlify adapters. So you can look in there for hints.

When I've looked at AWS amplify it all seemed very browser-oriented and it wasn't obvious how to set up those two requirements. We welcome any amplify experts to help out here :)

@chanan
Copy link

chanan commented Dec 20, 2021

@ryanflorence do you think the error:

Uncaught TypeError: Failed to resolve module specifier "url". Relative references must start with either "/", "./", or "../".

Is thrown by Remix?

@dangreaves
Copy link

Hey guys, I’m on mobile so can’t type out a proper writeup, but the reason for this is because the frontend amplify packages reference node modules like url, path etc.

These modules don’t actually exist in the browser, but are polyfilled when bundling with webpack 4. Note that throughout the amplify documentation, they always reference webpack 4 specifically.

In webpack 5, this polyfill functionality was removed, so it’s my understanding that the amplify packages will not work with webpack 5 without some config.

https://github.com/webpack/changelog-v5

Coming back to remix, I believe remix uses esbuild under the hood which won’t be polyfilling these node libraries, hence the errors.

There’s a giant thread over in the amplify repo with discussion on this.

aws-amplify/amplify-js#9639

Just thought I would provide some context, this is an amplify ui + esbuild issue, nothing to do with remix itself.

I personally think given the backend focus of remix, you probably don’t want to be using the amplify ui packages anyway. Do all your auth, queries etc using the AWS admin SDKs in your loaders and actions. Amplify UI is designed for single page apps, so you will be fighting the remix paradigm when it comes to auth etc.

@misantronic
Copy link
Author

misantronic commented Dec 20, 2021

Do all your auth, queries etc using the AWS admin SDKs in your loaders and actions.

thank your for this detailed explanation.
do you happen to know where I would find the docs for those aws admin sdks?

@chanan
Copy link

chanan commented Dec 20, 2021

@misantronic I think he means the aws-sdk which you can find the docs and detailed API here: https://aws.amazon.com/sdk-for-javascript/

@dangreaves Thanks for the explanation. Yes, it should mostly all work via the sdk in the Loader/Action function. One thing that would still be problematic would be Auth when using social/oauth providers as that needs to be done via the browser. I haven't found a way to do that without the library, although it should all be http calls/redirects so presumably there is a way.

@ryanflorence
Copy link
Member

ryanflorence commented Dec 20, 2021

Often you do the initial auth dance in the browser, and then submit the JWT to your remix app and put it in a cookie and then use the JWT on the Remix server.

@chanan
Copy link

chanan commented Dec 20, 2021

@ryanflorence Right that is the problem, if we do the initial browser part with the library, the app crashes with the error above. Maybe we can do the redirect without the library, not sure yet, I will give it a shot at some point this week.

@dangreaves
Copy link

If you were able to add esbuild plugins to remix, you could add a plugin like this which adds a webpack 4-like polyfill feature.

https://github.com/remorses/esbuild-plugins#esbuild-pluginsnode-modules-polyfill

I can’t find a documented way of adding esbuild plugins to remix though so that may not be possible yet.

Also, it’s clear that the amplify team have only tested the package with webpack 4, so you might run into more esbuild related problems. as there’s a lot less “magic” in esbuild (which is a good thing!).

If it’s possible to do your initial auth with an alternate library, I would highly recommend it as the amplify ui package isn’t great for performance, has a lot of side effects and has some design problems (eg the use of node modules, requiring polyfilling at the bundler).

You might have some luck using this package which is specifically for cognito, rather than the full amplify ui package.

https://www.npmjs.com/package/amazon-cognito-identity-js

@chanan
Copy link

chanan commented Dec 21, 2021

In case anyone needs it, here is an authentication method for Cognito without Amplify libraries:

https://gist.github.com/chanan/d1601c63df36ac476e84fbc2ca96b2e9

@misantronic
Copy link
Author

In case anyone needs it, here is an authentication method for Cognito without Amplify libraries:

https://gist.github.com/chanan/d1601c63df36ac476e84fbc2ca96b2e9

that is incredible helpful — thank you 🙏

@jesuscovam
Copy link

something that pops in my mind is that Amplify AppSync (GraphQL API) requires client-side Auth to run queries and mutations that are Restricted to Cognito User Pool users, at least to work effortlessly, but for backend requests you would have to

  • make those requests available for the public API or private with IAM auth in a lambda function

so if you choose the IAM to keep the API restricted you would call a lambda to call de request from your backend, unless there's a way to sign the request from the remix backend with the AWS-SDK npm pkg.

@pckilgore
Copy link

Just as another vote, I don't have the time budget to re-implement the Amplify/Oauth stuff for the project I'm picking up remix to handle, it would be nice to have enough build system escape hatches for these kinds of things.

@ErikCH
Copy link

ErikCH commented Mar 24, 2022

Hello @pckilgore and @misantronic !

I'm with the Amplify team, and with our latest release, I've been able to get Remix working with the Amplify library. We are still testing it, so if you find any issues let me know.

Here is our documentation.

https://ui.docs.amplify.aws/getting-started/installation

@machour machour added the needs-response We need a response from the original author about this issue/PR label Mar 25, 2022
@pckilgore
Copy link

@ErikCH Ended up writing the server-side stuff with the SDK. Good to know for the future.

@acusti
Copy link
Contributor

acusti commented Apr 1, 2022

@ErikCH i’m super excited to hear that you’ve been able to get Remix working with Amplify! i would love to start exploring that myself. i checked the docs you linked to and it only covers the amplify UI library, whereas the part i’m stuck on is how to integrate Remix with Amplify SSR hosting. i read the AWS docs on Amplify SSR hosting, as well as the Amplify docs on Next.js hosting, and there are some parts that seem pretty Next.js specific, so i’m not sure how to adapt them to work with a Remix app.

the SSR docs give an example amplify.yml file:

version: 1
frontend:
  phases:
    preBuild:
      commands:
        - npm ci
    build:
      commands:
        - npm run build
  artifacts:
    baseDirectory: .next
    files:
      - '**/*'
  cache:
    paths:
      - node_modules/**/*

according to the docs, setting baseDirectory: .next indicates that the build artifacts are for a Next.js app that supports SSG and SSR pages (for SSG-only, it would be baseDirectory: out). what should that value be for a Remix app?

the docs also state that “Amplify inspects the app’s build script in the package.json file to detect whether the app is SSR or SSG”. the "build": "next build", indicates SSR, while ”build”: “next build && next export”, indicates SSG. do you know what that value should be for integrating with a Remix app?

thanks so much for any guidance you can provide! also, if you want me to take this discussion anywhere else (a different GitHub repo, the discord, etc.), i’m happy to do so. once i get Amplify and Remix working together, i will put together a write-up with guidance and instructions on my blog.

@calavera
Copy link

calavera commented Apr 1, 2022

👋 @acusti It's currently not possible to deploy Remix apps using the Amplify Hosting SSR implementation because it's designed to work with Next.js at the moment. We're working on several improvements that would remove that limitation. Now that I'm aware of this thread, I'll keep you all informed here when we have news worth sharing.

@CrshOverride
Copy link

Hello @pckilgore and @misantronic !

I'm with the Amplify team, and with our latest release, I've been able to get Remix working with the Amplify library. We are still testing it, so if you find any issues let me know.

Here is our documentation.

https://ui.docs.amplify.aws/getting-started/installation

Do you happen to know if that includes the Authentication components? That's a big blocker for me at the moment moving forward.

@ErikCH
Copy link

ErikCH commented Apr 1, 2022

@CrshOverride ! Yup that's what we've been testing, the Authenticator, and it's been going well.

@CrshOverride
Copy link

@ErikCH Do you have a gist or anything anywhere that you can toss up to show the flow? That would be amazing if it "just worked" but I need it to secure calls to the "backend" as well. 🤔

@github-actions
Copy link
Contributor

github-actions bot commented Apr 4, 2022

This issue has been automatically closed because we haven't received a response from the original author 🙈. This automation helps keep the issue tracker clean from issues that are unactionable. Please reach out if you have more information for us! 🙂

@github-actions github-actions bot closed this as completed Apr 4, 2022
@MichaelDeBoey MichaelDeBoey removed the needs-response We need a response from the original author about this issue/PR label Apr 6, 2022
@aaronksaunders
Copy link

@ErikCH Do you have a gist or anything anywhere that you can toss up to show the flow? That would be amazing if it "just worked" but I need it to secure calls to the "backend" as well. 🤔

@CrshOverride - were you able to get any additional information about this? Thanks

@CrshOverride
Copy link

@aaronksaunders I wasn't. My naive attempts also didn't work at all. As soon as I added the Amplify UI components to my project, my bundle was too large to be deployed to Lambda.

@aaronksaunders
Copy link

aaronksaunders commented Apr 22, 2022 via email

@ErikCH
Copy link

ErikCH commented Apr 22, 2022

Hi @aaronksaunders , @CrshOverride !

We don't have any official documentation on using Amplify with Remix yet. When I tested it, it was working. My testing was just limited to using the aws-amplify/ui-react package Authenticator. I followed the steps in our official documentation to create a new app. However, I didn't test every scenario, or hosting it somewhere in production, so your may run into some unexpected problems.

When we feel confident that we've tested enough scenarios, we'll add it to our official documentation. If you do run into problems though, as @aaronksaunders suggested, post on our Discord #ui-help channel. Or post your issue on our Github too.

@CrshOverride We made a fix that reduced the bundle size significantly recently. So you may want to try that again if the Lambda was having problems with the size.

@acusti
Copy link
Contributor

acusti commented May 18, 2022

@ErikCH i’ve been experimenting with migrating an existing amplify web app to remix (using cloudflare-workers as the server target) and am unable to get it to build. once i add aws-amplify as a dependency, i get this:

✘ [ERROR] Could not resolve "http2"

    node_modules/@aws-sdk/node-http-handler/dist/es/node-http2-handler.js:4:35:
      4 │ import { connect, constants } from "http2";
        ╵                                    ~~~~~~~

  The package "http2" wasn't found on the file system but is built into node. Are you trying to bundle for node? You can use "platform: 'node'" to do that, which will remove this error.

i then ran yarn why @aws-sdk/node-http-handler to see why that dependency is getting included:

[1/4] 🤔  Why do we have the module "@aws-sdk/node-http-handler"...?
[2/4] 🚚  Initialising dependency graph...
[3/4] 🔍  Finding dependency...
[4/4] 🚡  Calculating file sizes...
=> Found "@aws-sdk/node-http-handler@3.6.1"
info Reasons this module exists
   - "@aws-amplify#core#@aws-sdk#client-cloudwatch-logs" depends on it
   - Hoisted from "@aws-amplify#core#@aws-sdk#client-cloudwatch-logs#@aws-sdk#node-http-handler"
   - Hoisted from "@aws-amplify#core#@aws-sdk#client-cognito-identity#@aws-sdk#node-http-handler"
   - Hoisted from "@aws-amplify#storage#@aws-sdk#client-s3#@aws-sdk#node-http-handler"
info Disk size without dependencies: "388KB"
info Disk size with unique dependencies: "1.41MB"
info Disk size with transitive dependencies: "1.54MB"
info Number of shared dependencies: 6

did you run into any issues from @aws-sdk/* packages and esbuild in your tests? any ideas on how i can work around them? i’m still unclear why these node.js-only libraries are being depended on from the @aws-amplify/* packages when they are intended to be used in a browser context, but i guess that’s a bigger question than this immediate issue.


a quick update: marking http2 as an external for esbuild results in that error going away and these fresh errors

✘ [ERROR] No matching export in "node-modules-polyfills:child_process" for import "exec"

    node_modules/@aws-sdk/credential-provider-process/dist/es/index.js:4:9:
      4 │ import { exec } from "child_process";
        ╵          ~~~~

 ✘ [ERROR] No matching export in "node-modules-polyfills:crypto" for import "createHash"

    node_modules/@aws-sdk/hash-node/dist/es/index.js:3:9:
      3 │ import { createHash, createHmac } from "crypto";
        ╵          ~~~~~~~~~~

 ✘ [ERROR] No matching export in "node-modules-polyfills:crypto" for import "createHmac"

    node_modules/@aws-sdk/hash-node/dist/es/index.js:3:21:
      3 │ import { createHash, createHmac } from "crypto";
        ╵                      ~~~~~~~~~~

 ✘ [ERROR] No matching export in "node-modules-polyfills:fs" for import "createReadStream"

    node_modules/@aws-sdk/hash-stream-node/dist/es/index.js:1:9:
      1 │ import { createReadStream } from "fs";
        ╵          ~~~~~~~~~~~~~~~~

 ✘ [ERROR] No matching export in "node-modules-polyfills:fs" for import "readFile"

    node_modules/@aws-sdk/shared-ini-file-loader/dist/es/index.js:2:9:
      2 │ import { readFile } from "fs";
        ╵          ~~~~~~~~

 ✘ [ERROR] No matching export in "node-modules-polyfills:os" for import "homedir"

    node_modules/@aws-sdk/shared-ini-file-loader/dist/es/index.js:3:9:
      3 │ import { homedir } from "os";
        ╵          ~~~~~~~

 ✘ [ERROR] No matching export in "node-modules-polyfills:fs" for import "lstatSync"

    node_modules/@aws-sdk/util-body-length-node/dist/es/index.js:1:9:
      1 │ import { lstatSync } from "fs";
        ╵          ~~~~~~~~~

@pckilgore
Copy link

You can try using just @aws-amplify/auth or @aws-amplify/ui-react.

I ended up implementing auth on the remix side with the v2 SDK.

@aaronksaunders
Copy link

I ended up getting it working with a combination of server side code and client side code using the Amplify Authenticator component to simplify the user management on the client and then passing the session information to the server to track in a session cookie. I then can make api calls using AppSync and the token from the user that was in the session cookie.

I do need to go back an add an additional call to verify the token on the server side but the basic structure is in the code sample

source code - https://github.com/aaronksaunders/amplify-remix-todos-1

@CrshOverride
Copy link

@aaronksaunders Which stack did you wind up using? I'm wondering if it'll address the issues I had my first attempt.

@aaronksaunders
Copy link

aaronksaunders commented Jun 6, 2022 via email

@chrispepper1989
Copy link

Hey so I currently have a standard create react app hosted via aws amplify that does need to use the authentication.

I'm considering converting it to remix as a learning experience as well as giving the client the performance benefit.

But reading this thread I'm wondering is it worth the pain? And shall I save remix for my other project which will be hosted on cloudflare?

@juliankrispel
Copy link

Using amplify on the frontend kind of defeats the point of using remix :D - I will opt for the approach of implementing remix handlers for auth

@j-fulbright
Copy link

Has there been any changes to the SSR side to allow other libraries to work beyond Next?

@MattyBalaam
Copy link

Using amplify on the frontend kind of defeats the point of using remix :D - I will opt for the approach of implementing remix handlers for auth

You can use @aws-amplify/auth server side - although it is a little tricky.

@silberistgold
Copy link

Hi there,

I am currently trying to use the new amplify v6 apis in my remix app but I get stuck here:

    const keyValueStorage = createKeyValueStorageFromCookieStorageAdapter({
      get: async (name) => {
        const cookieHeader = request.headers.get("cookie");
        console.log("get", cookieHeader);
        const cookie = createCookie(name)
          .parse(cookieHeader)
          .then((c) => console.log("cc", c));
        console.log("cookie", cookie);
        return { name: "", value: "" };
      },
    });

Problem is that the get method is not allowed to be async and remix cookie api needs to be awaited. Anyone tried this and has ideas or made progress? Would also be nice to have a reference implementation for remix cookies like the one in the nextjs-adapter.

@MattyBalaam
Copy link

MattyBalaam commented Jan 24, 2024

I experimented with the current Amplify 6 SSR solution, but as it stands currently you cannot officially sign in server side (and do not get things like IP address or user agent logged) so we have decided to write our own custom Cognito solution.

Someone from Amplify team claims that a proper server-side solution is in the works but there are no timescales for this:

Screenshot 2024-01-24 at 07 11 57

If this is not a blocker from you, then to get this working what you need to do is move grabbing the session outside:


const createKeyValueStorage = async (request) => {
  const values = await sessionStorage.getSession(request.headers.get('Cookie'))

  if (!values) throw new Error('No session found');

  return createKeyValueStorageFromCookieStorageAdapter({
    get: (name) => {

      const value = values.get(name)

      if (!value) {
        console.log({ name, values });

        throw new Error('No value found');
      }

      return { name, value };
    },
   
  });
};

@Afsoon
Copy link

Afsoon commented Mar 19, 2024

@MattyBalaam do you have a full example to save the cookies using your approach? I'm trying but I can't successfully login. If I remove the SSR, keeping everything client side, everything works fine.

@MattyBalaam
Copy link

I would strongly recommend not using it! Are you on 5 or 6? There was one tricky workaround we needed to do which was that when you do the original sign-in we needed to store the temporary session (not user session) and then re-apply. It was quite frankly a mess.

@Afsoon
Copy link

Afsoon commented Mar 19, 2024

@MattyBalaam I'm on v6

@MattyBalaam
Copy link

I can‘t help, for v6 I just threw something up just to test if if would run server-side as we wanted and the code is long gone.

@Afsoon
Copy link

Afsoon commented Mar 19, 2024

@MattyBalaam thank you for answer, I just run out of ideas on how to make it work, the API on V6 it's very NextJS flavour, and I don't want move to v5 so probably we will do everything client side.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests