Skip to content
Auth

Use Supabase Auth with React Native

Learn how to use Supabase Auth with React Native

Quickstart#

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
select * from auth.users;
2
Create a React app

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

Terminal
npx create-expo-app -t expo-template-blank-typescript my-app
3
Install the Supabase client library

Install supabase-js and the required dependencies.

Terminal
cd 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
Publishable key
lib/supabase.ts
import { AppState, Platform } from 'react-native'
import 'react-native-url-polyfill/auto'
import AsyncStorage from '@react-native-async-storage/async-storage'
import { createClient } from '@supabase/supabase-js'
const supabaseUrl = process.env.EXPO_PUBLIC_SUPABASE_URL!
const supabasePublishableKey = process.env.EXPO_PUBLIC_SUPABASE_PUBLISHABLE_KEY!
export const supabase = createClient(supabaseUrl, supabasePublishableKey, {
auth: {
...(Platform.OS !== 'web' ? { storage: AsyncStorage } : {}),
autoRefreshToken: true,
persistSession: true,
detectSessionInUrl: false,
},
})
// Tells Supabase Auth to continuously refresh the session automatically
// if the app is in the foreground. When this is added, you will continue
// to receive `onAuthStateChange` events with the `TOKEN_REFRESHED` or
// `SIGNED_OUT` event if the user's session is terminated. This should
// only be registered once.
if (Platform.OS !== 'web') {
AppState.addEventListener('change', (state) => {
if (state === 'active') {
supabase.auth.startAutoRefresh()
} else {
supabase.auth.stopAutoRefresh()
}
})
}
View source

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.

Project URL
Publishable key
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
import React, { useState } from 'react'
import { Alert, StyleSheet, View, Text, TextInput, TouchableOpacity } from 'react-native'
import { supabase } from '../lib/supabase'
export default function Auth() {
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const [loading, setLoading] = useState(false)
async function signInWithEmail() {
setLoading(true)
const { error } = await supabase.auth.signInWithPassword({
email: email,
password: password,
})
if (error) Alert.alert(error.message)
setLoading(false)
}
async function signUpWithEmail() {
setLoading(true)
const {
data: { session },
error,
} = await supabase.auth.signUp({
email: email,
password: password,
})
if (error) Alert.alert(error.message)
if (!session) Alert.alert('Please check your inbox for email verification!')
setLoading(false)
}
return (
<View style={styles.container}>
<View style={[styles.verticallySpaced, styles.mt20]}>
<Text style={styles.label}>Email</Text>
<TextInput
onChangeText={(text) => setEmail(text)}
value={email}
placeholder="email@address.com"
autoCapitalize="none"
style={styles.input}
/>
</View>
<View style={styles.verticallySpaced}>
<Text style={styles.label}>Password</Text>
<TextInput
onChangeText={(text) => setPassword(text)}
value={password}
secureTextEntry={true}
placeholder="Password"
autoCapitalize="none"
style={styles.input}
/>
</View>
<View style={[styles.verticallySpaced, styles.mt20]}>
<TouchableOpacity
style={[styles.button, loading && styles.buttonDisabled]}
onPress={() => signInWithEmail()}
disabled={loading}
>
<Text style={styles.buttonText}>Sign in</Text>
</TouchableOpacity>
</View>
<View style={styles.verticallySpaced}>
<TouchableOpacity
style={[styles.button, loading && styles.buttonDisabled]}
onPress={() => signUpWithEmail()}
disabled={loading}
>
<Text style={styles.buttonText}>Sign up</Text>
</TouchableOpacity>
</View>
</View>
)
}
const styles = StyleSheet.create({
container: {
marginTop: 40,
padding: 12,
},
verticallySpaced: {
paddingTop: 4,
paddingBottom: 4,
alignSelf: 'stretch',
},
mt20: {
marginTop: 20,
},
label: {
fontSize: 16,
fontWeight: '600',
color: '#86939e',
marginBottom: 6,
},
input: {
borderWidth: 1,
borderColor: '#86939e',
borderRadius: 4,
padding: 12,
fontSize: 16,
},
button: {
backgroundColor: '#2089dc',
borderRadius: 4,
padding: 12,
alignItems: 'center',
},
buttonDisabled: {
opacity: 0.5,
},
buttonText: {
color: '#fff',
fontSize: 16,
fontWeight: '600',
},
})
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
import 'react-native-url-polyfill/auto'
import { useState, useEffect } from 'react'
import { supabase } from './lib/supabase'
import Auth from './components/Auth'
import { View, Text } from 'react-native'
import { JwtPayload } from '@supabase/supabase-js'
export default function App() {
const [claims, setClaims] = useState<JwtPayload | null>(null)
useEffect(() => {
supabase.auth.getClaims().then(({ data: { claims } }) => {
setClaims(claims)
})
supabase.auth.onAuthStateChange(() => {
supabase.auth.getClaims().then(({ data: { claims } }) => {
setClaims(claims)
})
})
}, [])
return (
<View>
<Auth />
{claims && <Text>{claims.sub}</Text>}
</View>
)
}
View source
7
Start the app

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

Terminal
npm start