auth-helpers icon indicating copy to clipboard operation
auth-helpers copied to clipboard

Create auth helpers for Remix

Open VictorPeralta opened this issue 2 years ago • 16 comments

Like with Next.js which currently has easy to use helpers and routes, the same could be done for Remix.

I didn't find an open issue about this, although I heard it's planned, so it can be tracked here.

VictorPeralta avatar Mar 28 '22 20:03 VictorPeralta

If no one is working on this yet, I'd like work on it.

I have something like the next + supabase auth example for Remix here, so I feel like ai have enough context to accomplish this:

https://github.com/VictorPeralta/supabase-remix-auth

VictorPeralta avatar Mar 28 '22 20:03 VictorPeralta

Hi Victor, PRs are most definitely welcome! Thanks for opening this issue to track.

One consideration we have with Remix and Supabase Auth is ensuring realtime still works on the client side. Remix mostly uses HttpOnly cookies for auth but these currently don't play well with the client side realtime. This is something we're looking to address in the future, but if you can get it working with the current constraints, that would be great!

alaister avatar Mar 28 '22 20:03 alaister

@VictorPeralta that would be awesome indeed. I know that @dijonmusters was planning to work on this once he's back from leave, but I am very certain he wouldn't mind you getting started on it 💚

thorwebdev avatar Mar 29 '22 07:03 thorwebdev

Looks like @dijonmusters had already started working on this: https://github.com/supabase-community/supabase-auth-helpers/commit/2a690e50f1cbe0f5ad5e119818705774e2d90363

Might a good starting point Victor! Let me know if you need help, would be happy to contribute

MaxAst avatar Apr 04 '22 18:04 MaxAst

Also worthwhile looking at https://github.com/rphlmr/supa-fly-stack and if there are things from there we can pull out into auth helpers cc @rphlmr

thorwebdev avatar Apr 07 '22 06:04 thorwebdev

@dijonmusters Hi, i tried the example from the branch feat/add-remix-run but i have trouble to use the withAuthRequired function. When i use it, i get the following application error:

Error: Cannot initialize 'routeModules'. This normally occurs when you have server code in your client modules.

the problem is this line:

if (!user) return redirect('/login')

redirect comes from the @remix-run/node package so its not available in browser context. When i try to change withAuthRequired.js to withAuthRequired.server.js nothing changed. I get the same application error.

I also read something about the error in the remix docs: Server Code in Client Bundles but i didn't find any solution.

Does anyone have an idea how to solve this? I would like to use this wrapper because it makes things easier, but it doesn't seem to be possible...

niklasgrewe avatar Apr 20 '22 19:04 niklasgrewe

@niklasgrewe Hi,

It's because withAuthRequired is a high order function that creates a side effect.

Remix doesn't know what to do with that and add this code to client side bundle too.

https://remix.run/docs/en/v1/guides/constraints#higher-order-functions

You should rewrite it to use it in loader / action 😉

// withAuthRequired.server.js
export default async function withAuthRequired (request) => {
  const accessToken = await getAccessTokenFromRequest(request);
  const { user } = await supabase.auth.api.getUser(accessToken);

  if (!user) {
    throw redirect("/login");
  }

  return { accessToken, user };
};
// app/routes/channels.jsx
export const loader = async ({ request }) => {
  const { accessToken } = await withAuthRequired(request)
  supabase.auth.setAuth(accessToken);

  const { data: channels } = await supabase.from("channels").select("*");

  return json({
    channels,
  });
};

PS : return json() will be mandatory soon ;)

rphlmr avatar Apr 21 '22 06:04 rphlmr

@rphlmr thank you for your quick help. Do you know when the auth helper for remix will be ready? I had already considered using remix-auth with the supabase strategy. However, I had seen that there is also a PR from you pending. Can you tell me where the differences are? Honestly don't know what is the best/easiest way to integrate supabase auth into remix. Can you recommend me something?

niklasgrewe avatar Apr 21 '22 09:04 niklasgrewe

@rphlmr thank you for your quick help. Do you know when the auth helper for remix will be ready? I had already considered using remix-auth with the supabase strategy. However, I had seen that there is also a PR from you pending. Can you tell me where the differences are? Honestly don't know what is the best/easiest way to integrate supabase auth into remix. Can you recommend me something?

The remix-auth-supabase is on standby 😅 With the maintainer we think to deprecate it, because we think Remix Stacks are more suitable.

I can recommend you to check "my remix stack" . At least to have an overall idea about how it could be implemented, until supabase made an official way ;)

rphlmr avatar Apr 21 '22 10:04 rphlmr

@rphlmr great thank you, I did not know that. I also think the remix stacks are more suitable. Your stack I have already looked at, but admittedly, I do not really understand everything yet 😅

What I would like to understand though is why do I need to return json({ accessToken, User }) instead of return { accessToken, User } Can you possibly explain this to me? Most importantly, I would like to use types. But when I return json, I can only specify Promise<Response> as the return type. Do you know how I can specify the types for accessToken and User anyway?

niklasgrewe avatar Apr 21 '22 11:04 niklasgrewe

I would like to understand though is why do I need to return json({ accessToken, User }) instead of return { accessToken, User }

@niklasgrewe It's a Remix thing. At first, they had no opinion but to prevent future issues they advise to return json object with json.

It's an helper function equivalent to

new Response({ accessToken, User }, {
    headers: {
      "Content-Type": "application/json",
    },
  });

But when I return json, I can only specify Promise<Response> as the return type. Do you know how I can specify the types for accessToken and User anyway?

Typing a loader or action is not possible because they are just Fetch Response. Response body (your { accessToken, user }) is just a readable stream of byte data in the end ;) They are serialized thru the network and not directly used in your code like "normal" functions

But you can (and should) anyway use typing for useLoaderData and useActionData.

Example :

interface MyLoaderData {
  orders: {
    id: string;
    amount: number;
    ...
  };
}

export const loader = async ({ request }) => {
  const { accessToken } = await withAuthRequired(request);
  supabase.auth.setAuth(accessToken);

  const { data: orders } = await supabase.from("orders").select("*");

  return json({
    orders,
  });
};

export default function MyRoute () {
  const { orders } = useLoaderData() as MyLoaderData
  // or const { orders } = useLoaderData<MyLoaderData>()
  // its a matter of choice, Remix creator like using as ^^"

  return <div>...</div>
}

I hope it helps. Don't worry, take your time, and play with it. It's a new tech with lot of "old things" (HTTP standards re-implementation) coming back.

rphlmr avatar Apr 21 '22 12:04 rphlmr

@rphlmr thank you very much for the detailed info. However, could it be that return json({ accessToken, user }); is not currently supported? When i try this:

// withAuthRequired.server.js
export default async function withAuthRequired (request) => {
  const accessToken = await getAccessTokenFromRequest(request);
  const { user } = await supabase.auth.api.getUser(accessToken);

  if (!user) {
    throw redirect("/login");
  }

  return json({ accessToken, user }); // ❌ not working
  // return { accessToken, user } ✅ works
};
// app/routes/private.jsx
export const loader = async ({ request }) => {
  const { user } = await withAuthRequired(request)
  return json({ email: user.email })
};

i always get

Cannot read properties of undefined (reading 'email')

When i change return json({ accessToken, user }); to return { accessToken, user } it works

niklasgrewe avatar Apr 21 '22 13:04 niklasgrewe

@niklasgrewe I'm so sorry, I've edited my previous example => https://github.com/supabase-community/supabase-auth-helpers/issues/57#issuecomment-1104763964

Of course, withAuthRequired have to return "classic json" and not json({}) that is a "http layer thing". Sorry again for the confusion :(

rphlmr avatar Apr 21 '22 13:04 rphlmr

Sorry again for the confusion :(

all good, no problem at all, I figured it out myself. Thanks again for your support and explanations

niklasgrewe avatar Apr 21 '22 15:04 niklasgrewe

Any news on Remix support?

413n avatar May 27 '22 12:05 413n

Supabase 🤝 Remix?

image

abhagsain avatar Aug 24 '22 16:08 abhagsain

Chiming in to remind people that Cloudflare Pages/Workers is a supported deployment environment for Remix that doesn't support environment variables. Seems like all the stacks mainly use Fly. Hoping these helpers will keep that in mind and make sure it's compatible with Cloudflare.

beppek avatar Oct 06 '22 22:10 beppek

Has anyone used an oath supabase login with the remix auth helpers? I'm only seeing an email/password login example in the root https://github.com/supabase/auth-helpers/blob/4a709e24445d17b5bafae00ea06f562f5e052fcc/examples/remix/app/root.tsx

lsbyerley avatar Oct 29 '22 13:10 lsbyerley

@lsbyerley I've added an OAuth example here: https://github.com/supabase/auth-helpers/pull/354/files

Thinking about changing the example to use the Auth UI. Would that be helpful?

thorwebdev avatar Nov 01 '22 08:11 thorwebdev

@lsbyerley I've added an OAuth example here: https://github.com/supabase/auth-helpers/pull/354/files

Thinking about changing the example to use the Auth UI. Would that be helpful?

Awesome, thank you for the updated oauth example! I personally don't use the Auth UI components but I'm sure someone else out there would find it useful. I think having both would be perfect.

lsbyerley avatar Nov 01 '22 13:11 lsbyerley

I'd second keeping an example without Auth UI. I don't tend to use it either, so having an example without is useful for me too.

IHIutch avatar Nov 01 '22 13:11 IHIutch

The new remix oauth example doesn't seem to be working for me. I see the access token in the url after auth and then the remix app does nothing with it.

lsbyerley avatar Nov 01 '22 13:11 lsbyerley

@lsbyerley calling the auth methods in a server action wasn't the right approach unfortunately. I'm working on moving auth stuff to the client here: https://github.com/supabase/auth-helpers/pull/356 . It currently uses the Auth UI but I'll also add a plain JS example.

This approach will simplify things and save you money (server function invocations).

thorwebdev avatar Nov 01 '22 14:11 thorwebdev

  • Example with Auth UI: https://github.com/supabase/auth-helpers/blob/main/examples/remix/app/root.tsx#L116-L122
  • Example with custom form: https://github.com/supabase/auth-helpers/blob/main/examples/remix/app/routes/no-auth-ui.tsx#L9-L22

thorwebdev avatar Nov 02 '22 07:11 thorwebdev

  • Example with Auth UI: https://github.com/supabase/auth-helpers/blob/main/examples/remix/app/root.tsx#L116-L122
  • Example with custom form: https://github.com/supabase/auth-helpers/blob/main/examples/remix/app/routes/no-auth-ui.tsx#L9-L22

Thank you! I'm still not sure I understand how to perform a signInWithOAuth authentication without the Auth UI as it seems you've switched back to signInWithPassword.

The earlier example you had for oauth signin did not do anything with the accessToken after coming back to the remix

lsbyerley avatar Nov 02 '22 12:11 lsbyerley

@lsbyerley by following the createBrowserClient and onAuthStatChange handler setup in the root route (https://github.com/supabase/auth-helpers/blob/main/examples/remix/app/root.tsx#L80-L96) you can now use the standard javascript methods: https://supabase.com/docs/reference/javascript/auth-signinwithoauth

<button
  onClick={() => {
    supabase?.auth.signInWithOAuth({
      provider: 'github',
      options: { redirectTo: 'http://localhost:3004' }
    });
  }}
>
  GitHub OAuth
</button>

I've added it to the example: https://github.com/supabase/auth-helpers/pull/360

thorwebdev avatar Nov 02 '22 16:11 thorwebdev