Use Supabase Auth with React Native
Learn how to use Supabase Auth with React Native
Quickstart#
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.
1select * from auth.users;Create a React app using the create-expo-app command.
1npx create-expo-app -t expo-template-blank-typescript my-appInstall supabase-js and the required dependencies.
1cd my-app && npx expo install @supabase/supabase-js @react-native-async-storage/async-storage @rneui/themed react-native-url-polyfillCreate 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:
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 supabasePublishableKey = process.env.EXPO_PUBLIC_SUPABASE_PUBLISHABLE_KEY!89export const supabase = createClient(supabaseUrl, supabasePublishableKey, {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}Get API details#
To interact with data in database tables, you use the client libraries that wrap the auto-generated Data API endpoints, authenticating using the Project URL and key from the project Connect dialog.
Read the API keys docs for a full explanation of all key types, their uses, and where to find them.
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.
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})Add the Auth component to your App.tsx file. If the user is logged in, print the user id to the screen.
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}Start the app, and follow the instructions in the terminal.
1npm start