Getstream firebase auth react native documentation? - firebase

Not sure if anyone has any experience with getstream and react native.
I followed there tutorial to implement getstreams SDK into my existing app and its working great but I'm stuck on tokens. I've successfully set up firebase so when a new user signs up I can see there UID and information over on both firebase auth and getstream but I'm hung up on my frontend getting the user to sign in on the chat with there token. I set up firebase with there extension but still having issues. Works great with dev.tokens but just can't get past this part. Is there any examples out there or better documentation for this? Thank you!
Only documentation I can find.. not specific to react native
https://getstream.io/chat/docs/react/tokens_and_authentication/
This is currently how I initialize my user.. the user token is hard coded in my chat config file.
// useChatClient.js
import { useEffect, useState } from 'react';
import { StreamChat } from 'stream-chat';
import { chatApiKey, chatUserId, chatUserName, chatUserToken } from './chatConfig';
const user = {
id: chatUserId,
name: chatUserName,
};
const chatClient = StreamChat.getInstance(chatApiKey);
export const useChatClient = () => {
const [clientIsReady, setClientIsReady] = useState(false);
useEffect(() => {
const setupClient = async () => {
try {
chatClient.connectUser(user, chatUserToken);
setClientIsReady(true);
// connectUser is an async function. So you can choose to await for it or not depending on your use case (e.g. to show custom loading indicator)
// But in case you need the chat to load from offline storage first then you should render chat components
// immediately after calling `connectUser()`.
// BUT ITS NECESSARY TO CALL connectUser FIRST IN ANY CASE.
} catch (error) {
if (error instanceof Error) {
console.error(`An error occurred while connecting the user: ${error.message}`);
}
}
};
// If the chat client has a value in the field `userID`, a user is already connected
// and we can skip trying to connect the user again.
if (!chatClient.userID) {
setupClient();
}
}, []);
return {
clientIsReady,
};
};

The next step is to request the token from the Firebase cloud function (ext-auth-chat-getStreamUserToken), and then initialise the current user with that token.
There is a guide and video showing how to do this using the Stream Chat Flutter SDK:
https://getstream.io/chat/docs/sdk/flutter/guides/token_generation_with_firebase/
https://youtu.be/Dt_taxX98sg

Related

Firebase Authentication JS does not populate `providerData`array

in a VueJS / QuasarJS application Im using firebase-js-sdk [1] together with firebaseui-web [2] to handle authentication.
After successful auth with any of the configured providers (e.g. password, google, apple, etc) I want to check which provider the user used. But immediately after successful authentication the user.providerData[] array that should contain the information is empty.
BUT if I reload my app the user.providerData[] array is suddenly populated correctly.
Iยดm checking for user data with something like this
import { getAuth } from "firebase/auth";
const auth = getAuth();
const user = auth.currentUser;
if (user) {
console.log(user.providerData)
}
After that the user object is fully populated (incl auth tokens, etc) but the user.providerData[] array is empty. Only after a page reload (CTRL-R) does the array get populated.
I searched both projects issues pages and documentation and didnt find anything that could explain this.
Im thankful for ANY idea where to look next!
EDIT
As suggested by #aside Im using onAuthStateChanged to check for updates of the user state.
onAuthStateChanged(
fbAuth,
(user) => {
if (user) {
console.log("onAuthStateChanged: user found");
console.log("onAuthStateChanged: user.providerData", user.providerData);
console.log("onAuthStateChanged: user", user);
} else {
console.log("onAuthStateChanged: no user found");
}
},
function (error) {
console.log("onAuthStateChanged:", error);
}
);
But even if I wait minutes after authentication is completed, still the user.providerData array is only populated after a page reload.
Here is a full demo: https://codesandbox.io/s/github/perelin/firebase-auth-providerdata-test
Thanks in advance :)
Im using
"firebase": "9.6.1",
"firebaseui": "6.0.0",
[1] https://github.com/firebase/firebase-js-sdk
[2] https://github.com/firebase/firebaseui-web
Your app should call getAuth().currentUser.reload() to refresh the local user data after login.
This could be done either in beforeRouteEnter() nav guard of the LoggedIn view:
// LoggedIn.vue
import { getAuth, signOut } from "firebase/auth";
export default {
async beforeRouteEnter(to, from, next) {
await getAuth().currentUser?.reload() ๐Ÿ‘ˆ
next()
},
}
demo 1
Or in the onAuthStateChanged callback:
// main.js
onAuthStateChanged(
fbAuth,
async (user) => {
await user?.reload() ๐Ÿ‘ˆ
},
)
demo 2
Your code is only running once instead of running every time the auth state is updated.
If you want to listen to any changes to the auth state, use a callback along with onAuthStateChanged as described here.
https://firebase.google.com/docs/auth/web/manage-users#get_the_currently_signed-in_user
import { getAuth, onAuthStateChanged } from "firebase/auth";
const auth = getAuth();
onAuthStateChanged(auth, (user) => {
if (user) {
// Check used provider here
const providerData = user.providerData;
// ...
} else {
// User is signed out
// ...
}
});
The reason checking/requesting the user object right after authentication does not work is that it might take firebase a second to update the providerData array. signInWithX might therefore return before the property is updated.

Send an email using Firebase Cloud Functions in React Native

I would like to send emails in my React Native using Firebase Cloud Functions. Users should be able to send an email for reporting issues/feedback in the app. I have created a text input and a button in my react native app. The user should be able to specify their issue/feedback in the text input box and when they press the button I will receive their response as an email in my gmail or hotmail account. Can I achieve this using onCreate in Firebase Cloud Functions? If so how can I achieve this? What would the onCreate method look like as well as the button function in react native? I am very new to react native and firebase cloud functions. Unfortunately, I haven't seen any links about this.
Thank you.
Please see below:
const nodemailer = require('nodemailer');
const email = functions.config().email_credentials.email;
const password = functions.config().email_credentials.password;
const mailTransport = nodemailer.createTransport(`smtps://${email}:${password}#smtp.gmail.com`);
functions.database.ref('/feedbacks/{currentId}').onCreate((snapshot, context) => {
const feedback = snapshot.val().feedback;
const name = snapshot.val().name;
const mailOptions = {
from: snapshot.val().email,
replyTo: snapshot.val().email,
to: functions.config().email_credentials.email,
subject: `Feedback from `+name,
html: feedback,
};
try {
mailTransport.sendMail(mailOptions);
} catch(error) {
console.log(error);
}
return null;
});
Realtime database:
Your cloud function could look like this:
import * as functions from "firebase-functions";
import admin from "firebase-admin";
import nodemailer from "nodemailer";
const { email, password } = functions.config().gmail;
const mailTransport = nodemailer.createTransport(
`smtps://${email}:${password}#smtp.gmail.com`
);
export default functions.database
.ref("/feedbacks/{uid}")
.onCreate(async (eventSnapshot, context) => {
const data = eventSnapshot.val();
const { feedback } = data;
const mailOptions = {
from: functions.config().email_credentials.email,
replyTo: functions.config().email_credentials.email,
to: snapshot.val().email,
subject: `Feedback from `+name,
html: feedback,
};
await mailTransport.sendMail(mailOptions);
return null;
});
Make sure to save your email credentials under the firebase cloud function configs and NOT in the code. If you put it anywhere in the code it could potentialy been read by someone in some time. This is very importand.
In your Gmail ensure "Unsercure Apps" are enabled. More about it here.
Now if someon adds some data to the path feeds and email will be send.
Don't forget to deplyo your function with the configs.

This operation is not supported in the environment this application is runnung on [duplicate]

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 };
}//
}

Firebase Auth in a Flutter app with WebView

I'm developing a Flutter app that uses Firebase Auth to handle authentication. However, some sections of the app use a WebView that shows content from the web version (which also uses Firebase Auth). My question is to how ensure that users that have signed in to the app are also signed in within the WebView.
There's nothing built into Firebase to automatically synchronize the authentication state from native code into a web view that is opened from this native code.
It should be possible to pass the ID token from the native code to the web view and use it there, but I've never tried that myself.
Some relevant links that I found:
How to pass Firebase Auth token to webView and register for notifications on Android (describes the same problem, but then with Android - and unfortunately without an answer)
Is there a way to keep the user signed in between native code and a WebView using Firebase Auth on Android? (unfortunately also without an answer)
Webviews and social authentication with React Native (blog post describing a workaround for this type of problem with Facebook login and react native)
How to do Authentication on native and pass to webView? (also with React Native, but this answer looks promising)
capacitor-firebase-auth npm module (plugin for Capacitor framework that propagates the token from native code to web view)
None of these are pre-built solutions for Flutter + WebView, but I hope that combined they allow you to build something yourself. If you do: please share it! :)
Here is solution for Firebase Auth with WebView in React Native:
import React from 'react'
import WebView from 'react-native-webview'
export default function HomeScreen(props) {
// props.user represents firebase user
const apiKey = props.user.toJSON().apiKey
const authJS = `
if (!("indexedDB" in window)) {
alert("This browser doesn't support IndexedDB")
} else {
let indexdb = window.indexedDB.open('firebaseLocalStorageDb', 1)
indexdb.onsuccess = function() {
let db = indexdb.result
let transaction = db.transaction('firebaseLocalStorage', 'readwrite')
let storage = transaction.objectStore('firebaseLocalStorage')
const request = storage.put({
fbase_key: "firebase:authUser:${apiKey}:[DEFAULT]",
value: ${JSON.stringify(props.user.toJSON())}
});
}
}
`
return <WebView
injectedJavaScriptBeforeContentLoaded={authJS}
source={{
uri: 'http://192.168.1.102:3000',
baseUrl: 'http://192.168.1.102:3000',
}}
/>
}
Similar logic might be required in Flutter (JS injection).
High Level
From Flutter mobile client, sign in to Firebase
Generate a unique Firestore document for the logged in user, setting whatever auth data you need to lookup via calls from the webView - eg, uid, email, etc
Pass that doc.id to the webView, and use that token value as a parameter for cloud functions being called from the webView, that require the logged-in user data
Code
Implementation requires 5 small JS blocks between Firebase cloud and the browser:
From Flutter mobile client, call cloud function to give you a unique token, where token will be a doc ID and data will have Auth User uid:
exports.getWebAppUserToken = functions.https.onCall(async (data, context) => {
let docRef = await firestore.collection('webTokens')
.add({uid : context.auth['uid']});
return {'webToken' : docRef.id};
});
Pass the token into the url called to open the webview, eg: http://app.com/appPage/<token>, and then extract token in browser:
getValidationToken() {
let href = window.location.href;
let lastIdx = href.lastIndexOf('/');
return href.substr(lastIdx + 1).trim();
}
Now from the browser you can call a cloud function using the token:
const authFuncCalledFromWeb =
firebase.functions().httpsCallable('authFuncCalledFromWeb');
const result = await authFuncCalledFromWeb(uiValidationToken);
Cloud function that uses the webToken to get uid for the request:
exports.authFuncCalledFromWeb = functions.https.onCall(async (data, context) => {
let webToken = data;
let uid = await getWebTokenUid(webToken);
// >>> do stuff that requires uid
});
Helper to lookup webToken:
getWebTokenUid = async function (webToken) {
let webTokenDoc = await firestore.collection(appData.Collctn.webTokens)
.doc(webToken).get();
let webTokenDocData = webTokenDoc.data();
return webTokenDocData['uid'];
}
=================
Here's a variation if you want to consider expiring the token:
<!-- begin snippet: js hide: true -->
let EXPIRES_INTERVAL = 1000 * 60 * 20;
exports.getWebAppUserToken = functions.https.onCall(async (data, context) => {
logr.enter(`getWebAppUserToken`);
const uid = appConfig.getLoggedInUid(context);
logr.i(`uid: ${uid}`);
// For Field.expires, consider that webToken will not be
// looked up until user clicks HTML submit action.
// So whatever interval we give, we should check in client
// On the other hand, user can only get this token through
// the app in a cloud func, so expires may not be nec.
let expiresTimestamp = dateUtil.getNowNumericTimestamp() + EXPIRES_INTERVAL;
let webTokenProfile = {
[Field._created] : dateUtil.getNowReadableTimestampPST(),
[Field.expires] : expiresTimestamp,
[Field.uid] : uid,
}
let docRef = await firestore.collection('webTokens')
.add(webTokenProfile);
let webToken = docRef.id;
return {'data' : webToken};
});

What's the difference between the 'firebase' module, and the "Firebase" one from Ionic Native, in Ionic

Currently found this question (which also puzzled me), but I'm currently using "firebase" to authenticate, and "Firebase" from Ionic Native to get analytics data on the Firebase console. I think that one of these is redundant (since I have the Firebase initialization data once as an object in code, and another one in google-services.json).
So what is the difference, are these two packages substitutes for each other, or is there something else.
u talk about node-modules in ionic. im using if i understand to using it. and my experience tell me its not substitutes for each other. Lets talk about the modules.
First if using:
import firebase from 'firebase'
or
import * as firebase from "firebase";
working with dataSnapshot, snapshot, snap.
if i need object to array data from firebase example:
import firebase from 'firebase';
this.addProduct = firebase.database().ref('/product-List');
this.addProduct.on('value', snapshot => {
this.productList = [];
snapshot.forEach( snap => {
this.productList.push({
category: snap.val().category,
id: snap.key,
in_stock: snap.val().in_stock,
name: snap.val().name,
downloadURL: snap.val().downloadURL,
short_description: snap.val().short_description,
description: snap.val().description,
regular_price: snap.val().regular_price,
sale_price: snap.val().sale_price,
brand: snap.val().brand,
vendor: snap.val().vendor
});
});
});
}
another node-modules ionic-native/firebase
import {Firebase} from '#ionic-native/firebase';
plugin for push notifications, event tracking, crash reporting, analytics and more.
in my case. im using for login with phone and verifyPhoneNumber example:
import {Firebase} from '#ionic-native/firebase';
constructor(private firebasePlugin: Firebase) {
}
Private registerPhone(): void {
if (!this.phoneNumber.value) {
alert('Mohon isi nomor telepon anda');
return;
}
const appVerifier = this.recaptchaVerifier;
const phoneNo = '+62' + this.phoneNumber.value;
if (this.platform.is('cordova')) {
try {
this.firebasePlugin.verifyPhoneNumber(phoneNo, 60).then (credential=> {
// alert("SMS Kode Verifikasi Berhasil dikirim ke Nomor Telp anda");
console.log(credential);
this.showPrompt(credential.verificationId);
}).catch (error => {
console.error(error);
});
}catch(error){alert(error.message)}
}
}

Resources