react-native-social-x-auth
Version:
A lightweight React Native library for authenticating with X (formerly Twitter) using OAuth 2.0 with PKCE. Provides a secure and seamless login experience through Android Custom Tabs and iOS Safari ViewController. Built specifically for integrating X auth
87 lines (86 loc) • 3.05 kB
JavaScript
;
// useXAuth.ts
import { useEffect, useState, useCallback, useRef } from 'react';
import { Linking, Platform } from 'react-native';
import { generateCodeChallenge, generateCodeVerifier } from "./pkceUtils.js";
import SocialXAuth from "./NativeSocialXAuth.js";
export function useXAuth({
clientId,
redirectUri,
scopes = ['users.read'],
onSuccess,
onError
}) {
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const stateRef = useRef('');
const codeVerifierRef = useRef('');
function parseQuery(query) {
return query.split('&').map(param => param.split('=')).reduce((acc, [key, value]) => {
if (key !== undefined) {
acc[decodeURIComponent(key)] = decodeURIComponent(value ?? '');
}
return acc;
}, {});
}
useEffect(() => {
const handleDeepLink = event => {
const url = event.url;
const query = url.split('?')[1];
if (!query) return;
const params = parseQuery(query);
const code = params['code'];
const returnedState = params['state'];
if (!code) {
const err = new Error('No code in URL');
setError(err.message);
onError?.(err);
return;
}
if (stateRef.current !== returnedState) {
const err = new Error('Invalid state');
setError(err.message);
onError?.(err);
return;
}
onSuccess?.(code, codeVerifierRef.current);
};
const subscription = Linking.addEventListener('url', handleDeepLink);
return () => subscription.remove();
}, [onSuccess, onError]);
const startAuth = useCallback(async () => {
setLoading(true);
setError(null);
const state = Math.random().toString(36).substring(2);
stateRef.current = state;
const codeVerifier = generateCodeVerifier();
codeVerifierRef.current = codeVerifier;
const url = 'https://x.com/i/oauth2/authorize?' + `client_id=${encodeURIComponent(clientId)}` + `&redirect_uri=${encodeURIComponent(redirectUri)}` + '&response_type=code' + `&scope=${encodeURIComponent(scopes.join(' '))}` + `&state=${encodeURIComponent(state)}` + `&code_challenge_method=S256` + `&code_challenge=${encodeURIComponent(generateCodeChallenge(codeVerifier))}`;
try {
if (Platform.OS === 'android') {
const opened = await SocialXAuth.open(url);
if (!opened) {
throw new Error('Could not open auth window');
}
const supported = await Linking.canOpenURL(url);
if (!supported) throw new Error('Cannot open auth URL');
await Linking.openURL(url);
} else {
const supported = await Linking.canOpenURL(url);
if (!supported) throw new Error('Cannot open auth URL');
await Linking.openURL(url);
}
} catch (err) {
setError(err.message || 'Unknown error');
onError?.(err);
} finally {
setLoading(false);
}
}, [clientId, redirectUri, scopes]);
return {
startAuth,
loading,
error
};
}
//# sourceMappingURL=useXAuth.js.map