Skip to content

Commit

Permalink
feat: refactor oauth signin to use an in-app-browser
Browse files Browse the repository at this point in the history
  • Loading branch information
onehassan committed May 20, 2024
1 parent b3807ba commit 593fc03
Show file tree
Hide file tree
Showing 9 changed files with 96 additions and 94 deletions.
6 changes: 3 additions & 3 deletions examples/react-apollo/nhost/nhost.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[global]

[hasura]
version = 'v2.33.4-ce'
version = 'v2.38.0-ce'
adminSecret = '{{ secrets.HASURA_GRAPHQL_ADMIN_SECRET }}'
webhookSecret = '{{ secrets.NHOST_WEBHOOK_SECRET }}'

Expand Down Expand Up @@ -29,7 +29,7 @@ httpPoolSize = 100
version = 18

[auth]
version = '0.30.0-beta0'
version = '0.30.0-beta1'

[auth.elevatedPrivileges]
mode = 'required'
Expand Down Expand Up @@ -154,7 +154,7 @@ enabled = true
issuer = 'nhost'

[postgres]
version = '14.6-20240129-1'
version = '14.11-20240429-1'

[provider]

Expand Down
2 changes: 2 additions & 0 deletions examples/react_native/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,7 @@ import 'react-native-gesture-handler';
import {AppRegistry} from 'react-native';
import App from './src/root';
import {name as appName} from './app.json';
import {decode as atob} from 'base-64';
global.atob = atob;

AppRegistry.registerComponent(appName, () => App);
6 changes: 6 additions & 0 deletions examples/react_native/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1121,6 +1121,8 @@ PODS:
- glog
- RCT-Folly (= 2022.05.16.00)
- React-Core
- RNInAppBrowser (3.7.0):
- React-Core
- RNReanimated (3.8.1):
- glog
- RCT-Folly (= 2022.05.16.00)
Expand Down Expand Up @@ -1210,6 +1212,7 @@ DEPENDENCIES:
- ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`)
- "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)"
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
- RNInAppBrowser (from `../node_modules/react-native-inappbrowser-reborn`)
- RNReanimated (from `../node_modules/react-native-reanimated`)
- RNScreens (from `../node_modules/react-native-screens`)
- Yoga (from `../node_modules/react-native/ReactCommon/yoga`)
Expand Down Expand Up @@ -1334,6 +1337,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/@react-native-async-storage/async-storage"
RNGestureHandler:
:path: "../node_modules/react-native-gesture-handler"
RNInAppBrowser:
:path: "../node_modules/react-native-inappbrowser-reborn"
RNReanimated:
:path: "../node_modules/react-native-reanimated"
RNScreens:
Expand Down Expand Up @@ -1405,6 +1410,7 @@ SPEC CHECKSUMS:
ReactCommon: 8cae78d3c3eceff20ee4bbca8bb73b675a45fd5d
RNCAsyncStorage: 826b603ae9c0f88b5ac4e956801f755109fa4d5c
RNGestureHandler: bc2cdb2dc42facdf34992ae364b8a728e19a3686
RNInAppBrowser: e36d6935517101ccba0e875bac8ad7b0cb655364
RNReanimated: 2fb0146b2c87507286ad93d6112927eac48a34cb
RNScreens: b6b64d956af3715adbfe84808694ae82d3fec74f
SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17
Expand Down
3 changes: 3 additions & 0 deletions examples/react_native/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@
"@react-navigation/drawer": "^6.6.15",
"@react-navigation/native": "^6.1.17",
"@react-navigation/native-stack": "^6.9.26",
"base-64": "^1.0.0",
"react": "18.2.0",
"react-hook-form": "^7.51.2",
"react-native": "0.73.7",
"react-native-document-picker": "^9.2.0",
"react-native-gesture-handler": "^2.16.0",
"react-native-inappbrowser-reborn": "^3.7.0",
"react-native-reanimated": "^3.8.1",
"react-native-safe-area-context": "^4.9.0",
"react-native-screens": "^3.30.1",
Expand All @@ -37,6 +39,7 @@
"@react-native/eslint-config": "0.73.2",
"@react-native/metro-config": "0.73.5",
"@react-native/typescript-config": "0.73.1",
"@types/base-64": "^1.0.2",
"@types/react": "^18.2.6",
"@types/react-native-vector-icons": "^6.4.18",
"@types/react-test-renderer": "^18.0.0",
Expand Down
33 changes: 7 additions & 26 deletions examples/react_native/src/components/SignInWithAppleButton.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,12 @@
import Button from '@components/Button';
import {useNhostClient} from '@nhost/react';
import {Alert, Linking, StyleSheet, Text, View} from 'react-native';
import {StyleSheet, Text, View} from 'react-native';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';

export default function SignInWithAppleButton() {
const nhost = useNhostClient();

const handleSignInWithApple = async () => {
const {providerUrl} = await nhost.auth.signIn({
provider: 'apple',
options: {
redirectTo: 'myapp://',
},
});

if (providerUrl) {
try {
if (await Linking.canOpenURL(providerUrl)) {
Linking.openURL(providerUrl);
}
} catch (error) {
console.log(error);
Alert.alert('Error', 'An error occurred');
}
}
};

export default function SignInWithAppleButton({
hanldeSignIn,
}: {
hanldeSignIn?: () => Promise<void>;
}) {
return (
<Button
label={
Expand All @@ -35,7 +16,7 @@ export default function SignInWithAppleButton() {
</View>
}
color="black"
onPress={handleSignInWithApple}
onPress={hanldeSignIn}
/>
);
}
Expand Down
33 changes: 7 additions & 26 deletions examples/react_native/src/components/SignInWithGoogleButton.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,12 @@
import Button from '@components/Button';
import {useNhostClient} from '@nhost/react';
import {Alert, Linking, StyleSheet, Text, View} from 'react-native';
import {StyleSheet, Text, View} from 'react-native';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';

export default function SignInWithGoogleButton() {
const nhost = useNhostClient();

const handleSignInWithGoogle = async () => {
const {providerUrl} = await nhost.auth.signIn({
provider: 'google',
options: {
redirectTo: 'myapp://',
},
});

if (providerUrl) {
try {
if (await Linking.canOpenURL(providerUrl)) {
Linking.openURL(providerUrl);
}
} catch (error) {
console.log(error);
Alert.alert('Error', 'An error occurred');
}
}
};

export default function SignInWithGoogleButton({
handleSignIn,
}: {
handleSignIn: () => Promise<void>;
}) {
return (
<Button
label={
Expand All @@ -35,7 +16,7 @@ export default function SignInWithGoogleButton() {
</View>
}
color="#de5246"
onPress={handleSignInWithGoogle}
onPress={handleSignIn}
/>
);
}
Expand Down
35 changes: 5 additions & 30 deletions examples/react_native/src/screens/Main.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,15 @@
import CustomDrawer from '@components/Drawer';
import {useAuthenticationStatus, useNhostClient} from '@nhost/react';
import {createDrawerNavigator} from '@react-navigation/drawer';
import {NavigationContainer} from '@react-navigation/native';
import {createNativeStackNavigator} from '@react-navigation/native-stack';
import React, {useEffect} from 'react';
import {
ActivityIndicator,
StyleSheet,
View,
Linking,
Alert,
} from 'react-native';
import Profile from '@screens/Profile';
import SignUp from '@screens/SignUp';
import SignIn from '@screens/SignIn';
import CustomDrawer from '@components/Drawer';
import Todos from '@screens/Todos';
import SignUp from '@screens/SignUp';
import Storage from '@screens/Storage';
import Todos from '@screens/Todos';
import React from 'react';
import {ActivityIndicator, StyleSheet, View} from 'react-native';

const Drawer = createDrawerNavigator();
const Stack = createNativeStackNavigator();
Expand All @@ -32,25 +26,6 @@ function Main() {
const nhost = useNhostClient();
const {isAuthenticated, isLoading} = useAuthenticationStatus();

useEffect(() => {
const getRefreshTokenFromUrl = (url: string) => {
const regex = /[?&]refreshToken(=([^&#]*)|&|#|$)/;
const results = regex.exec(url);
if (!results || !results[2]) return null;
return decodeURIComponent(results[2].replace(/\+/g, ' '));
};

const handleDeepLink = async (event: {url: string}) => {
const refreshToken = getRefreshTokenFromUrl(event.url);
if (refreshToken) {
await nhost.auth.refreshSession(refreshToken);
}
};

const listener = Linking.addEventListener('url', handleDeepLink);
return () => listener.remove();
}, []);

if (isLoading) {
return <LoadingIndicatorView />;
}
Expand Down
41 changes: 38 additions & 3 deletions examples/react_native/src/screens/SignIn.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import {useNhostClient, useSignInEmailPassword} from '@nhost/react';
import {
useNhostClient,
useProviderLink,
useSignInEmailPassword,
} from '@nhost/react';
import {NavigationProp, ParamListBase} from '@react-navigation/native';
import {useForm} from 'react-hook-form';
import {
Expand All @@ -13,6 +17,7 @@ import Button from '@components/Button';
import ControlledInput from '@components/ControlledInput';
import SignInWithAppleButton from '@components/SignInWithAppleButton';
import SignInWithGoogleButton from '@components/SignInWithGoogleButton';
import InAppBrowser from 'react-native-inappbrowser-reborn';

interface SignUpFormValues {
firstName: string;
Expand All @@ -27,6 +32,10 @@ export default function SignIn({
navigation: NavigationProp<ParamListBase>;
}) {
const nhost = useNhostClient();
const {apple, google} = useProviderLink({
redirectTo: 'myapp://',
});

const {control, handleSubmit} = useForm<SignUpFormValues>();
const {signInEmailPassword, isLoading} = useSignInEmailPassword();

Expand All @@ -52,6 +61,32 @@ export default function SignIn({
}
};

const handleSignInWithOAuth = async (providerLink: string) => {
try {
const response = await InAppBrowser.openAuth(
providerLink,
'myapp://',
{},
);

if (response.type === 'success' && response.url) {
const refreshToken =
response.url.match(/refreshToken=([^&]*)/)?.at(1) ?? null;
if (refreshToken) {
await nhost.auth.refreshSession(refreshToken);
} else {
Alert.alert('Error', 'An error occurred during the sign-in process.');
}
}
} catch (error) {
console.log({error});
Alert.alert('Error', 'An error occurred during the sign-in process.');
}
};

const handleSignInWithApple = () => handleSignInWithOAuth(apple);
const handleSignInWithGoogle = () => handleSignInWithOAuth(google);

return (
<SafeAreaView style={{flex: 1}}>
<ScrollView
Expand Down Expand Up @@ -107,8 +142,8 @@ export default function SignIn({
onPress={handleSubmit(onSubmit)}
/>

<SignInWithAppleButton />
<SignInWithGoogleButton />
<SignInWithAppleButton hanldeSignIn={handleSignInWithApple} />
<SignInWithGoogleButton handleSignIn={handleSignInWithGoogle} />

<View
style={{
Expand Down
31 changes: 25 additions & 6 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 593fc03

Please sign in to comment.