SaaSIndie LogoSaaSIndie
Back to Blog

9 Supabase JS Auth Tricks Every JavaScript Developer Should Know

9 Supabase JS Auth Tricks Every JavaScript Developer Should Know

AK

Aug 7, 20254 min read

Supabase is quickly becoming the go-to backend for developers who want to build full-stack apps without the boilerplate. One of its most used features is Supabase JS Auth, a simple but powerful authentication system that works seamlessly with JavaScript and modern frameworks like Next.js, React, and Vue.

In this article, we’ll go beyond basic email/password login and dive into the capabilities of Supabase JS Auth.

Whether you're building an MVP, a SaaS product, or a side project, mastering these auth features will help you build faster, safer, and more scalable applications.

1. Email and Password Sign-Up with Metadata

The standard email/password sign-up is straightforward in Supabase JS Auth:

const { data, error } = await supabase.auth.signUp({
  email: 'user@example.com',
  password: 'securepassword123',
  options: {
    data: { full_name: 'Jane Doe' }
  }
});

The options.data field allows you to attach custom metadata to the user, such as name, role, or preferences. This metadata can later be accessed via the user object or used in Row-Level Security (RLS) policies.

Use Case: Personalize onboarding or user dashboards immediately after signup.

Supabase JS Auth supports passwordless authentication using magic links:

const { data, error } = await supabase.auth.signInWithOtp({
  email: 'user@example.com'
});

This method sends an email with a time-limited login link. It’s ideal for apps where you want to minimize friction and remove the need for password management.

Best For: MVPs, beta apps, or any app where ease-of-access is a priority.

3. Social Logins with OAuth Providers

Adding Google, GitHub, or Twitter login is very simple:

await supabase.auth.signInWithOAuth({
  provider: 'google'
});

To use this, configure the provider from the Supabase Dashboard under Auth > Providers. Supabase handles the full OAuth flow, including redirects and token exchange.

Why It Matters: Users often prefer using existing credentials, and OAuth increases sign-up conversion.

4. Listen to Auth State Changes and Manage Sessions

Supabase automatically stores auth sessions, but you should still monitor session state for better UX:

supabase.auth.onAuthStateChange((event, session) => {
  console.log('Event:', event);
  console.log('Session:', session);
});

Use this listener to redirect users after login, logout, or token refresh events. It’s essential for building reactive UIs and persisting login state after page reloads.

5. Use the Supabase Client in Next.js (Server vs Client Components)

To integrate Supabase Auth properly in a Next.js app, you need two separate clients:

  • Client Component client – used in components that run in the browser.
  • Server Component client – used in Server Components, Route Handlers, and Server Actions.

Create a utils/supabase folder (e.g., utils/supabase/client.ts and utils/supabase/server.ts) and add the following:

Client Component Client

// utils/supabase/client.ts
import { createBrowserClient } from '@supabase/ssr';

export function createClient() {
  return createBrowserClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
  );
}

Use this in Client Components (e.g., login forms or dashboards that run in the browser).

Server Component Client

// utils/supabase/server.ts
import { createServerClient } from '@supabase/ssr';
import { cookies } from 'next/headers';

export async function createClient() {
  const cookieStore = await cookies();

  return createServerClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
    {
      cookies: {
        getAll() {
          return cookieStore.getAll();
        },
        setAll(cookiesToSet) {
          try {
            cookiesToSet.forEach(({ name, value, options }) =>
              cookieStore.set(name, value, options)
            );
          } catch {
            // The setAll method was called from a Server Component.
            // This can be ignored if you have middleware refreshing
            // user sessions.
          }
        },
      },
    }
  );
}

Use this in Server Components, Route Handlers, or Server Actions.

Why This Matters

Using the correct Supabase client ensures:

  • Environment-specific execution (client vs. server)
  • Proper cookie-based session management
  • Secure, scalable architecture in Next.js with Supabase

Bonus Tip: Native Stripe Integration with Supabase Wrapper

Supabase now offers a built-in Stripe Wrapper integration, making it easier than ever to sync and query Stripe data directly from your Postgres database—no need to write custom backend sync logic.

This integration uses the wrappers and supabase_vault extensions to securely connect to Stripe and expose resources like subscriptions, invoices, and customers as foreign tables in your database.

To enable this:

  1. Go to Integrations > Stripe Wrapper in your Supabase project.
  2. Click Enable wrappers to install the required Postgres extensions.
  3. Configure your Stripe credentials and start querying Stripe like a native table.
🔗 Referenced from this update: Tweet by Jordie N

Why it’s Useful

This eliminates a lot of boilerplate and enables real-time visibility into Stripe data, directly within your Supabase DB—perfect for dashboards, billing workflows, and admin panels.


6. Handle Errors Gracefully in Auth Flows

Supabase returns detailed error messages that help with debugging and improving UX:

const { error } = await supabase.auth.signInWithPassword({
  email: 'wrong@example.com',
  password: 'incorrect'
});

if (error) {
  console.error(error.message);
}

Display clear messages like "Invalid login credentials" or "Email already registered". Never expose raw error logs in production.

7. Enable Row-Level Security for Secure Multi-User Access

Supabase Postgres database tables are wide open until you enable Row-Level Security (RLS). Pair RLS with Supabase JS Auth for secure multi-user apps.

Example RLS policy:

CREATE POLICY "Users can access their own data"
  ON profiles
  FOR SELECT USING (auth.uid() = id);

Why It’s Crucial: Without RLS, any authenticated user can access or modify all rows in your tables. Always turn on RLS in production environments.

8. Refresh Sessions Automatically for Long-Lived Logins

Supabase tokens expire after a certain period, but sessions can be refreshed automatically:

supabase.auth.onAuthStateChange(async (event, session) => {
  if (event === 'TOKEN_REFRESHED') {
    // Update your state or client here
  }
});

This ensures users stay logged in and don't get logged out unexpectedly during long sessions.

You can use JWT claims from Supabase Auth to write Postgres functions that behave differently based on the user’s role or metadata:

-- Access control inside a function
CREATE OR REPLACE FUNCTION get_user_data()
RETURNS TABLE(...) AS $$
BEGIN
  RETURN QUERY SELECT * FROM users WHERE id = auth.uid();
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

This provides a strong backend-level access control mechanism for apps that require granular logic on the DB side.


Conclusion

Supabase JS Auth is much more than a login box. From magic links to role-based policies and session management, it's a complete authentication solution built for modern JavaScript apps.

By mastering these Supabase JS Auth tricks, you’ll be able to:

  • Build secure and scalable auth flows
  • Enhance UX with minimal effort
  • Avoid common pitfalls in authentication design

Whether you're building an MVP or scaling a SaaS, understanding how Supabase Auth works under the hood will save you time, headaches, and potentially critical security issues.

If you’re using Supabase JS Auth in production or planning to, consider enabling RLS, tracking sessions, and experimenting with OAuth flows today.

💡
Looking to Boost Conversions? Try Toastie: A Free Sales Pop up Tool !