React & Next.js SDK
React hooks and components for Glide Identity integration.
Installation
npm install glide-web-client-sdk
# or
yarn add glide-web-client-sdk
React Hook
import { usePhoneAuth } from 'glide-web-client-sdk/react';
function PhoneVerification() {
const {
verifyPhoneNumber,
getPhoneNumber,
isSupported,
isLoading,
error,
result
} = usePhoneAuth({
endpoints: {
prepare: '/api/phone-auth/prepare',
process: '/api/phone-auth/process'
},
debug: true
});
const handleVerify = async () => {
await verifyPhoneNumber('+14155551234', {
consent_data: {
consent_text: 'I agree to verify my phone number',
policy_link: 'https://example.com/privacy',
policy_text: 'Privacy Policy'
}
});
};
const handleGetPhone = async () => {
await getPhoneNumber({
consent_data: {
consent_text: 'I agree to share my phone number',
policy_link: 'https://example.com/privacy',
policy_text: 'Privacy Policy'
}
});
};
if (!isSupported) {
return <div>Your browser doesn't support phone verification</div>;
}
return (
<div>
<button onClick={handleVerify} disabled={isLoading}>
Verify Phone Number
</button>
<button onClick={handleGetPhone} disabled={isLoading}>
Get Phone Number
</button>
{isLoading && <p>Loading...</p>}
{error && <p>Error: {error.message}</p>}
{result?.verified && <p>✅ Phone verified!</p>}
{result?.phone_number && <p>📱 {result.phone_number}</p>}
</div>
);
}
Next.js App Router
1. Create Client Component
// app/components/PhoneAuth.jsx
'use client';
import { useState } from 'react';
import { PhoneAuthClient } from 'glide-web-client-sdk';
export default function PhoneAuth() {
const [phoneNumber, setPhoneNumber] = useState('');
const [isLoading, setIsLoading] = useState(false);
const [result, setResult] = useState(null);
const [error, setError] = useState(null);
const client = new PhoneAuthClient({
endpoints: {
prepare: '/api/phone-auth/prepare',
process: '/api/phone-auth/process'
}
});
const handleVerify = async (e) => {
e.preventDefault();
setIsLoading(true);
setError(null);
try {
const res = await client.verifyPhoneNumberComplete(phoneNumber, {
consent_data: {
consent_text: 'I agree to verify my phone number',
policy_link: 'https://example.com/privacy',
policy_text: 'Privacy Policy'
}
});
setResult(res);
} catch (err) {
setError(err);
} finally {
setIsLoading(false);
}
};
return (
<form onSubmit={handleVerify}>
<input
type="tel"
value={phoneNumber}
onChange={(e) => setPhoneNumber(e.target.value)}
placeholder="+14155551234"
required
/>
<button type="submit" disabled={isLoading}>
{isLoading ? 'Verifying...' : 'Verify Phone'}
</button>
{error && <div className="error">{error.message}</div>}
{result?.verified && <div className="success">✅ Phone verified!</div>}
</form>
);
}
2. Create API Routes
// app/api/phone-auth/prepare/route.js
import { GlideClient } from 'glide-sdk';
const glide = new GlideClient({
apiKey: process.env.GLIDE_API_KEY
});
export async function POST(request) {
try {
const body = await request.json();
const response = await glide.magicAuth.prepare(body);
return Response.json(response);
} catch (error) {
return Response.json(
{ error: error.message },
{ status: error.status || 500 }
);
}
}
// app/api/phone-auth/process/route.js
export async function POST(request) {
try {
const body = await request.json();
if (body.use_case === 'VerifyPhoneNumber') {
const response = await glide.magicAuth.verifyPhoneNumber(body);
return Response.json(response);
} else {
const response = await glide.magicAuth.getPhoneNumber(body);
return Response.json(response);
}
} catch (error) {
return Response.json(
{ error: error.message },
{ status: error.status || 500 }
);
}
}
Next.js Pages Router
API Routes
// pages/api/phone-auth/prepare.js
import { GlideClient } from 'glide-sdk';
const glide = new GlideClient({
apiKey: process.env.GLIDE_API_KEY
});
export default async function handler(req, res) {
if (req.method !== 'POST') {
return res.status(405).json({ error: 'Method not allowed' });
}
try {
const response = await glide.magicAuth.prepare(req.body);
res.json(response);
} catch (error) {
res.status(error.status || 500).json({ error: error.message });
}
}
Context Provider Pattern
// contexts/PhoneAuthContext.jsx
import { createContext, useContext, useState } from 'react';
import { PhoneAuthClient } from 'glide-web-client-sdk';
const PhoneAuthContext = createContext();
export function PhoneAuthProvider({ children }) {
const [client] = useState(() => new PhoneAuthClient({
endpoints: {
prepare: '/api/phone-auth/prepare',
process: '/api/phone-auth/process'
}
}));
return (
<PhoneAuthContext.Provider value={client}>
{children}
</PhoneAuthContext.Provider>
);
}
export function usePhoneAuthClient() {
const client = useContext(PhoneAuthContext);
if (!client) {
throw new Error('usePhoneAuthClient must be used within PhoneAuthProvider');
}
return client;
}
TypeScript Support
// types/phone-auth.ts
import { PhoneAuthClient } from 'glide-web-client-sdk';
interface UsePhoneAuthOptions {
endpoints: {
prepare: string;
process: string;
};
debug?: boolean;
}
interface UsePhoneAuthReturn {
verifyPhoneNumber: (phoneNumber: string, options?: any) => Promise<void>;
getPhoneNumber: (options?: any) => Promise<void>;
isSupported: boolean;
isLoading: boolean;
error: Error | null;
result: any;
}
// Component with types
const PhoneVerification: React.FC = () => {
const { verifyPhoneNumber, isLoading }: UsePhoneAuthReturn = usePhoneAuth({
endpoints: {
prepare: '/api/phone-auth/prepare',
process: '/api/phone-auth/process'
}
});
// ... rest of component
};
Error Handling
function PhoneVerification() {
const { verifyPhoneNumber, error } = usePhoneAuth({
endpoints: {
prepare: '/api/phone-auth/prepare',
process: '/api/phone-auth/process'
}
});
const getErrorMessage = (error) => {
switch (error?.code) {
case 'CARRIER_NOT_ELIGIBLE':
return 'Your carrier is not supported. Please try a different method.';
case 'PHONE_NUMBER_MISMATCH':
return 'The phone number does not match your device.';
case 'RATE_LIMIT_EXCEEDED':
return 'Too many attempts. Please try again later.';
default:
return error?.message || 'An error occurred. Please try again.';
}
};
return (
<div>
{error && (
<div className="error-message">
{getErrorMessage(error)}
</div>
)}
{/* ... rest of component */}
</div>
);
}