rembrembdocs

Use Supabase Auth with React Native

Learn how to use Supabase Auth with React Native


1

Create a new Supabase project

Launch a new project in the Supabase Dashboard.

Your new database has a table for storing your users. You can see that this table is currently empty by running some SQL in the SQL Editor.

SQL_EDITOR
1select * from auth.users;

2

Create a React app

Create a React app using the create-expo-app command.

Terminal
1npx create-expo-app -t expo-template-blank-typescript my-app

3

Install the Supabase client library

Install supabase-js and the required dependencies.

Terminal
1cd my-app && npx expo install @supabase/supabase-js @react-native-async-storage/async-storage @rneui/themed react-native-url-polyfill

4

Set up your login component

Create a helper file lib/supabase.ts that exports a Supabase client using your Project URL and key.

Rename .env.example to .env and populate with your Supabase connection variables:

Project URL

To get your Project URL, log in.

Publishable key

To get your Publishable key, log in.

lib/supabase.ts
1import { AppState, Platform } from 'react-native'2import 'react-native-url-polyfill/auto'3import AsyncStorage from '@react-native-async-storage/async-storage'4import { createClient, processLock } from '@supabase/supabase-js'56const supabaseUrl = process.env.EXPO_PUBLIC_SUPABASE_URL!7const supabaseAnonKey = process.env.EXPO_PUBLIC_SUPABASE_ANON_KEY!89export const supabase = createClient(supabaseUrl, supabaseAnonKey, {10  auth: {11    ...(Platform.OS !== 'web' ? { storage: AsyncStorage } : {}),12    autoRefreshToken: true,13    persistSession: true,14    detectSessionInUrl: false,15    lock: processLock,16  },17})1819// Tells Supabase Auth to continuously refresh the session automatically20// if the app is in the foreground. When this is added, you will continue21// to receive `onAuthStateChange` events with the `TOKEN_REFRESHED` or22// `SIGNED_OUT` event if the user's session is terminated. This should23// only be registered once.24if (Platform.OS !== 'web') {25  AppState.addEventListener('change', (state) => {26    if (state === 'active') {27      supabase.auth.startAutoRefresh()28    } else {29      supabase.auth.stopAutoRefresh()30    }31  })32}

View source

You can also get the Project URL and key from the project's Connect dialog.

Get API details#

Now that you've created some database tables, you are ready to insert data using the auto-generated API.

To do this, you need to get the Project URL and key from the project Connect dialog.

Read the API keys docs for a full explanation of all key types and their uses.

Changes to API keys

Supabase is changing the way keys work to improve project security and developer experience. You can read the full announcement, but in the transition period, you can use both the current anon and service_role keys and the new publishable key with the form sb_publishable_xxx which will replace the older keys.

The legacy keys will be deprecated shortly, so we strongly encourage switching to and using the new publishable and secret API keys.

In most cases, you can get the correct key from the Project's Connect dialog, but if you want a specific key, you can find all keys in the API Keys section of a Project's Settings page:

For new keys, open the API Keys tab, if you don't have a publishable key already, click Create new API Keys, and copy the value from the Publishable key section.

5

Create a login component

Create a React Native component to manage logins and sign ups. The app later uses the getClaims method in App.tsx to validate the local JWT before showing the signed-in user.

components/Auth.tsx
1import React, { useState } from 'react'2import { Alert, StyleSheet, View, Text, TextInput, TouchableOpacity } from 'react-native'3import { supabase } from '../lib/supabase'45export default function Auth() {6  const [email, setEmail] = useState('')7  const [password, setPassword] = useState('')8  const [loading, setLoading] = useState(false)910  async function signInWithEmail() {11    setLoading(true)12    const { error } = await supabase.auth.signInWithPassword({13      email: email,14      password: password,15    })1617    if (error) Alert.alert(error.message)18    setLoading(false)19  }2021  async function signUpWithEmail() {22    setLoading(true)23    const {24      data: { session },25      error,26    } = await supabase.auth.signUp({27      email: email,28      password: password,29    })3031    if (error) Alert.alert(error.message)32    if (!session) Alert.alert('Please check your inbox for email verification!')33    setLoading(false)34  }3536  return (37    <View style={styles.container}>38      <View style={[styles.verticallySpaced, styles.mt20]}>39        <Text style={styles.label}>Email</Text>40        <TextInput41          onChangeText={(text) => setEmail(text)}42          value={email}43          placeholder="email@address.com"44          autoCapitalize="none"45          style={styles.input}46        />47      </View>48      <View style={styles.verticallySpaced}>49        <Text style={styles.label}>Password</Text>50        <TextInput51          onChangeText={(text) => setPassword(text)}52          value={password}53          secureTextEntry={true}54          placeholder="Password"55          autoCapitalize="none"56          style={styles.input}57        />58      </View>59      <View style={[styles.verticallySpaced, styles.mt20]}>60        <TouchableOpacity61          style={[styles.button, loading && styles.buttonDisabled]}62          onPress={() => signInWithEmail()}63          disabled={loading}64        >65          <Text style={styles.buttonText}>Sign in</Text>66        </TouchableOpacity>67      </View>68      <View style={styles.verticallySpaced}>69        <TouchableOpacity70          style={[styles.button, loading && styles.buttonDisabled]}71          onPress={() => signUpWithEmail()}72          disabled={loading}73        >74          <Text style={styles.buttonText}>Sign up</Text>75        </TouchableOpacity>76      </View>77    </View>78  )79}8081const styles = StyleSheet.create({82  container: {83    marginTop: 40,84    padding: 12,85  },86  verticallySpaced: {87    paddingTop: 4,88    paddingBottom: 4,89    alignSelf: 'stretch',90  },91  mt20: {92    marginTop: 20,93  },94  label: {95    fontSize: 16,96    fontWeight: '600',97    color: '#86939e',98    marginBottom: 6,99  },100  input: {101    borderWidth: 1,102    borderColor: '#86939e',103    borderRadius: 4,104    padding: 12,105    fontSize: 16,106  },107  button: {108    backgroundColor: '#2089dc',109    borderRadius: 4,110    padding: 12,111    alignItems: 'center',112  },113  buttonDisabled: {114    opacity: 0.5,115  },116  buttonText: {117    color: '#fff',118    fontSize: 16,119    fontWeight: '600',120  },121})

View source

6

Add the Auth component to your app

Add the Auth component to your App.tsx file. If the user is logged in, print the user id to the screen.

App.tsx
1import 'react-native-url-polyfill/auto'2import { useState, useEffect } from 'react'3import { supabase } from './lib/supabase'4import Auth from './components/Auth'5import { View, Text } from 'react-native'6import { JwtPayload } from '@supabase/supabase-js'78export default function App() {9  const [claims, setClaims] = useState<JwtPayload | null>(null)1011  useEffect(() => {12    supabase.auth.getClaims().then(({ data: { claims } }) => {13      setClaims(claims)14    })1516    supabase.auth.onAuthStateChange(() => {17      supabase.auth.getClaims().then(({ data: { claims } }) => {18        setClaims(claims)19      })20    })21  }, [])2223  return (24    <View>25      <Auth />26      {claims && <Text>{claims.sub}</Text>}27    </View>28  )29}

View source

7

Start the app

Start the app, and follow the instructions in the terminal.

Terminal
1npm start