Implementing Local Authentication
1. Using Local Authentication
| Property | Description | Values |
|---|---|---|
| expo-local-authentication | Module for local authentication | expo-local-authentication |
Example: Check if local authentication is available
import * as LocalAuthentication from 'expo-local-authentication';
const hasHardware = await LocalAuthentication.hasHardwareAsync();
console.log("Has hardware: ", hasHardware);
Example: Authenticate with biometrics
import * as LocalAuthentication from 'expo-local-authentication';
const authResult = await LocalAuthentication.authenticateAsync({
promptMessage: 'Authenticate to proceed',
cancelLabel: 'Cancel',
});
console.log("Authentication result: ", authResult);
Note: On iOS, the device must have Face ID or Touch ID enabled for local authentication to work.
2. Checking Biometric Support
| Feature | Description | Support |
|---|---|---|
| Face ID | Biometric authentication using facial recognition | iOS / Android |
| Fingerprint | Biometric authentication using fingerprint scanning | iOS / Android |
| Iris Scan | Biometric authentication using iris recognition | iOS / Android |
| Touch ID | Biometric authentication using fingerprint scanning on iOS | iOS |
Example: Check Biometric Support
import * as LocalAuthentication from 'expo-local-authentication';
const checkBiometricSupport = async () => {
const supported = await LocalAuthentication.hasHardwareAsync();
console.log("Biometric hardware supported:", supported);
const types = await LocalAuthentication.supportedAuthenticationTypesAsync();
console.log("Supported authentication types:", types);
};
checkBiometricSupport();
Note: On Android, biometric support depends on the device's security settings and installed biometric sensors.
3. Authenticating User
| Property | Description | Example |
|---|---|---|
| authToken | Token used for authentication with the server | "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." |
| userCredentials | Credentials provided by the user (e.g., username/password) | { username: "john_doe", password: "secure123" } |
| refreshToken | Token used to obtain a new auth token when it expires | "refresh_token_abc123" |
Example: Basic Authentication Flow
import * as ExpoAuth from 'expo-auth';
const login = async () => {
const credentials = {
username: 'john_doe',
password: 'secure123'
};
try {
const response = await ExpoAuth.authenticate(credentials);
console.log('Authentication successful:', response.authToken);
} catch (error) {
console.error('Authentication failed:', error.message);
}
};
Note: Ensure that sensitive credentials are never stored in plain text. Use secure storage methods like
SecureStore for sensitive data.
Warning: Do not send passwords in plain text over the network. Always use HTTPS and secure authentication methods.
4. Checking Enrolled Biometrics
| Property | Description | Values | Notes |
|---|---|---|---|
| isEnrolledAsync() | Checks if the device has enrolled biometrics | Promise<boolean> |
Returns true if biometrics are enrolled, otherwise false |
| isEnrolledAsync(type) | Checks if the device has enrolled specific biometrics | Promise<boolean> |
Supports Face, Fingerprint, and Biometric |
Example: Checking Enrolled Biometrics
import * as LocalAuthentication from 'expo-local-authentication';
async function checkBiometrics() {
const isEnrolled = await LocalAuthentication.isEnrolledAsync();
console.log("Biometrics enrolled: ", isEnrolled);
}
checkBiometrics();
Example: Checking Specific Biometric Type
import * as LocalAuthentication from 'expo-local-authentication';
async function checkSpecificBiometrics() {
const isFaceEnrolled = await LocalAuthentication.isEnrolledAsync("Face");
const isFingerprintEnrolled = await LocalAuthentication.isEnrolledAsync("Fingerprint");
console.log("Face enrolled: ", isFaceEnrolled);
console.log("Fingerprint enrolled: ", isFingerprintEnrolled);
}
checkSpecificBiometrics();
Note: On Android,
isEnrolledAsync may return false even if biometrics are set up, due to platform limitations.
Warning: Always handle the case where biometrics are not enrolled, as users may have disabled them or not set them up.
5. Setting Authentication Options
| Option | Values | Description |
|---|---|---|
| authType | "local" | "oauth" |
Specifies the authentication method to use. "local" for username/password, "oauth" for third-party providers. |
| requireEmailVerification | true | false |
Enforces email verification before login. Defaults to false. |
| passwordPolicy | string |
Defines password strength requirements (e.g., "minLength:8;requireNumbers:true;"). |
| maxLoginAttempts | number |
Maximum login attempts before account lockout. Defaults to 5. |
| lockoutDuration | number |
Duration (in minutes) for which the account is locked after max attempts. Defaults to 30. |
Example: Configure Authentication Options
const authConfig = {
authType: "local",
requireEmailVerification: true,
passwordPolicy: "minLength:8;requireNumbers:true;",
maxLoginAttempts: 5,
lockoutDuration: 30
};
Note: These options are typically set in the backend configuration or via Expo's authentication service settings.
6. Handling Authentication Result
Example: Handle Authentication Result
import * as AuthSession from 'expo-auth-session';
const handleAuthResult = async (result) => {
if (result?.type === 'success') {
const { params } = result;
const accessToken = params.access_token;
const refreshToken = params.refresh_token;
// Store tokens securely
await SecureStore.setItemAsync('access_token', accessToken);
await SecureStore.setItemAsync('refresh_token', refreshToken);
// Redirect to app screen
navigation.replace('Home');
} else if (result?.type === 'dismissed') {
// User dismissed the auth session
console.log('Authentication was dismissed');
}
};
export default function AuthScreen() {
const [request, response, promptAsync] = AuthSession.useAuthRequest(
{
clientId: 'your-client-id',
redirectUri: AuthSession.makeRedirectUri(),
scopes: ['read', 'write'],
},
AuthSession.authTypes.PKCE
);
return (
<View style={styles.container}>
<Button
title="Login with OAuth"
onPress={() => promptAsync()}
/>
</View>
);
}
| Property | Description | Values |
|---|---|---|
| result.type | Indicates the outcome of the authentication flow | 'success', 'dismissed', 'error' |
| result.params | Parameters returned from the OAuth provider | Object containing tokens and metadata |
| result.error | Error object if authentication failed | Standard error object with message and code |
Note: Always validate and sanitize the tokens before storing them.
Warning: Never log or expose raw tokens in production environments.
7. Using Face ID (iOS)
| Property | Description | Values |
|---|---|---|
| requireFaceID | Indicates whether Face ID is required for authentication | true or false |
| fallback | Fallback authentication method if Face ID fails | FaceID, TouchID, or None |
Example: Enabling Face ID Authentication
import * as LocalAuthentication from 'expo-local-authentication';
const authenticateWithFaceID = async () => {
const hasHardware = await LocalAuthentication.hasHardwareAsync();
if (!hasHardware) {
console.log("Face ID not supported");
return;
}
const authResult = await LocalAuthentication.authenticateAsync({
promptMessage: "Authenticate with Face ID",
requireFaceID: true,
fallback: "TouchID"
});
if (authResult.success) {
console.log("Authentication successful");
} else {
console.log("Authentication failed");
}
};
Note: Face ID authentication is only available on iOS devices with Face ID hardware.
Warning: Ensure that your app has the appropriate permissions in
app.json or app.config.js to use Face ID.
| Property | Default Value | Description |
|---|---|---|
| requireFaceID | false |
Set to true to enforce Face ID usage |
| fallback | None |
Defines fallback authentication method if Face ID is not available |
8. Using Touch ID (iOS)
| Property | Description | Values |
|---|---|---|
| touchID | Enables or disables Touch ID authentication | true or false |
| touchIDPrompt | Custom message displayed to the user during Touch ID authentication | string |
Example: Enabling Touch ID Authentication
import * as LocalAuthentication from 'expo-local-authentication';
const authenticateWithTouchID = async () => {
const hasHardware = await LocalAuthentication.hasHardwareAsync();
if (hasHardware) {
const authResult = await LocalAuthentication.authenticateAsync({
promptMessage: 'Authenticate with your fingerprint',
fallbackEnabled: true
});
if (authResult.success) {
console.log('Authentication successful');
} else {
console.log('Authentication failed');
}
} else {
console.log('Touch ID not supported');
}
};
Note: Touch ID authentication requires the device to have a compatible sensor and the user must have enrolled fingerprints in the system.
Warning: Touch ID authentication is only available on iOS devices. For Android, consider using Face Recognition or Fingerprint scanning via
expo-local-authentication.
9. Using Fingerprint (Android)
| Property | Description | Values |
|---|---|---|
| fingerprint | Enables fingerprint authentication | true or false |
| fallback | Allows fallback to PIN or password | true or false |
Example: Enabling Fingerprint Authentication
import * as LocalAuthentication from 'expo-local-authentication';
const authenticateWithFingerprint = async () => {
const { success } = await LocalAuthentication.authenticateAsync({
promptMessage: 'Authenticate with fingerprint',
fallback: true,
});
if (success) {
console.log('Authentication successful');
} else {
console.log('Authentication failed');
}
};
Note: Fingerprint authentication is only available on Android devices with fingerprint sensors.
Warning: Ensure proper error handling for cases where fingerprint authentication is not supported or fails.
10. Setting Fallback to Passcode
When implementing local authentication in Expo, you can configure a fallback to passcode authentication if biometric authentication fails or is not available.
| Property | Description | Default |
|---|---|---|
| fallback | Specifies the fallback method when biometric authentication fails. Options include 'passcode', 'devicePasscode', or false. |
false |
Example: Configure fallback to passcode
import * as LocalAuthentication from 'expo-local-authentication';
const authenticateWithFallback = async () => {
const hasHardware = await LocalAuthentication.hasHardwareAsync();
const isEnrolled = await LocalAuthentication.isEnrolledAsync();
if (hasHardware && isEnrolled) {
const authResult = await LocalAuthentication.authenticateAsync({
fallback: 'passcode'
});
if (authResult.success) {
console.log("Authentication successful");
} else {
console.log("Authentication failed");
}
} else {
console.log("No biometric hardware or enrollment");
}
};
Note: The
fallback option is only supported on iOS and Android devices that have a passcode set up.
Warning: If the user has not set up a passcode, setting
fallback to 'passcode' will result in a failure.
11. Getting Biometric Types
| Property | Description | Values |
|---|---|---|
| biometryType | Indicates the type of biometric authentication available | FACE, FINGERPRINT, IRIS, UNKNOWN |
Example: Check Biometric Type
import * as LocalAuthentication from 'expo-local-authentication';
async function getBiometricType() {
const { biometryType } = await LocalAuthentication.getBiometricTypesAsync();
console.log("Biometric type:", biometryType);
}
getBiometricType();
12. Handling Authentication Cancellation
Example: Canceling Authentication Flow
import * as Authentication from 'expo-auth-session';
const handleAuthCancel = () => {
// Reset authentication state
setAuthState('idle');
// Clear any temporary tokens or data
clearAuthTokens();
// Notify user of cancellation
alert('Authentication was canceled');
};
// Example usage in a cancellation handler
const onCancel = () => {
handleAuthCancel();
// Optionally navigate back to previous screen
navigation.goBack();
};
| Property | Description | Usage |
|---|---|---|
| onCancel | Callback function triggered when authentication is canceled by user | Pass to authentication providers to handle cancellation |
| authState | Current state of authentication flow (idle, pending, success, error) | Used to manage UI state during cancellation |
Note: When handling cancellation, ensure all temporary authentication data is cleared to prevent security issues.
Warning: Do not reuse canceled authentication tokens or session data as they may be invalid.