React Native
This tutorial demonstrates how to add user login to an React Native with Expo application using BlitzWare.
1) Configure BlitzWare
Get Your Application Keys
You will need some details about your application to communicate with BlitzWare. You can get these details from the Application Settings section in the BlitzWare dashboard.

You need the Client ID.
Configure Redirect URIs
A redirect URI is a URL in your application where BlitzWare redirects the user after they have authenticated. The redirect URI for your app must be added to the Redirect URIs list in your Application Settings under the Security tab. If this is not set, users will be unable to log in to the application and will get an error.
2) Install the BlitzWare React Native SDK
Run the following command within your project directory to install the BlitzWare React Native SDK:
npm install blitzware-react-native-sdk
yarn add blitzware-react-native-sdk
Prerequisites
This SDK requires Expo and the following dependencies:
expo-auth-session
- For OAuth 2.0 authenticationexpo-secure-store
- For secure token storage
If using Expo managed workflow, these are included. For bare React Native, install them separately.
Platform Setup
iOS Setup
Add URL scheme to your
app.json
orapp.config.js
:
{
"expo": {
"scheme": "yourapp"
}
}
Android Setup
The URL scheme in app.json
automatically configures Android intent filters in Expo managed workflow.
For bare React Native, add to android/app/src/main/AndroidManifest.xml
:
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="yourapp" />
</intent-filter>
3) Implementation Guide
Follow this step-by-step guide to implement authentication in your app.
Step 1: Configure the Provider
Wrap your app with the BlitzWareAuthProvider
at the root level:
import React from 'react';
import { BlitzWareAuthProvider, BlitzWareConfig } from 'blitzware-react-native-sdk';
import { Stack } from 'expo-router';
export default function RootLayout() {
const blitzWareConfig: BlitzWareConfig = {
clientId: "your-client-id",
redirectUri: "yourapp://oauth", // Must match your app scheme
responseType: "code", // OAuth 2.0 authorization code flow
};
return (
<BlitzWareAuthProvider config={blitzWareConfig}>
<Stack>
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
</Stack>
</BlitzWareAuthProvider>
);
}
Step 2: Basic Authentication
Create your main authentication screen:
import React from "react";
import { StyleSheet, Pressable, View, Text } from "react-native";
import { useBlitzWareAuth } from "blitzware-react-native-sdk";
export default function HomeScreen() {
const { login, logout, isAuthenticated, user, isLoading, error } = useBlitzWareAuth();
const handleLogin = async () => {
try {
await login();
} catch (error) {
console.error("Login error:", error);
}
};
const handleLogout = async () => {
try {
await logout();
} catch (error) {
console.error("Logout error:", error);
}
};
return (
<View style={styles.container}>
<Text style={styles.title}>BlitzWare Authentication</Text>
{/* Authentication Status */}
<View style={styles.statusContainer}>
<Text style={styles.subtitle}>Status:</Text>
<Text>
{isLoading ? "Loading..." : isAuthenticated ? "Authenticated" : "Not Authenticated"}
</Text>
{/* Error Display */}
{error && (
<View style={styles.errorContainer}>
<Text style={styles.errorTitle}>Error:</Text>
<Text style={styles.errorText}>{error.message}</Text>
</View>
)}
{/* User Information */}
{user && (
<View style={styles.userContainer}>
<Text style={styles.subtitle}>User Info:</Text>
<Text>ID: {user.id}</Text>
<Text>Email: {user.email || "N/A"}</Text>
<Text>Username: {user.username || "N/A"}</Text>
</View>
)}
</View>
{/* Login/Logout Button */}
<View style={styles.buttonContainer}>
{!isAuthenticated ? (
<Pressable style={styles.button} onPress={handleLogin} disabled={isLoading}>
<Text style={styles.buttonText}>Login with BlitzWare</Text>
</Pressable>
) : (
<Pressable style={styles.button} onPress={handleLogout} disabled={isLoading}>
<Text style={styles.buttonText}>Logout</Text>
</Pressable>
)}
</View>
</View>
);
}
Step 3: Advanced Features - Session Validation
Add session validation for enhanced security:
import React, { useState } from "react";
import { Alert } from "react-native";
import { useValidateSession } from "blitzware-react-native-sdk";
export default function ProtectedScreen() {
const { isAuthenticated, user } = useBlitzWareAuth();
const validateSession = useValidateSession();
const [sessionValid, setSessionValid] = useState<boolean | null>(null);
const [validating, setValidating] = useState(false);
const handleValidateSession = async () => {
setValidating(true);
try {
const isValid = await validateSession();
setSessionValid(isValid);
Alert.alert(
"Session Status",
isValid ? "Session is valid!" : "Session expired. Please log in again."
);
} catch (error) {
console.error("Session validation error:", error);
Alert.alert("Error", "Failed to validate session");
} finally {
setValidating(false);
}
};
if (!isAuthenticated) {
return (
<View style={styles.container}>
<Text>Please log in to access this content</Text>
</View>
);
}
return (
<View style={styles.container}>
<Text style={styles.title}>Protected Content</Text>
<Text>Welcome, {user?.username || user?.email}!</Text>
{/* Session Status Display */}
{sessionValid !== null && (
<View style={[styles.statusBadge, {
backgroundColor: sessionValid ? '#4CAF50' : '#F44336'
}]}>
<Text style={styles.statusText}>
Session: {sessionValid ? 'Valid' : 'Invalid'}
</Text>
</View>
)}
<Pressable
style={styles.button}
onPress={handleValidateSession}
disabled={validating}
>
<Text style={styles.buttonText}>
{validating ? "Validating..." : "Check Session"}
</Text>
</Pressable>
</View>
);
}
Step 4: Access Token Management
Get access tokens for API calls:
import React from "react";
import { Alert } from "react-native";
import { useAccessToken } from "blitzware-react-native-sdk";
export default function ApiScreen() {
const getAccessToken = useAccessToken();
const makeApiCall = async () => {
try {
// Get the access token (automatically refreshed if needed)
const token = await getAccessToken();
if (!token) {
Alert.alert("Error", "No access token available");
return;
}
// Make authenticated API call
const response = await fetch("https://api.yourservice.com/protected", {
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
},
});
if (response.ok) {
const data = await response.json();
Alert.alert("Success", "API call successful!");
} else {
Alert.alert("Error", "API call failed");
}
} catch (error) {
console.error("API call error:", error);
Alert.alert("Error", "Failed to make API call");
}
};
const showTokenInfo = async () => {
try {
const token = await getAccessToken();
if (token) {
Alert.alert(
"Token Info",
`Length: ${token.length} characters\nPreview: ${token.substring(0, 20)}...`
);
} else {
Alert.alert("No Token", "No access token available");
}
} catch (error) {
Alert.alert("Error", "Failed to get token info");
}
};
return (
<View style={styles.container}>
<Text style={styles.title}>API Integration</Text>
<Pressable style={styles.button} onPress={makeApiCall}>
<Text style={styles.buttonText}>Make Protected API Call</Text>
</Pressable>
<Pressable style={styles.button} onPress={showTokenInfo}>
<Text style={styles.buttonText}>Show Token Info</Text>
</Pressable>
</View>
);
}
Step 5: Role-Based Access Control
Implement role-based features:
import { Tabs } from "expo-router";
import React from "react";
import { HapticTab } from "@/components/haptic-tab";
import { IconSymbol } from "@/components/ui/icon-symbol";
import { Colors } from "@/constants/theme";
import { useColorScheme } from "@/hooks/use-color-scheme";
import { useBlitzWareAuth } from "blitzware-react-native-sdk";
export default function TabLayout() {
const colorScheme = useColorScheme();
const { isAuthenticated, hasRole } = useBlitzWareAuth();
const isAdmin = hasRole("admin");
return (
<Tabs
screenOptions={{
tabBarActiveTintColor: Colors[colorScheme ?? "light"].tint,
headerShown: false,
tabBarButton: HapticTab,
}}
>
<Tabs.Screen
name="index"
options={{
title: "Home",
tabBarIcon: ({ color }) => (
<IconSymbol size={28} name="house.fill" color={color} />
),
}}
/>
<Tabs.Protected guard={isAuthenticated && isAdmin}>
<Tabs.Screen
name="admin"
options={{
title: "Admin",
tabBarIcon: ({ color }) => (
<IconSymbol size={28} name="person.fill" color={color} />
),
}}
/>
</Tabs.Protected>
<Tabs.Screen
name="explore"
options={{
title: "Explore",
tabBarIcon: ({ color }) => (
<IconSymbol size={28} name="paperplane.fill" color={color} />
),
}}
/>
</Tabs>
);
}
import React from "react";
import { useHasRole } from "blitzware-react-native-sdk";
export default function Dashboard() {
const { user } = useBlitzWareAuth();
const isAdmin = useHasRole('admin');
const isPremium = useHasRole('premium');
return (
<View style={styles.container}>
<Text style={styles.title}>Dashboard</Text>
<Text>Welcome, {user?.username}!</Text>
<Text>Roles: {user?.roles?.join(', ') || 'None'}</Text>
{/* Admin-only content */}
{isAdmin && (
<View style={[styles.card, styles.adminCard]}>
<Text style={styles.cardTitle}>🔧 Admin Panel</Text>
<Text>You have administrative privileges</Text>
</View>
)}
{/* Premium content */}
{isPremium && (
<View style={[styles.card, styles.premiumCard]}>
<Text style={styles.cardTitle}>⭐ Premium Features</Text>
<Text>Access to premium content</Text>
</View>
)}
{/* Regular user content */}
<View style={styles.card}>
<Text style={styles.cardTitle}>📊 User Stats</Text>
<Text>Standard user features available</Text>
</View>
</View>
);
}
That's it!
Last updated
Was this helpful?