Migrating to Server Side Supabase Auth

My winning hackathon project, Supaque, is a http queue & schedule service built on top of Supabase’s PostgreSQL database and function. The project was built using the Deno Fresh framework and deployed on Deno Deploy platform. While building the project, I initially used the authentication flow on the client side, using supabase auth SDK.

During Supabase Launch Week 7, a new feature was released for the Supabase Auth PKCE flow. This new flow allows for more secure authentication on the server side of applications. With this release, I decided to migrate the authentication flow of my Supaque project to use the new PKCE flow on the server side.

There is a new Auth helper available for handling the PKCE flow on the server side, which can be found at https://github.com/supabase/auth-helpers. This helper is currently available for Next.js, SvelteKit, and Remix applications. Although I was using the Deno Fresh framework for my project, I was able to leverage the available documentation to write my own helper to integrate the PKCE flow into my server-side authentication process. Despite not having an official helper for Fresh framework, the process was still relatively straightforward and the documentation was helpful in guiding me through the integration.

Show me the Code

Here is my previous callback handler on client side:

  useEffect(() => {
    const url = new URL(window.location.href);
    const param = new URLSearchParams(url.hash);

    const token = param.get("#access_token");
    param.delete("#access_token");
    if (token) {
      param.set("access_token", token);
      globalThis.location.replace(`/auth?${param.toString()}`);
    } else if (param.get("error_code")) {
      setMessage(param.get("error_description") || "Unable to login");
      setIsError(true);
    }
  }, []);

And now, using PKCE auth flow, it’s can handled on backend code

const code = url.searchParams.get("code");
const { data, error } = await supabase.auth.exchangeCodeForSession(code);

And this is my custom helper for Deno Fresh Framework

export const supabaseSSR = (req: Request, res: Response) =>
  createClient<Database>(
    Deno.env.get("SUPABASE_URL") as string,
    Deno.env.get("SUPABASE_KEY") as string,
    {
      auth: {
        detectSessionInUrl: false,
        flowType: "pkce",
        storageKey: "pkce",
        storage: {
          setItem: (key, value) => {
            const val = encode(value);
            setCookie(res.headers, {
              name: key,
              value: val,
              sameSite: "Lax",
              maxAge: 60 * 60 * 24 * 7 * 1000,
              path: "/",
            });
          },
          getItem: (key) => {
            const cok = getCookies(req.headers);
            const val = cok[key];
            if (!val) {
              return null;
            }
            const decoded = decode(val);
            const decodedStr = new TextDecoder("utf-8").decode(decoded);
            return decodedStr;
          },
          removeItem: (key) => {
            setCookie(res.headers, {
              name: key,
              value: "",
              sameSite: "Lax",
              expires: new Date(0),
              path: "/",
            });
          },
        },
      },
    }
  );

For those who are interested, the source code for Supaque is available on my GitHub repository at https://github.com/suciptoid/supaque. You can see how I integrated the new PKCE flow into the server-side authentication process and explore the codebase to learn more about how the project works. Feel free to leave any feedback or suggestions in the repository’s issues section.