I am using react-native 0.60.5, with firebase authentication (using package react-native-firebase and react-native-google-signin).
Everything looks good to me and the google sign return an object with the user logged in, but the idToken is always null. I need to get the idToken to perform the authentication in firebase.
import { GoogleSignin } from 'react-native-google-signin';
export const googleLogin = async () => {
GoogleSignin.configure();
const userInfo = await GoogleSignin.signIn();
//here we have the issue. userInfo cotains all google user informations except the idToken
//userInfo.idToken is null
}
how can I fix the google-sign-in to return the idToken?
Add the web client id which is availble in Firebase authentication/signInmethod/Google:
function configureGoogleSign() {
GoogleSignin.configure({
webClientId: WEB_CLIENT_ID,
offlineAccess: false
})
}
This is working for me.
You have not specified webclientId.
and make sure to configure google signIn in useEffect Method so when you load the screen it already configured.
useEffect(() => {
GoogleSignin.configure({
webClientId:
'YOUR_WEBCLIENT_ID',
});
}, []);
Related
I have been trying to implement sign in with google and apple using the following libraries and supabase in bare react-native projects.
react-native-apple-authentication
react-native-google-signin
They work very well with firebase as described here using firebase sdk.
The concept is fairly simple, the native sdk for both apple and google sign return user credential after a successful sign in . Here is an example from https://rnfirebase.io/auth/social-auth
With google credential
import auth from '#react-native-firebase/auth';
import { GoogleSignin } from '#react-native-google-signin/google-signin';
async function onGoogleButtonPress() {
// Get the users ID token
const { idToken } = await GoogleSignin.signIn();
// Create a Google credential with the token
const googleCredential = auth.GoogleAuthProvider.credential(idToken);
// Sign-in the user with the credential
return auth().signInWithCredential(googleCredential);
}
With apple credential
import auth from '#react-native-firebase/auth';
import { appleAuth } from '#invertase/react-native-apple-authentication';
async function onAppleButtonPress() {
// Start the sign-in request
const appleAuthRequestResponse = await appleAuth.performRequest({
requestedOperation: appleAuth.Operation.LOGIN,
requestedScopes: [appleAuth.Scope.EMAIL, appleAuth.Scope.FULL_NAME],
});
// Ensure Apple returned a user identityToken
if (!appleAuthRequestResponse.identityToken) {
throw 'Apple Sign-In failed - no identify token returned';
}
// Create a Firebase credential from the response
const { identityToken, nonce } = appleAuthRequestResponse;
const appleCredential = auth.AppleAuthProvider.credential(identityToken, nonce);
// Sign the user in with the credential
return auth().signInWithCredential(appleCredential);
}
I have gone through the auth provided by supabase here supabase-js auth
The closest thing I can find related to the implementation above is the use of a refresh-token as shown here
Sign in using a refresh token
// An example using Expo's `AuthSession`
const redirectUri = AuthSession.makeRedirectUri({ useProxy: false });
const provider = 'google';
AuthSession.startAsync({
authUrl: `https://MYSUPABASEAPP.supabase.co/auth/v1/authorize?provider=${provider}&redirect_to=${redirectUri}`,
returnUrl: redirectUri,
}).then(async (response: any) => {
if (!response) return;
const { user, session, error } = await supabase.auth.signIn({
refreshToken: response.params?.refresh_token,
});
});
The example above uses a refreshToken parameter auth.sign() to create a session for a user who is already registered.
Correct me if am wrong. According to the auth documentation there is no method that allows one to create a user using an auth credential. This is because of how gotrue social auth is implemented. The only solution I can think of as now is to move the entire auth logic to the backend and handle it on the web. This is not elegant at all since it will have to involve ugly deep-linking or webview implementations to use supabase session and access token.
Given the scenario above, is there way of using native social sdk in react-native to create a new user account in supabase using a user credential without having to force them use an email link, password or web ? Any ideas , answers or corrections are welcome.
At the time of writing, Signing in with third party credentials is not implemented in gotrue(Module used for auth in supabase) yet. If you have a native app, flutter app and react-native app that needs social auth using credentials follow up on this WIP:PR. For further information refer to Proof Key for Code Exchange (PKCE).
I develop a react-native (expo) mobile app and try to sign in with a google account to firebase, but I get an error:
"auth/operation-not-supported-in-this-enviroment. This operation is not supported in the enviroment this application is running on. "location.protocol" must be http, https or chrome-extension and web storage must be enabled"
Code:
loginGoogle() {
var provider = new firebase.auth.GoogleAuthProvider();
provider.addScope('profile');
provider.addScope('email');
firebase.auth().signInWithPopup(provider).then(function(result) {
var token = result.credential.accessToken;
var user = result.user;
return true;
}).catch(function(error) {
alert(error.code + '\n' +
error.message + '\n' +
error.email + '\n' +
error.credential);
return false;
});
}
signInWithPopup is not supported in react-native. You will need to use a third party OAuth library to get the OAuth ID token or access token and then sign in with Firebase:
const cred = firebase.auth.GoogleAuthProvider.credential(googleIdToken, googleAccessToken);
firebase.auth().signInWithCredential(cred)
.then((result) => {
// User signed in.
})
.catch((error) => {
// Error occurred.
});
Firebase does not support signInWithPopup in a React Native environment.
You can view a full list of supported environments on this page.
You can also submit a feature request for extended Firebase support for React Native here.
If you are using expo bare workflow or simple React native cli (or in simple words which contain android and ios folder) then simply use "React Native Firebase" library.
Here is the link https://rnfirebase.io/
But if you are using expo managed workflow(which donot contain android and ios folder ) then you have to follow below steps .
1.setup google developer account
use this guide to setup : https://docs.expo.dev/versions/latest/sdk/google/
Note that: use host.exp.exponent as the package name.
Another problem you may face in this step is generation of hash,which I also faced,the reason for that error is java dev kit(JDK) is not install ,so do install it before proceeding to this step.
2.Setup Firebase account
Simply setup firebase project as you set before, enable google sign in service
but this time the only change is you have to add client ID of your google developer account in (safest client id field) which will popup once you click on edit Google signin in firebase
look like this
3.Coding Part
import * as Google from 'expo-google-app-auth'; //imported from expo package
import {
GoogleAuthProvider,getAuth
} from 'firebase/auth';
import { initializeApp } from "firebase/app";
import { firebaseconfig } from '[your firebase credentials]';
const app=intitializeApp(firebaseconfig)
const auth=getAuth(app);
async function signInWithGoogleAsync() {
try {
const result = await Google.logInAsync({
androidClientId: 'cliend id from google dev console',
iosClientId: 'client id from google dev console for ios app(if you setup)',
scopes: ['profile', 'email'],
});
if (result.type === 'success') {
console.log(result)
const credential = GoogleAuthProvider.credential(result.idToken, result.accessToken);
// Sign in with credential from the Facebook user.
signInWithCredential(auth, credential)
.then(async result => {
console.log(result)
})
.catch(error => { console.log(error) });
return result.accessToken;
} else {
console.log("cancelled by user")
return { cancelled: true };
}
} catch (e) {
console.log(e);
return { error: true };
}//
}
I working with firebase auth and I'm a bit confused on how to manage the authentication between different apps, in particular nextjs (main site, that use express too) api and react app (is a kind of dashboard). After reading a bit of documentation what I did (but I'm not sure is the right way) is to get the idToken on the main site with the client side library:
firebase
.auth()
.signInWithEmailAndPassword(email, password)
.then(() => {
const currentUser = firebase.auth().currentUser.getIdToken();
currentUser.then(idToken => {
return axios.post("/auth/login", { idToken });
});
});
and make a request to nextjs/express to create the cookie sessions:
firebase
.auth()
.createSessionCookie(idToken, { expiresIn })
.then(
sessionCookie => {
res.cookie("session", sessionCookie, {
maxAge: expiresIn,
httpOnly: true
});
return res.end(JSON.stringify({ status: "success" }));
},
error => res.status(401).send(error)
);
then when I need to send a request to the api I'll pass the idtoken saved in the cookie and I verify the token in a middleware
const userInfo = await firebase.auth().verifySessionCookie(authToken);
I'm not implemented the react app yet but I think in that I'll just use the clientside library to do everything....My main doubt is the authentication between the nextjs/express and the api, I'm not sure if usin the sessioncookie is the right choise...do I need to send just the tokenId instead of the session cookie? do you have any suggestions?
I'm trying to implement Facebook OAuth (react-native-fbsdk) in my React Native application. I can get the Access Token. With the access token, I can then retrieve the credentials using const credential = yield facebookAuth.credential(data.accessToken); Then when I try to create a user, I get an error (see below)
The Credentials Object:
{
oauthIdToken: "MY_ID_TOKEN"
providerId: "facebook.com"
signInMethod: "facebook.com"
}
The Issue:
The last step that I want to do that I can't seem to figure out is to create a user in Firebase using the credentials in const user = yield call(reduxSagaFirebase.auth.signInAndRetrieveDataWithCredential, credential);
When I try and sign in with the credential, I get the following error: Invalid IdP response/credential http://localhost?id_token="MY_TOKEN_HERE
Login With Facebook Saga
// Redux Saga: Login With Facebook
function* loginWithFacebookSaga() {
try {
// Login To Facebook With Read Permissions
console.log('Logging in with Facebook');
yield LoginManager.logInWithPermissions([
'public_profile',
'email',
'user_friends',
]);
// Check If Cancelled
// if (!result.isCancelled) {
const data = yield AccessToken.getCurrentAccessToken();
// yield alert(JSON.stringify(data.accessToken));
// }
// Create Firebase Auth Account With Facebook Access Token
const credential = yield facebookAuth.credential(data.accessToken);
// alert(JSON.stringify(credential));
// Login (ISSUE HERE)
const user = yield call(reduxSagaFirebase.auth.signInAndRetrieveDataWithCredential, credential);
}
catch (error) {
// Firebase: Login Error
alert(error);
yield put(loginWithFacebookError(error));
}
};
UPDATE: You may got the problem with the credential. Please try below
import firebase from 'firebase';
const credential = firebase.auth.FacebookAuthProvider.credential(data.accessToken);
I am trying to get the Firebase authentication access token within a React Native application so that I can authenticate my API calls to a custom server. The Firebase documentation says I should get this token by using auth().currentUser.getIdToken(); however currentUser returns null.
I've tried to use getIdToken() in multiple areas of the application. I know the access token is generated as I can see it in the logs while using expo (user.stsTokenManager.accessToken).
Why is currentUser returning null and how can I get the accessToken?
You need to wrap user.getIdToken() inside of firebase.auth().onAuthStateChanged for user to be available. You can then use jwtToken in your header to authenticate your API calls. You need to import your Firebase configuration file for this to work.
let jwtToken = firebase.auth().onAuthStateChanged(function(user) {
if (user) {
user.getIdToken().then(function(idToken) { // <------ Check this line
alert(idToken); // It shows the Firebase token now
return idToken;
});
}
});
Just putting await before will work too just like this:
await auth().currentUser.getIdToken();
getIdToken returns a promise
firebase.auth()
.signInWithCredential(credential)
.then(async data => {
const jwtToken = await data.user?.getIdToken();
console.log(jwtToken);
})
Hook example
Unfortunately, its not reliable to directly get the token. You first have to listen to the authentication state change event which fires upon initialization since its asynchronous.
import {auth} from '../utils/firebase'
import {useState, useEffect} from 'react'
export default function useToken() {
const [token, setToken] = useState('')
useEffect(() => {
return auth().onAuthStateChanged(user => {
if (user) {
user.getIdToken(true)
.then(latestToken => setToken(latestToken))
.catch(err => console.log(err))
}
})
}, [])
return token
}
then use like so in your functional component
const token = useToken()
useEffect(() => {
if (token) {
// go wild
}
}, [token])