Supabase Auth and Plasmic

Hi,

I’m new to Plasmic and I have to say I’m really really impressed. There’s only one thing I’m finding way too difficult which is the Supabase integration. I understood choosing Plasmic over other low code builders would mean dealing with more technical things, although I think something as widely used as Supabase should be more easily integrated in Plasmic.

Anyways, after researching the Auth part of Plasmic-Supabase integration I have a few questions about the loader example with NextJS that would love some confirmation on before deciding to continue with Plasmic Auth or Supabase Auth (which I’d love but don’t want to deal with extra technical details diminishing development speed)(plasmic/examples/supabase-auth-nextjs-pages-loader at master · plasmicapp/plasmic · GitHub):

  1. Apart from setting up the project… Would I need to “sync” anything afterwards?
  2. Once I do the final clone and start editing in Plasmic, can I use all the Roles/Permissions/User features available in Plasmic as if I were using Plasmic Auth?
  3. Does this add any extra step to the deployment of the app or can I use the one click button to have my app live through Plasmic hosting?

If you someday achieve a full integration with Supabase with just a few clicks without abandoning your platform, etc, you’re gonna have a killer product.
I do understand all of this is complex technically, but it’s the only part of the product I see lacking (problem is, it’s a very important part of an app).

But you’ve truly truly built something impressive. Congrats and thank you!

1 Like

Hi @jacobo_garcia thanks for the great feedback

Here are the answer for your questions:

  1. If you are using the loader API version, you won’t need to perform any syncs afterwards, this is one of the benefits of using loader, if you are using codegen than you need to incrementally sync the changes of your project into your repository. I recommend reading Headless API vs. Codegen | Learn Plasmic
  2. Yes, the idea is to provide a seamless interface to help you describe your app authorization into the Studio.
  3. If you are using custom auth, you won’t be able to use Plasmic Hosting, but you should be able to deploy to a service of your preference and invoke a webhook through the publish button.

Let me know if this helps you.

Hey @fmota!

Thanks a lot for the answers. Would you mind clarifying two more things for me? :sweat_smile:.

  1. With the Supabase-Next.js project, I assume I’ll always have to spin up the local dev environment before editing in Plasmic editor, am I right?

  2. I guess with Supabase auth, even if it’s integrated through the NextJS sample app, any roles that I define in Plasmic auth settings aren’t synced to Supabase in any way, right?

Thanks a ton!

  1. It’s not necessary, you only need to spin the project if you are using a plasmic host for code components Using code components in Plasmic Studio | Learn Plasmic in a local version, but if you publish your host page to production, you no longer will need to spin the project in local dev to perform edits in the Studio. For the supabase next.js project it’s being used component substitution to attach specific handlers for the auth/business logic, so it doesn’t require to spin the local dev environment.
  2. Yes, currently, the mirroring of roles has to be manually performed.

Hi everyone,
I have been struggling for hours without success, I need some help here…
Me, as @jacobo_garcia, I have been making some tests with the Supabase & Plasmic Next.js example from Github. Everything works nice but next step is trying to use another Auth UI. I have been trying the React Auth UI from Supabase and here is where I am hitting a wall again and again. In that example, SWR is used to update the requests after being logged in / out. I, for the love of all gods, cannot make it work like I am doing with the substituted Plasmic components. Whenever I try to get the Plasmic data after looging in to Supabase (that is working fine) I get null objects. And if I try to run the ensurePlasmicAppUser method, I get a “Unhandled Runtime Error TypeError: Failed to fetch”. I have also tried with simple buttons. It looks like it’s something related to the fact that my component is not wrapped into a tag, like the substituted ones? If you could please help me, @fmota …I have spent too many hours with this. I know it’s dirty and messy, just trying things.

import {
  SignInWithPasswordCredentials,
  createClient,
} from "@supabase/supabase-js";
import { mutate } from "swr";
import { PLASMIC_AUTH_DATA_KEY } from "@/utils/cache-keys";

import { Auth } from "@supabase/auth-ui-react";
import {
  // Import predefined theme
  ThemeSupa,
} from "@supabase/auth-ui-shared";
import { createPagesBrowserClient } from "@supabase/auth-helpers-nextjs";
import { useState } from "react";
import { ensurePlasmicAppUser } from "@plasmicapp/auth-api";

const PLASMIC_AUTH_SECRET = process.env.PLASMIC_AUTH_SECRET;

const supabaseClient = createClient(
  process.env.NEXT_PUBLIC_SUPABASE_URL!,
  process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
);
const credentials = {
  email: "<deleted>",
  password: "<deleted>",
};

async function authCallback() {
  try {
    // Logic to handle the callback

    // After callback handling
    // ...

    const result = await ensurePlasmicAppUser({
      email: credentials.email,
      appSecret: PLASMIC_AUTH_SECRET!,
    });

    // Check if there's an error in the result
    if (result.error) {
      // If there's an error, log it and handle it accordingly
      console.error(result.error);
      // Optionally, you can throw the error to stop further execution
      throw new Error("Error occurred while ensuring Plasmic app user.");
    }

    const { user: plasmicUser, token: plasmicUserToken } = result;
    console.log("Result: ", result);

    // Store the token in a cookie or session
    // ...
  } catch (error) {
    // Catch any errors that occur within the try block or are thrown explicitly
    console.error("An error occurred:", error);
    // Handle the error as needed, such as displaying a user-friendly message
    // or performing additional error logging or cleanup
  }
}

async function getAuthUser() {
  const { data, error } = await supabaseClient.auth.getUser();
  if (error || !data?.user) {
    console.log("Error", error);
  } else {
    console.log("User: ", data?.user);
    return data?.user;
  }
}
async function signIn(credentials: SignInWithPasswordCredentials) {
  await supabaseClient.auth.signInWithPassword(credentials);
  await mutate(PLASMIC_AUTH_DATA_KEY);
}

const AuthUi = ({ className }: { className?: string }) => {
  const [supabaseClient] = useState(() => createPagesBrowserClient());
  return (
    <div className={className}>
      <Auth
        supabaseClient={supabaseClient}
        providers={["google"]}
        appearance={{ theme: ThemeSupa }}
        redirectTo="/"
      />
      <button
        onClick={() => {
          signIn(credentials);
        }}
      >
        Sign In
      </button>
      <button
        onClick={() => {
          // set the cookie as expired
          document.cookie =
            "token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";

          // tell all SWRs with this key to revalidate
          mutate(PLASMIC_AUTH_DATA_KEY);
        }}
      >
        Mutate
      </button>
      <button
        onClick={() => {
          getAuthUser();
          authCallback();
        }}
      >
        Get Auth User
      </button>
      <button
        onClick={async () => {
          await supabaseClient.auth.signOut();
          await mutate(PLASMIC_AUTH_DATA_KEY);
        }}
      >
        Sign Out
      </button>
    </div>
  );
};
export default AuthUi;

Thanks,

I struggled with similar things. What I ended up is:

  • deactivating the plasmic auth completely and build it myself via codegen
  • using the auth component from asim (below)
  • implementing a simple middleware to ensure users are logged in
  • working with supabase ssr

Asim has some good indepth videos. In the whatsapp video he has a good approach to authentication with supabase, although using a little older api. I used that auth form as it is a super version.
Repo: GitHub - asimkhan73301/plasmic-whatsapp-clone

Amongst all the supabase documentation I found this to be the most helpful
Creating a Supabase client for SSR | Supabase Docs

For Middleware I use
import { createMiddlewareClient } from '@supabase/auth-helpers-nextjs'
I think the server client from ssr didn’t work for me, but not so sure anymore.

3 Likes

OK, @gabriel_grohmann, thanks a lot for your answer. I will dig into that.
But, for the rest of the @support team from Plasmic, it can’t be that hard, right? I mean, I am already communicating correctly between a custom component and Plasmic auth. I just need to wrap my own custom component with the needed context to make it work, don’t I?
Thanks,

OK guys, I just wanted to let you all know that I finally managed to integrate Plasmic with Supabase auth using the Auth UI. I made a Github repo for future reference. I hope it helps people to figure everything out.

3 Likes

@daniel_grau Thank you. I am stuck myself. I will be using your repo as guide. Correct me if I’m wrong but you aren’t using Next.js App directory right?

Honestly wish I had seen your repo first then we could have built on it but now I have to figure out how to integrate Supabase Auth and Plasmic myself.

I do am using next.js App. I only use one page to route it after signing up. I hope that helps!

1 Like

Hey @jacobo_garcia can I contact you to see how do you integrate supabase auth?
I’m new also, and I need some info about it. I’ll pay you please for your teaching.

1 Like

Edit: This setup is entirely client-side within the Plasmic Studio environment. This means it might be accessible directly in the browser if Plasmic’s API integration and direct database connections aren’t handled on the backend. I’m certain their integration settings (like URLs and API keys) are secured, but I’m unsure about how the data responses themselves are handled. Regardless, this method essentially mirrors the Supabase client-side SDK, which also utilizes local storage and operates client-side.

In any case, this approach lets you quickly prototype and test your idea before committing to a fully server-side architecture if you ultimately decide to use cookies for authentication.

@abel_conde The easiest method I’ve found for integrating Supabase with Plasmic, without resorting to custom code components, custom authentication implementations, or importing external projects, is to use Plasmic’s built-in API integration directly. This approach even allows you to leverage Supabase’s Row-Level Security (RLS), making it ideal for multi-tenant applications.

Here’s how it works:

  1. Create a signup form: Use Plasmic’s form components to create a form with “email” and “password” input fields and a submit button.
  2. Implement signup logic: On form submission, use Plasmic’s HTTP integration to make a POST request to your Supabase project’s signup endpoint: [your supabase project base url]/auth/v1/signup.
  3. Create a login form: Similarly, create a login form with “email” and “password” inputs and a submit button.
  4. Implement login logic: On login form submission, use Plasmic’s HTTP integration to make a POST request to your Supabase project’s token endpoint: [your supabase project base url]/auth/v1/token?grant_type=password.
  5. Store essential data in local storage: Store the returned access token and user ID in local storage. Do not store the refresh token in local storage.
  6. Use the access token for authenticated requests: For all subsequent HTTP requests to your Supabase tables that require user authorization, include the access token in the Authorization header using the Bearer [dynamic value of the access token from local storage] format. This ensures that RLS is enforced and all JWT claims are correctly processed by Supabase.
  7. Refresh tokens securely: Use Plasmic’s Supabase direct connection to refresh tokens. Query the auth.refresh_tokens table in Supabase, filtering by the stored user_id and revoked = false (or whatever your “not revoked” status is). This method avoids storing the refresh token in local storage, which is a significant security improvement.

Note: Use the Plasmic Supabase direct connection for tasks unrelated to user authentication or authorization (JWT). This is useful for things like complex database queries involving joins, administrative tasks that don’t need RLS enforcement, and situations where you want to bypass RLS entirely. (For example, we used it to retrieve a user’s refresh token via their session ID, avoiding the need to store the refresh token directly in client-side storage—which is even more secure than how the standard Supabase client SDK handles it.) Think of this direct connection as your Supabase “service role” key – it has full access. For all user-facing interactions that do require user context and RLS enforcement, you should use the Supabase “anon” (anonymous) key.

Remember to think of the JavaScript API library (like the Supabase client-side library) as simply a wrapper around standard API calls. This means that all the underlying API requests will function the same way, regardless of whether you use the library or make the calls directly. Therefore, you can use Plasmic’s built-in REST or GraphQL API functionality to make all your API calls directly, bypassing the need for the full client-side library in many cases.

[Edit] Remember to remove the stored access token from local storage when logging out. You can do this by making a request to your Supabase project’s logout endpoint ([your supabase project base url]/auth/v1/logout) with the appropriate authorization header (Authorization: Bearer [dynamic access token]). Immediately following this request, use a “Run Code” interaction in Plasmic to remove the token from local storage (e.g., localStorage.removeItem("[your key name]")). Finally, add a navigation interaction to redirect the user to your login page.

This setup gives you a complete signup, sign-in, and logout system. (You can easily add features like password resets and email changes later using the same principles.)

I haven’t enabled Plasmic’s built-in authentication, nor am I using any custom authentication methods or custom code components. Everything is done within Plasmic’s no-code environment, with the exception of using the “set” and “remove” Run Code interactions for local storage management. I do, however, have Supabase Row-Level Security (RLS) fully implemented and working.

3 Likes

@ahmed_makki Awesome, I’ll try that way. Thank you!

1 Like

Awesome thx

some idea to deal with google signup/signin button? or with other social/app login?

@shamsXnahid made a detailed video of integrating Supabase Auth with Plasmic. He also did a write up and the link is available from his video down in the description.

Hi @papan_digital! Which video and where can I find it? Sorry for what might be a silly question but it would be helpful to know.

Found it!

2 Likes

Oooops ! I totally missed out the link! This the video for those wanting to slow slow see through …

https://www.youtube.com/watch?v=daiODdH1BYk.

A very daunting but @shamsXnahid took all the effort to deliver. Thanks @shamsXnahid. You are saving alot of headaches!

NOTE: this only work with NextJS pages router - Loader API and NOT codegen. You may refer further to GitHub - CallumBoase/plasmic-supabase for further information.

1 Like