惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

IT之家
IT之家
NISL@THU
NISL@THU
The Hacker News
The Hacker News
C
CXSECURITY Database RSS Feed - CXSecurity.com
T
Tenable Blog
Forbes - Security
Forbes - Security
V2EX - 技术
V2EX - 技术
Webroot Blog
Webroot Blog
Schneier on Security
Schneier on Security
T
The Exploit Database - CXSecurity.com
T
Tor Project blog
C
Cisco Blogs
TaoSecurity Blog
TaoSecurity Blog
The Last Watchdog
The Last Watchdog
PCI Perspectives
PCI Perspectives
O
OpenAI News
C
Cyber Attacks, Cyber Crime and Cyber Security
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Google Online Security Blog
Google Online Security Blog
宝玉的分享
宝玉的分享
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
量子位
D
Docker
AI
AI
Blog — PlanetScale
Blog — PlanetScale
S
Security @ Cisco Blogs
S
Schneier on Security
The GitHub Blog
The GitHub Blog
W
WeLiveSecurity
云风的 BLOG
云风的 BLOG
M
MIT News - Artificial intelligence
P
Privacy International News Feed
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
H
Hackread – Cybersecurity News, Data Breaches, AI and More
B
Blog
C
Check Point Blog
A
About on SuperTechFans
D
Darknet – Hacking Tools, Hacker News & Cyber Security
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Engineering at Meta
Engineering at Meta
I
InfoQ
T
Threat Research - Cisco Blogs
Project Zero
Project Zero
Cloudbric
Cloudbric
MongoDB | Blog
MongoDB | Blog
Cisco Talos Blog
Cisco Talos Blog
L
Lohrmann on Cybersecurity
S
Securelist

Supabase Blog

AI Agents Know About Supabase. They Don't Always Use It Right. Custom OIDC Providers for Supabase Auth 100,000 GitHub stars Supabase docs over SSH Navigating Regional Network Blocks Supabase Joins the Stripe Projects Developer Preview Log Drains: Now available on Pro Supabase Storage: major performance, security, and reliability updates Supabase incident on February 12, 2026 Hydra joins Supabase X / Twitter OAuth 2.0 is now available for Supabase Auth BKND joins Supabase Supabase is now an official Claude connector Supabase PrivateLink is now available Introducing: Postgres Best Practices When to use Read Replicas vs. bigger compute Introducing TRAE SOLO integration with Supabase Supabase Security Retro: 2025 Sync Stripe Data to Your Supabase Database in One Click Building ChatGPT Apps with Supabase Edge Functions and mcp-use Own Your Observability: Supabase Metrics API Introducing iceberg-js: A JavaScript Client for Apache Iceberg Introducing Supabase for Platforms Adding Async Streaming to Postgres Foreign Data Wrappers Build "Sign in with Your App" using Supabase Auth Introducing Seven New Email Templates for Supabase Auth The new Supabase power for Kiro Introducing Supabase ETL Introducing Analytics Buckets Introducing Vector Buckets Snap, Inc. Launches Snap Cloud, Powered by Supabase Triplit joins Supabase Supabase Series E 1000 Y Combinator Founders Choose Supabase gm 👋 web3, welcome aboard to Sign in with Web3 (Solana, Ethereum) Announcing the Supabase Remote MCP Server Enterprise speed, enterprise standards with Bolt Cloud + Supabase PostgREST 13 Lovable Cloud + Supabase: The Default Platform for AI Builders Processing large jobs with Edge Functions, Cron, and Queues Defense in Depth for MCP Servers OrioleDB Patent: now freely available to the Postgres community Supabase Launch Week 15 Hackathon Winner Announcement The Vibe Coder's Guide to Supabase Environments Testing for Vibe Coders: From Zero to Production Confidence The Vibe Coding Master Checklist Vibe Coding: Best Practices for Prompting Supabase Auth: Build vs. Buy Top 10 Launches of Launch Week 15 Supabase Launch Week 15 Hackathon Storage: 10x Larger Uploads, 3x Cheaper Cached Egress, and 2x Egress Quota Persistent Storage and 97% Faster Cold Starts for Edge Functions Algolia Connector for Supabase New Observability Features in Supabase Improved Security Controls and A New Home for Security Introducing Branching 2.0 Stripe-To-Postgres Sync Engine as standalone Library Supabase Analytics Buckets with Iceberg Support Create a Supabase backend using Figma Make Introducing JWT Signing Keys Supabase UI: Platform Kit Build a Personalized AI Assistant with Postgres Announcing Multigres: Vitess for Postgres Building on open table formats Open Data Standards: Postgres, OTel, and Iceberg Simplifying back-end complexity with Supabase Data APIs PostgreSQL Event Triggers without superuser access Top 10 Launches of Launch Week 14 Supabase MCP Server Data API Routes to Nearest Read Replica Declarative Schemas for Simpler Database Management Realtime: Broadcast from Database Keeping Tabs on What's New in Supabase Studio Edge Functions: Deploy from the Dashboard + Deno 2.1 Automatic Embeddings in Postgres Introducing the Supabase UI Library Supabase Auth: Bring Your Own Clerk Postgres Language Server: Initial Release Migrating from Fauna to Supabase Migrating from the MongoDB Data API to Supabase Dedicated Poolers Postgres as a Graph Database: (Ab)using pgRouting AI Hackathon at Y Combinator Calendars in Postgres using Foreign Data Wrappers Supabase Launch Week 13 Hackathon Winners How to Hack the Base! Running Durable Workflows in Postgres using DBOS database.build v2: Bring-your-own-LLM Restore to a New Project Hack the Base! with Supabase Top 10 Launches of Launch Week 13 Supabase Queues High Performance Disk Supabase Cron Supabase CLI v2: Config as Code Supabase Edge Functions: Introducing Background Tasks, Ephemeral Storage, and WebSockets Supabase AI Assistant v2 OrioleDB Public Alpha Executing Dynamic JavaScript Code on Supabase with Edge Functions ClickHouse Partnership, improved Postgres Replication, and Disk Management
Getting started with React Native authentication
Thor Schaeff · 2023-11-16 · via Supabase Blog

Getting started with React Native authentication

Authentication is the process of verifying the identity of a user who is attempting to access a system, application, or online service. In this blog post, you will learn about React Native authentication, including native mobile specific login mechanisms like "Sign in with Apple" and "Google One Tap sign-in", as well as SMS & WhatsApp based authentication.

At the end of this blog post, you will have all the components needed to create the ideal authentication experience for your mobile app users.

This article assumes you are comfortable with writing a basic application in React Native. No knowledge of Supabase is required.

We will use the following tools

  • Expo - we used Expo SDK version 49.0.0 (React Native version 0.72)
  • Supabase - create your account here if you do not have one
  • IDE of your choosing

Note: We're using Expo as that's the recommended way of getting started with React Native. However, the fundamental approach here applies to bare React Native applications as well.

Using supabase-js is the most convenient way of leveraging the full power of the Supabase stack as it conveniently combines all the different services (database, auth, realtime, storage, edge functions) together.

Install supabase-js and dependencies#

After you have created your Expo project, you can install supabase-js and the required dependencies using the following command:


_10

npx expo install @supabase/supabase-js @react-native-async-storage/async-storage react-native-url-polyfill


Authentication storage#

By default, supabase-js uses the browser's localStorage mechanism to persist the user's session but can be extended with platform specific storage implementations. In React Native we can build native mobile and web applications with the same code base, so we need a storage implementation that works for all these platforms: react-native-async-storage.

We need to pass an instance of react-native-async-storage to supabase-js to make sure authentication works reliably across all react native platforms:


_15

import 'react-native-url-polyfill/auto'

_15

import AsyncStorage from '@react-native-async-storage/async-storage'

_15

import { createClient } from '@supabase/supabase-js'

_15

_15

const supabaseUrl = YOUR_REACT_NATIVE_SUPABASE_URL

_15

const supabaseAnonKey = YOUR_REACT_NATIVE_SUPABASE_ANON_KEY

_15

_15

export const supabase = createClient(supabaseUrl, supabaseAnonKey, {

_15

auth: {

_15

storage: AsyncStorage,

_15

autoRefreshToken: true,

_15

persistSession: true,

_15

detectSessionInUrl: false,

_15

},

_15

})


You can find your URL and anon key in the API credentials section of the Supabase dashboard.

Encrypting the user session#

If you wish to encrypt the user's session information, you can use aes-js and store the encryption key in Expo SecureStore. The aes-js library is a reputable JavaScript-only implementation of the AES encryption algorithm in CTR mode. A new 256-bit encryption key is generated using the react-native-get-random-values library. This key is stored inside Expo's SecureStore, while the value is encrypted and placed inside AsyncStorage.

Please make sure that:

  • You keep the expo-secure-storage, aes-js and react-native-get-random-values libraries up-to-date.
  • Choose the correct SecureStoreOptions for your app's needs. E.g. SecureStore.WHEN_UNLOCKED regulates when the data can be accessed.
  • Carefully consider optimizations or other modifications to the above example, as those can lead to introducing subtle security vulnerabilities.

Install the necessary dependencies in the root of your Expo project:


_10

npm install @supabase/supabase-js

_10

npm install @rneui/themed @react-native-async-storage/async-storage react-native-url-polyfill

_10

npm install aes-js react-native-get-random-values

_10

npx expo install expo-secure-store


Implement a LargeSecureStore class to pass in as Auth storage for the supabase-js client:


_69

import 'react-native-url-polyfill/auto'

_69

import { createClient } from '@supabase/supabase-js'

_69

import AsyncStorage from '@react-native-async-storage/async-storage'

_69

import * as SecureStore from 'expo-secure-store'

_69

import * as aesjs from 'aes-js'

_69

import 'react-native-get-random-values'

_69

_69

// As Expo's SecureStore does not support values larger than 2048

_69

// bytes, an AES-256 key is generated and stored in SecureStore, while

_69

// it is used to encrypt/decrypt values stored in AsyncStorage.

_69

class LargeSecureStore {

_69

private async _encrypt(key: string, value: string) {

_69

const encryptionKey = crypto.getRandomValues(new Uint8Array(256 / 8))

_69

_69

const cipher = new aesjs.ModeOfOperation.ctr(encryptionKey, new aesjs.Counter(1))

_69

const encryptedBytes = cipher.encrypt(aesjs.utils.utf8.toBytes(value))

_69

_69

await SecureStore.setItemAsync(key, aesjs.utils.hex.fromBytes(encryptionKey))

_69

_69

return aesjs.utils.hex.fromBytes(encryptedBytes)

_69

}

_69

_69

private async _decrypt(key: string, value: string) {

_69

const encryptionKeyHex = await SecureStore.getItemAsync(key)

_69

if (!encryptionKeyHex) {

_69

return encryptionKeyHex

_69

}

_69

_69

const cipher = new aesjs.ModeOfOperation.ctr(

_69

aesjs.utils.hex.toBytes(encryptionKeyHex),

_69

new aesjs.Counter(1)

_69

)

_69

const decryptedBytes = cipher.decrypt(aesjs.utils.hex.toBytes(value))

_69

_69

return aesjs.utils.utf8.fromBytes(decryptedBytes)

_69

}

_69

_69

async getItem(key: string) {

_69

const encrypted = await AsyncStorage.getItem(key)

_69

if (!encrypted) {

_69

return encrypted

_69

}

_69

_69

return await this._decrypt(key, encrypted)

_69

}

_69

_69

async removeItem(key: string) {

_69

await AsyncStorage.removeItem(key)

_69

await SecureStore.deleteItemAsync(key)

_69

}

_69

_69

async setItem(key: string, value: string) {

_69

const encrypted = await this._encrypt(key, value)

_69

_69

await AsyncStorage.setItem(key, encrypted)

_69

}

_69

}

_69

_69

const supabaseUrl = YOUR_REACT_NATIVE_SUPABASE_URL

_69

const supabaseAnonKey = YOUR_REACT_NATIVE_SUPABASE_ANON_KEY

_69

_69

const supabase = createClient(supabaseUrl, supabaseAnonKey, {

_69

auth: {

_69

storage: new LargeSecureStore(),

_69

autoRefreshToken: true,

_69

persistSession: true,

_69

detectSessionInUrl: false,

_69

},

_69

})


Once we've set up the storage mechanism, building an email and password sign in flow becomes pretty straight forward. Install @rneui/themed to get some nice cross platform button and input fields:


_10

npm install @rneui/themed


Set up a simple email form component:


_83

import React, { useState } from 'react'

_83

import { Alert, StyleSheet, View } from 'react-native'

_83

import { supabase } from '../lib/supabase'

_83

import { Button, Input } from '@rneui/themed'

_83

_83

export default function EmailForm() {

_83

const [email, setEmail] = useState('')

_83

const [password, setPassword] = useState('')

_83

const [loading, setLoading] = useState(false)

_83

_83

async function signInWithEmail() {

_83

setLoading(true)

_83

const { error } = await supabase.auth.signInWithPassword({

_83

email: email,

_83

password: password,

_83

})

_83

_83

if (error) Alert.alert(error.message)

_83

setLoading(false)

_83

}

_83

_83

async function signUpWithEmail() {

_83

setLoading(true)

_83

const {

_83

data: { session },

_83

error,

_83

} = await supabase.auth.signUp({

_83

email: email,

_83

password: password,

_83

})

_83

_83

if (error) Alert.alert(error.message)

_83

if (!session) Alert.alert('Please check your inbox for email verification!')

_83

setLoading(false)

_83

}

_83

_83

return (

_83

<View style={styles.container}>

_83

<View style={[styles.verticallySpaced, styles.mt20]}>

_83

<Input

_83

label="Email"

_83

leftIcon={{ type: 'font-awesome', name: 'envelope' }}

_83

onChangeText={(text) => setEmail(text)}

_83

value={email}

_83

placeholder="email@address.com"

_83

autoCapitalize={'none'}

_83

/>

_83

</View>

_83

<View style={styles.verticallySpaced}>

_83

<Input

_83

label="Password"

_83

leftIcon={{ type: 'font-awesome', name: 'lock' }}

_83

onChangeText={(text) => setPassword(text)}

_83

value={password}

_83

secureTextEntry={true}

_83

placeholder="Password"

_83

autoCapitalize={'none'}

_83

/>

_83

</View>

_83

<View style={[styles.verticallySpaced, styles.mt20]}>

_83

<Button title="Sign in" disabled={loading} onPress={() => signInWithEmail()} />

_83

</View>

_83

<View style={styles.verticallySpaced}>

_83

<Button title="Sign up" disabled={loading} onPress={() => signUpWithEmail()} />

_83

</View>

_83

</View>

_83

)

_83

}

_83

_83

const styles = StyleSheet.create({

_83

container: {

_83

marginTop: 40,

_83

padding: 12,

_83

},

_83

verticallySpaced: {

_83

paddingTop: 4,

_83

paddingBottom: 4,

_83

alignSelf: 'stretch',

_83

},

_83

mt20: {

_83

marginTop: 20,

_83

},

_83

})


Note, by default Supabase Auth requires email verification before a session is created for the users. To support email verification you need to implement deep link handling which is outlined in the next section.

While testing, you can disable email confirmation in your project's email auth provider settings.

As you saw above, we specified detectSessionInUrl: false when initializing supabase-js. By default, in a web based environment, supabase-js will automatically detect OAuth and magic link redirects and create the user session.

In native mobile apps, however, OAuth callbacks require a bit more configuration and the setup of deep linking.

To link to your development build or standalone app, you need to specify a custom URL scheme for your app. You can register a scheme in your app config (app.json, app.config.js) by adding a string under the scheme key:


_10

{

_10

"expo": {

_10

"scheme": "com.supabase"

_10

}

_10

}


In your project's auth settings add the redirect URL, e.g. com.supabase://**.

Finally, implement the OAuth and linking handlers. See the supabase-js reference for instructions on initializing the supabase-js client in React Native.


_68

import { Button } from 'react-native'

_68

import { makeRedirectUri } from 'expo-auth-session'

_68

import * as QueryParams from 'expo-auth-session/build/QueryParams'

_68

import * as WebBrowser from 'expo-web-browser'

_68

import * as Linking from 'expo-linking'

_68

import { supabase } from 'app/utils/supabase'

_68

_68

WebBrowser.maybeCompleteAuthSession() // required for web only

_68

const redirectTo = makeRedirectUri()

_68

_68

const createSessionFromUrl = async (url: string) => {

_68

const { params, errorCode } = QueryParams.getQueryParams(url)

_68

_68

if (errorCode) throw new Error(errorCode)

_68

const { access_token, refresh_token } = params

_68

_68

if (!access_token) return

_68

_68

const { data, error } = await supabase.auth.setSession({

_68

access_token,

_68

refresh_token,

_68

})

_68

if (error) throw error

_68

return data.session

_68

}

_68

_68

const performOAuth = async () => {

_68

const { data, error } = await supabase.auth.signInWithOAuth({

_68

provider: 'github',

_68

options: {

_68

redirectTo,

_68

skipBrowserRedirect: true,

_68

},

_68

})

_68

if (error) throw error

_68

_68

const res = await WebBrowser.openAuthSessionAsync(data?.url ?? '', redirectTo)

_68

_68

if (res.type === 'success') {

_68

const { url } = res

_68

await createSessionFromUrl(url)

_68

}

_68

}

_68

_68

const sendMagicLink = async () => {

_68

const { error } = await supabase.auth.signInWithOtp({

_68

email: 'example@email.com',

_68

options: {

_68

emailRedirectTo: redirectTo,

_68

},

_68

})

_68

_68

if (error) throw error

_68

// Email sent.

_68

}

_68

_68

export default function Auth() {

_68

// Handle linking into app from email app.

_68

const url = Linking.useURL()

_68

if (url) createSessionFromUrl(url)

_68

_68

return (

_68

<>

_68

<Button onPress={performOAuth} title="Sign in with GitHub" />

_68

<Button onPress={sendMagicLink} title="Send Magic Link" />

_68

</>

_68

)

_68

}


For the best user experience, it is recommended to use universal links which require a more elaborate setup. You can find the detailed setup instructions in the Expo docs.

Some native mobile operating systems, like iOS and Android, offer a built-in identity provider for convenient user authentication.

For iOS, apps that use a third-party or social login service to set up or authenticate the user’s primary account with the app must also offer Sign in with Apple as an equivalent option.

There are several benefits and reasons why you might want to add social login to your applications:

  • Improved user experience: Users can register and log in to your application using their existing app store accounts, which can be faster and more convenient than creating a new account from scratch. This makes it easier for users to access your application, improving their overall experience.

  • Better user engagement: You can access additional data and insights about your users, such as their interests, demographics, and social connections. This can help you tailor your content and marketing efforts to better engage with your users and provide a more personalized experience.

  • Increased security: Social login can improve the security of your application by leveraging the security measures and authentication protocols of the social media platforms that your users are logging in with. This can help protect against unauthorized access and account takeovers.

Sign in with Apple#

Supabase Auth supports using Sign in with Apple on the web and in native apps for iOS, macOS, watchOS, or tvOS.

For detailed setup and implementation instructions please refer to the docs and the video tutorial.

Sign in with Google#

Supabase Auth supports Sign in with Google on the web, native Android applications, and Chrome extensions.

For detailed set up and implementation instructions please refer to the docs and the video tutorial.

Supabase supports various forms of passwordless authentication:

Passwordless login mechanisms have similar benefits as the native mobile login options mentioned above.

In this post, we learned various authentication mechanisms we can use in React Native applications to provide a delightful experience for our users across native mobile and web.