Authentication in Supabase: Anon Key-Based and User Logic-Based Approaches

Understanding the Different Types of Authentication in Supabase. Data security in Supabase: Tips for Managing Auth in Your Client-Side Application

Fri Jan 06 2023
5 min read
Authentication in Supabase: Anon Key-Based and User Logic-Based Approaches

This article provides an overview of two types of authentication in Supabase: anon key-based auth and user logic-based auth. The anon key can be used for read-only access to the Supabase database, but it is important to ensure that read-only access is granted to the relevant tables.

User logic-based auth involves using a Supabase client or HTTP request to retrieve an access token, refresh token, and other information. It is recommended to manage client-side application auth helper libraries by supabase.

Anon Key-Based Auth

anon_key uses it on the client side for most of the READ-only access-related things. Basically, this gives a key to connect to your supabase account. This same key can be used for the apiKey and Authorization params for the HTTP-based requests.

For the anon_key to work as a read-only token you need to give read-only access to your tables

tip

IMP Note: you should ensure you understand supabase Row Level policies before going to production. Documentation

Code for Basic Supabase Auth Setup

js
import { createClient } from "@supabase/supabase-js"; const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL; const supabaseKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY; export const supabase = createClient(supabaseUrl, supabaseKey);

Note: you can import this client object in your application pages and fetch data which has read-only policy applicable.

User Logic-based Auth

You can create a login or register page or have both logic in same page. Before you render the page you should check if the user is logged in, if yes then redirect them to the application's protected page else prompt them for login/registration.

js
import { useUser, useSupabaseClient } from '@supabase/auth-helpers-react' function UserAuthPage() { const supabaseClient = useSupabaseClient() const user = useUser() useEffect(()=>{ supabaseClient.auth.getSession().then((res: { data: { session: any; }; error: any; })=>{ const { data: { session }, error } = res; if(session?.user && session.user.aud === 'authenticated') { // if the user is authenticated redirect them to some application page router.push('/<protected page>'); } }); }, [user]); function signOut() { supabaseClient.auth.signOut().then(()=>{ supabaseClient.auth.refreshSession().then((res: { data: { user: any; session: any; }; error: any; }) => { const { data: { user, session }, error } = res; setSession(session); setSessionUser(user); }) }) } return (<USER AUTH COMPONENT>) }

tip

if you are using the helper UI and want to quick way to login users then just the below code would suffice

js
<div className="container mx-auto px-10 mb-8"> <button onClick={signOut} className="inline-block px-6 py-2.5 bg-red-600 text-white font-medium text-xs leading-tight uppercase rounded shadow-md hover:bg-red-700 hover:shadow-lg focus:bg-red-700 focus:shadow-lg focus:outline-none focus:ring-0 active:bg-red-800 active:shadow-lg transition duration-150 ease-in-out" > Sign out </button> <p>User check:</p> <pre>{JSON.stringify(user, null, 2)}</pre> </div> )

Note: I am using the tailwindCss in my project

Keeping the user logged in

Based on past experience I was thinking okay now that the user is logged in then I need to make sure the token is refreshed so that he can log in and set up some other things to define overall token invalidation and so on. So started looking at the auth response. But soon realized that I don't have to do any of it.

Here is some observations: Once you log in using the supabase client or HTTP request you will get the following keys in response

  1. access_token : main token for auth transaction
  2. refresh_token : as the name says it, use this to request the access_token once the expires_in limit is reached from the time of request
  3. expires_in: time for access_token to expire
  4. token_type: Can help you identify the type of request you posted on the service like invite, bearer or magic_link
  5. user: User object with nested user_metadata which can be used to store application-specific information and retrieve it later on.

note

No need to remember these as by default the js client library by Supabase will auto-renew the token for the said user session unless you explicitly define things otherwise.

Once you want to protect some of these pages then leverage the supabase user auth session checks with help of the below-mentioned code.

js
import { useSupabaseClient, useUser } from '@supabase/auth-helpers-react' function AllPosts({posts, errorMessage}: Props) { const supabaseClient = useSupabaseClient(); const user = useUser(); const router = useRouter(); useEffect(() => { supabaseClient.auth.getSession().then((res: { data: { session: any; }; error: any; })=>{ const { data: { session }, error } = res; if(session?.user && session.user.aud !== 'authenticated') { // if the authenticated user is not in the session object then redirect them to login router.push('/login'); } }); }, [user]); return (<PROTECTED COMPONENT>) }

How to manage your client-side application auth?

In most of the documentation that I was able to browse through, I didn't see a direct example of using the segregated auth logic for read-only anon_key-based authorization and user account-based authorization. Basically wanted to understand the best practices to manage the supabase client.

After observing the user state and supabaseClient state object in developer window I came to realization that the lib @supabase/auth-helpers-react is leveraging the one global client. So again nothing additional things to handle here.

learning

BaaS systems have come a long way during my enterprise career so far. We always say to keep up to date with the latest tech, but without doing the projects you actually don't learn.

Much more with Auth

There are further customizations you can add, like custom functions with trigger functions, and use in the policy for a given table. Check the example here

References:

  1. https://supabase.com/docs/learn/auth-deep-dive/auth-deep-dive-jwts
  2. https://www.youtube.com/watch?v=xmb4JrTYhZg