Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP (/references/expo/local-credentials): update guide #1746

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 73 additions & 76 deletions docs/references/expo/local-credentials.mdx
Original file line number Diff line number Diff line change
@@ -1,20 +1,15 @@
---
title: Allow returning users to sign in with biometrics in Expo
description: Learn how to use the useLocalCredentials hook in your Expo app with Clerk.
title: Enable biometric sign-in for returning users in Expo
description: Learn how to use the useLocalCredentials() hook in your Expo app to enable biometric sign-ins for returning users.
---

Clerk's [`useLocalCredentials()`](/docs/references/expo/use-local-credentials) hook enables you to store a user's password credentials on their device and subsequently use biometrics for sign-in.

This guide shows you how to use the `useLocalCredentials()` hook to enhance your user experience by allowing users to sign in using biometrics when they re-sign in to your Expo app.

> [!WARNING]
> This API is available only for [@clerk/clerk-expo v2](/docs/upgrade-guides/expo-v2/upgrade) >=2.2.0.
> Be aware that this works only for sign in attempts with the password strategy.
> This feature requires @clerk/clerk-expo\@2.2.0 or later and works only for sign-in attempts that use the password strategy.

<Steps>
### Install the necessary peer dependencies
This guide demonstrates how to use the [`useLocalCredentials()`](/docs/references/expo/use-local-credentials) hook in your Expo app to securely store a user's password credentials on their device, enabling biometric sign-in for returning users.

These packages are required to be installed in order to use the `useLocalCredentials()` hook.
<Steps>
### Install dependencies

<CodeBlockTabs options={["npm", "yarn", "pnpm"]}>
```bash {{ filename: 'terminal' }}
Expand All @@ -32,82 +27,103 @@ This guide shows you how to use the `useLocalCredentials()` hook to enhance your

### Update `app.json`

Update your app.json file as instructed in the Expo documentation:
See the following Expo docs to update your `app.json` file with the necessary configurations for biometric sign-in. Replace `$(PRODUCT_NAME)` with your app's name as specified in the `"name"` field in your `app.json` file.

- [`expo-local-authentication`](https://docs.expo.dev/versions/latest/sdk/local-authentication/#configuration-in-appjsonappconfigjs)
- [`expo-secure-store`](https://docs.expo.dev/versions/latest/sdk/securestore/#configuration-in-appjsonappconfigjs)

### Securely store/access the user's credentials during sign in
### Securely store user credentials during sign-in

The following example demonstrates how to use `useLocalCredentials()` in a custom flow for signing users in.
The following example demonstrates how to use `useLocalCredentials()` in a custom flow for signing in users.

```tsx {{ filename: '/app/sign-in.tsx' }}
import { useSignIn } from '@clerk/clerk-expo'
import { Link, useRouter } from 'expo-router'
import { Text, TextInput, Button, View } from 'react-native'
import { useCallback, useState } from 'react'
import { useLocalCredentials } from '@clerk/clerk-expo/local-credentials'
import { Link, Stack, useRouter } from 'expo-router'
import { Text, TextInput, Button, View, TouchableOpacity, StyleSheet } from 'react-native'
import React from 'react'
import { SymbolView } from 'expo-symbols'

export default function Page() {
const { signIn, setActive, isLoaded } = useSignIn()
const router = useRouter()

const [emailAddress, setEmailAddress] = React.useState('')
const [password, setPassword] = React.useState('')
const { signIn, setActive, isLoaded } = useSignIn()
const { hasCredentials, setCredentials, authenticate, biometricType } = useLocalCredentials()

const onSignInPress = React.useCallback(
async (useLocal = false) => {
if (!isLoaded) {
return
}
const [emailAddress, setEmailAddress] = useState('')
const [password, setPassword] = useState('')

try {
const signInAttempt =
hasCredentials && useLocal
? await authenticate()
: await signIn.create({
identifier: emailAddress,
password,
})

if (signInAttempt.status === 'complete') {
if (!useLocal) {
await setCredentials({
const onSignInPress = useCallback(async (useLocal: boolean) => {
if (!isLoaded) return

// Start the sign-in process using the email and password provided
try {
const signInAttempt =
hasCredentials && useLocal
? await authenticate()
: await signIn.create({
identifier: emailAddress,
password,
})
}
await setActive({ session: signInAttempt.createdSessionId })

// navigate away
} else {
// handle other statuses of sign in
// If sign-in process is complete,
// set the created session as active and redirect the user
if (signInAttempt.status === 'complete') {
console.log('status is complete?', signInAttempt.status)

if (!useLocal) {
await setCredentials({
identifier: emailAddress,
password,
})
}
} catch (err: any) {
// handle any other error

await setActive({ session: signInAttempt.createdSessionId })
router.replace('/')
} else {
// If the status is not complete, check why.
// User may need to complete further steps.
console.error(JSON.stringify(signInAttempt, null, 2))
}
},
[isLoaded, emailAddress, password],
)
} catch (err) {
// For info on error handing,
// see https://clerk.com/docs/custom-flows/error-handling
console.error(JSON.stringify(err, null, 2))
}
}, [])

return (
<View>
<TextInput
autoCapitalize="none"
value={emailAddress}
placeholder="Enter email"
onChangeText={(emailAddress) => setEmailAddress(emailAddress)}
/>
<TextInput value={password} onChangeText={(password) => setPassword(password)} />
<Button title="Sign In" onPress={() => onSignInPress()} />

<TextInput
value={password}
placeholder="Enter password"
secureTextEntry={true}
onChangeText={(password) => setPassword(password)}
/>

<Button title="Sign In" onPress={() => onSignInPress(false)} />

{hasCredentials && biometricType && (
<TouchableOpacity onPress={() => onSignInPress(true)}>
<SymbolView
name={biometricType === 'face-recognition' ? 'faceid' : 'touchid'}
type="monochrome"
/>
</TouchableOpacity>
<Button
title={
biometricType === 'face-recognition' ? 'Sign in with Face ID' : 'Sign in with Touch ID'
}
onPress={() => onSignInPress(true)}
/>
)}

<View>
<Text>Don't have an account?</Text>

<Link href="/sign-up">
<Text>Sign up</Text>
</Link>
</View>
</View>
)
}
Expand Down Expand Up @@ -192,22 +208,3 @@ This guide shows you how to use the `useLocalCredentials()` hook to enhance your
}
```
</Steps>

## More resources

Use the following guides to learn more about Clerk components, how to build custom flows for your native apps, and how to use Clerk's client-side helpers.

<Cards>
- [Expo SDK](/docs/quickstarts/expo)
- Use Clerk with Expo to authenticate users in your React Native application.

---

- [Custom flows](/docs/custom-flows/overview)
- Expo native apps require custom flows in place of prebuilt components. Learn more about custom flows.

---

- [Client-side helpers](/docs/references/react/use-user)
- Clerk's client-side helpers enable you to access user data and perform actions on the client-side.
</Cards>
Loading