React Native with Google OpenID Connect - react-native

I am working on a react native application and I have some problems with OpenID connect. I would like to use some "Login with Google" functionality.
In normal (not native) react app I use the react-google-login library like this:
import { GoogleLogin} from 'react-google-login';
import axios from 'axios';
const CLIENT_ID = 'xxxxx.apps.googleusercontent.com';
const Login = () => {
const loginHandler = (response) => {
// I can use the OpenID JWT token got as response.tokenId e.g.
axios.get("/myapi", {
headers: {
Authorization: 'Bearer ' + response.tokenId
}
}).then(res => {
...
});
}
return (
<React.Fragment>
<GoogleLogin
clientId={CLIENT_ID}
buttonText='Login'
onSuccess={loginHandler}
cookiePolicy={'single_host_origin'}
responseType='code,token'
uxMode="redirect"
/>
</React.Fragment>
)
}
export default Login;
In the login handler as you can see I can use the OpenID JWT token and I can send it to the server.
I need the same in React Native but I haven't found any simple library for that. Neither of them returns the OpenID JWT token just the Oauth2 access token.
Does anybody have any idea which library I should use and how?
Thanks

Maybe you should use this library
npm install react-native-app-auth --savereact-native link react-native-app-auth
If you use yarn as a packet manager
yarn add #react-native-app-auth

Finally I managed to accomplish this with AppAuth

Related

React hooks and getStaticProps

I want to access hooks from getStaticProps to get the accessToken of the logged user which is saved in AuthContext. but this is impossible
I am using getStaticProps of Nextjs to pre-render pages, this is an example :
export async function getStaticProps() {
const result = await axios.get("http://127.0.0.1:5000/track/landing-tracks-for-admin");
return {
props: {
tracks: result.data,
},
revalidate: 5,
};
}
the problem is that this request needs the user accesToken which I can get from useAuth
import useAuth from "../../hooks/useAuth";
but when I try to call it in getStaticProps like this : const auth = useAuth();
I get this error
React Hook "useAuth" is called in function "getStaticProps" that is neither a React function component nor a custom React Hook function
any other alternatives ?
I guess you cannot authenticate the user like this. Please follow the documentation on Nextjs for authentication.
There is also an example repository for static page authentication using with-iron-session.
I suggest that you implement the user Authentication the nextjs way since you are using nextjs

How to use "promptAsync" from expo-auth-session, old library used in video tutorial was deprecated

I have been following the tinder 2.0 react native tutorial https://youtu.be/qJaFIGjyRms At 1:04:00 he sets the sign in method to: "await Google.logInAsync()" but I have noticed the google app auth library used in the video is now deprecated, I am redirected to use expo auth session instead but I notice there is a slight difference, where they used "await Google.logInAsync()" I must put "promptAsync" instead, when I do this I get the error promptAsync is undefined, I try with google.loginasync and get the same error that it is still undefined, what should I do? screenshot
code:
import React, { createContext, useContext } from 'react'
//import * as Google from 'expo-auth-session/providers/google';
import * as Google from 'expo-google-app-auth';
const AuthContext = createContext({});
const config = {
androidClientId:
'236293699216-9a0nknjdq7ie79h40iubg0tddokgogfv.apps.googleusercontent.com',
iosClientId:
'236293699216-6jdpm0rd6kn5d0qlbh1vgva5afgbqgib.apps.googleusercontent.com',
scopes: ["profile", "email"],
permissions: ["public_profile","email", "gender", "location"],
}
export const AuthProvider = ({ children}) => {
const signInWithGoogle = async() => {
await Google.logInAsync(config).then(async (logInResult) => {
if (logInResult.type === "success") {
// login
}
});
};
return (
<AuthContext.Provider
value={{
user: null,
signInWithGoogle
}}
>
{children}
</AuthContext.Provider>
)
}
export default function useAuth() {
return useContext(AuthContext);
}
I sought help on the forum that belongs to the maker of the video and other people had come across the same issue, one person recommended to go into package.json find the installed dependencies and change “expo-google-app-auth” from “^10.0.0” to “~9.0.0” and then npm I in the terminal, I have done this and I'm now getting the error “no such file or directory /Users/shangefagan/twinder-3/node_modules/expo-google-app-auth/node-modules/react-native/package.json” I have changed it back to “^10.0.0” but still getting the same error, screenshot
do I just npm uninstall expo-google-app-auth and try to use expo-auth-session as I was originally trying? if so What is the correct way to use promptAsync from the expo-auth-session library
I check the docs for both libraries, expo google app auth: https://docs.expo.dev/versions/v43.0.0/sdk/google/ and expo auth session: https://docs.expo.dev/versions/latest/sdk/auth-session/ but I am unsure exactly how to use the new login method "promptAsync"
To use promptAsync you have to use the package expo-auth-session. Like you said expo-google-app-auth is deprecated.

Is the function "signInWithPopup" from firebase supported on Expo?

I am trying to implement an authentication login method through Azure AD with Firebase on my Expo app.
Here is an extraction of my code, which looks exactly like the Firebase documentation:
const signInWithMicrosoft = () => {
const auth = initializeAuth(firebaseApp);
signInWithPopup(auth, provider)
.then((result) => {
const credential = OAuthProvider.credentialFromResult(result);
const accessToken = credential.accessToken;
const idToken = credential.idToken;
navigation.navigate("Home")
})
.catch((error) => {
// Handle error.
});
}
When pressing the button to activate the function, the following error message shows up:
TypeError: (0, _auth.signInWithPopup) is not a function. (In '(0, _auth.signInWithPopup)(auth, provider)', '(0, _auth.signInWithPopup)' is undefined)
I tried importing the functions as:
import { signInWithPopup } from "firebase/auth"
and
import { signInWithPopup } from "firebase/compat/auth"
And neither of them seem to work.
Is there any way I can get this function to work, or the solution would be going another way around? I don't know if functions such as SignInWithPopup and SignInWithRedirect are supported in Expo, since it is a Mobile application.
If you have any tip, clue or information on using firebase auth methods in a Expo app, please share below and I will be very happy to read it and comment on.

Firebase Google Sign In not working in React Native

import firebase from 'firebase';
import React from 'react';
import { useAuthState } from 'react-firebase-hooks/auth';
import App from './testlogin';
import { View, Text, Button } from 'react-native';
import { firebaseConfig } from './firebaseConfig';
const app = firebase.initializeApp(firebaseConfig);
const auth = app.auth();
const db = app.firestore();
const googleProvider = new firebase.auth.GoogleAuthProvider()
export const signInWithGoogle = async () => {
try {
const res = await auth.signInWithPopup(googleProvider);
const user = res.user;
const query = await db
.collection("users")
.where("uid", "==", user.uid)
.get();
if (query.docs.length === 0) {
await db.collection("users").add({
uid: user.uid,
name: user.displayName,
authProvider: "google",
email: user.email,
});
}
} catch (err) {
console.error(err);
alert(err.message);
}
};
This code accesses the google sign in method and should pop up a window, but I don't get anything when I click the button. I have been having difficulty with implementing Firebase in React Native and this is one of the examples. I need an example of easy Google sign in button in React Native.
I recommend you to use https://rnfirebase.io/ library (their docs are quite helpful).
Here are their instructions for Google Sign-in: https://rnfirebase.io/auth/social-auth#google.
According to them, you need to
ensure the "Google" sign-in provider is enabled on the Firebase Console.
also install #react-native-google-signin/google-signin',
then "Before triggering a sign-in request, you must initialize the Google SDK using your any required scopes and the webClientId, which can be found in the android/app/google-services.json"
Finally, as because following:
Starting April 2020, all existing applications using external 3rd party login services (such as Facebook, Twitter, Google etc) must ensure that Apple Sign-In is also provided. - You would also need to support iOS / and Apple Sign-in too. (if are building app also for iOS).
NOTE: I also remember that I had to put both, SHA1 and SHA256 hashes in the Firebase Console as some Firebase services were not working without it.
How to find SHA hashes in Android for Firebase (signing with Keystore that will be used in production should be already configured):
The debug signing certificate is optional to use Firebase with your app, but is required for Dynamic Links, Invites and Phone Authentication. To generate a certificate run
cd android && ./gradlew signingReport
and copy the SHA1 and SHA256 from the debug key. This generates two variant keys. You can copy the 'SHA1' that belongs to the debugAndroidTest variant key option.
Again, I recommend you to put both SHA hashes in Firebase Console.

React Native App Authentication with Instagram API

I've been trying to build a react native app that requires users to authenticate with their Instagram account. The Instagram API has a authorisation link and perhaps the only way to display that in an app would be through 'WebView' and so I used that.
The authentication workflow runs smoothly and then my server even gets the access token and user-id. But the problem is how to send this access token back to the app? I've used express-js for the 'redirect-uri' and so the WebView makes request to app.get() handler. In order to send response to same client on which the connection is opened, we must use res.send(). This would send the response to WebView, let's say I capture that using 'injectedJavaScript' but this javascript runs within WebView and so its unable to access react-native variables. In the event of a correct access-token, how would I ever navigate away from the WebView?
Any solutions to the above problems would be greatly appreciated. I suspect that there might even be problems with this approach(in my choice of WebView for this purpose, etc.), so a change of approach even entirely would also be of help. All I want is to authenticate the app users with Instagram and get my project going. Thanks a lot.
If you are using Expo, you can use AuthSessions to accomplish this (https://docs.expo.io/versions/latest/sdk/auth-session). The exact way to do it depends on whether you are using a managed workflow or a bare workflow, etc., but for managed workflow you can do the following:
Go to the Facebook Developer's console, go to your app, and add the Instagram Basic Display product.
Under Instagram Basic Display, under Valid OAuth Redirect URIs, use https://auth.expo.io/#your-expo-username/your-project-slug (project slug is in your app.json file)
On the same FB Developer page, add an Instagram tester profile and then follow the steps to authenticate that user.
In your project, install expo install expo-auth-session and import it into your Component
Also install expo-web-browser
Code your component like so:
import React, { useEffect } from 'react';
import { Button, Platform, Text, TouchableOpacity, View } from 'react-native';
import * as WebBrowser from 'expo-web-browser';
import { useAuthRequest, makeRedirectUri } from 'expo-auth-session';
WebBrowser.maybeCompleteAuthSession(); // <-- will close web window after authentication
const useProxy = Platform.select({ web: false, default: true });
const client_id = 9999999999999;
const redirect_uri = "https://auth.expo.io/#your-expo-username/your-project-slug";
const scope = "user_profile,user_media";
const site = "https://api.instagram.com/oauth/authorize?client_id=" + client_id + "&redirect_uri=" + redirect_uri + "&scope=" + scope + "&response_type=code&state=1";
const discovery = { authorizationEndpoint: site }
const GetInstagram = () => {
const [request, response, promptAsync] = useAuthRequest({
redirectUri: makeRedirectUri({
useProxy,
native: redirect_uri
}),
scopes: [scope],
clientId: client_id
}, discovery);
useEffect(() => {
if (response?.type === 'success') {
const { code } = response.params; <--- the IG code will be returned here
console.log("code : ", code);
}
}, [response]);
return (
<View>
<TouchableOpacity onPress={ () => promptAsync({useProxy,windowFeatures: { width: 700, height: 600 }}) }>
<Text>Connect Your Instagram</Text>
</TouchableOpacity>
</View>
)
}
export default GetInstagram;
One way to accomplish this is via using deeplink. I don't think it's the best practice though.
The response from the WebView will be sent to the redirect URL you've previously setup after successful authentication. Please set the redirect URL to your app. For example, on iOS if you have URL Scheme as "myapp123" then, anytime you open your browser and type myapp123://.. it will open your app and your app should be able to get response sent from the instagram.