I have this function to log in by facebook method in firebase with React Native :
async handleFacebookButton() {
const navigation = this.props.navigation;
const { type, token } = await Facebook.logInWithReadPermissionsAsync(FACEBOOK_APP_ID, {
permissions: ['public_profile', 'email']
});
if (type === 'success') {
const credential = firebase.auth.FacebookAuthProvider.credential(token);
navigation.navigate("Profile");
auth.signInWithCredential(credential).catch(error => {
this.setState({ errorMessage: error.message });
alert('please check your email or password');
});
}
}
And I need to get the user data when login, like username, phone, email.
how can I get the data?
You need a .then() in your auth.signInWithCredential(). Then you'd have something like:
auth.signInWithCredential().then(user => {
// user is the signed in user, for which you can get details
})
Related
Node.js CODE
exports.user = async (req, res) => {
try {
const { wallet } = req.body;
if (!wallet) {
res.status(400).json({ error: "Not logged in" });
return;
} else {
user = User.findone(wallet);
// if user is not found then create a new user and mark as loggged In
if (!user) {
User.create({
user: wallet,
});
}
// if user found then create a session token and mark as logged
in
res.send({
user: wallet,
});
}
} catch (error) {
console.log(`ERROR::`, error);
}
};
REACTJs CODE
// post call/update
const axiosCall = async () => {
// core login will give a unique username by fulling a transcation
// core.login i dont have any control
const userAccount = await core.login();
try {
const res = await Axios.post(`${API}/user`, userAccount, dataToken);
setData({
...data,
error: "",
success: res.data.message,
});
} catch (error) {
setData({
...data,
error: error.response.data.error,
});
}
};
Now here the problem occurs when some one could modify userAccount in the front-end or someone could send a body with wallet: anything to my route localhost:3000/api/user
There is no option for me to check if some actually used core.login(); to get the wallet address.
So is there any solution?
I was thinking to allow only my server IP or localhost to hit the route localhost:3000/api/user and is that even possible?
Also there is another issue anyone could modify userAccount in front-end.
I'm trying to work out how to receive helpful error messages on the client side, but keep getting generic error messages. For example, trying to sign up with an email that is not available should result in the email#email.com is already in use error message. I, however, get the generic Request failed with status code 409 message, which is obviously unhelpful to the user. The network response is as expected as seen in the screenshot below. What gives? Why am I not getting the same error message as my (Redux) payload?
Below are the relevant code snippets.
Sign up controller
export default {
signup: async (req, res, next) => {
try {
const { fullname, username, email, password } = req.body;
// Check if there is a user with the same email
const foundUser = await User.findOne({ email });
if (foundUser) {
return res.status(409).send({ error: `${email} is already in use` });
}
const newUser = await User.create({
fullname,
username,
email,
password,
});
// Assign token to succesfully registered user
const token = authToken(newUser);
return res.status(200).send({ token, user: newUser });
} catch (error) {
next(error);
}
},
};
Sign up action
export const createAccount = ({
fullname,
username,
email,
password,
history
}) => async dispatch => {
dispatch({
type: actionTypes.CREATE_ACCOUNT_REQUEST,
});
try {
const {
data: {
newUser: { token, user },
},
} = await request.post('/auth/signup', {
fullname,
username,
email,
password,
});
localStorage.setItem('auth-token', token);
dispatch({
type: actionTypes.CREATE_ACCOUNT_SUCCESS,
payload: user
});
// Redirect to home
history.push('/home');
} catch (error) {
dispatch({
type: actionTypes.CREATE_ACCOUNT_FAILURE,
payload: error.message
});
}
};
Sign up network response
Redux sign up error payload
Try 'error.response.data.error' instead of 'error.message'
I'm having a problem with sending an authorization header with a graphql request when a user signs up with my react app.
My flow is:
User signs up with Firebase, react app receives id token.
User is redirected to another page where they can fill out more information.
User clicks submit, a request is sent via graphql (Apollo) to custom backend to create user.
The problem is when the user clicks submit on the secondary sign up page to enter their name, the request that is sent to the backend does not contain the authorization header. If I reload that page before clicking submit (this is after firebase sign up was successful), then it works as expected.
index.js:
const token = localStorage.getItem(AUTH_TOKEN);
const client = new ApolloClient({
link: new HttpLink({
uri: 'http://localhost:9000/graphql',
headers: {
authorization: token ? `Bearer ${token}` : ''
}
}),
cache: new InMemoryCache()
});
App.js:
componentWillMount() {
const _this = this;
firebaseApp.auth().onAuthStateChanged((user) => {
if (user) {
console.log('AUTH STATE CHANGED', user);
// If logged in...
_this.setState({ loggedin: true });
user.getToken()
.then((result) => {
localStorage.setItem(AUTH_TOKEN, result);
});
} else {
// If not logged in...
_this.setState({ loggedin: false });
}
});
}
SignUp.js (this is where the user can authenticate with firebase):
handleSubmit(e) {
e.preventDefault()
const email = this.state.email.trim()
const password = this.state.password.trim()
if (isEmail(email)) {
firebaseApp
.auth()
.createUserWithEmailAndPassword(email, password)
.then(() => {
browserHistory.push('/signupcontinued');
})
.catch((error) => {
// Handle Errors here.
const errorMessage = error.message
alert(`errorMessage: ${ errorMessage}`)
})
} else {
alert('Email Address in not valid')
}
}
SignUpContinued.js (where the user enters their name before sending create user request to custom backend):
const SignUpMutation = gql`
mutation CreateUser($userInput: UserInput!) {
user {
create(organizationId: 3, userInput: $userInput) {
id
firstName
lastName
email
organizationId
balance
}
}
}
`
class SignupContinued extends Component {
render() {
let firstname;
let lastname;
return (
<div>
<Mutation mutation={SignUpMutation}>
{(signup, { data }) => (
<div>
<form
onSubmit={e => {
e.preventDefault();
const userInput = {
firstName: firstname.value,
lastName: lastname.value,
email: (firebaseApp.auth().currentUser) ? firebaseApp.auth().currentUser.email : ''
}
signup({ variables: {
userInput
}}).then(() => {
browserHistory.push('/home')
});
firstname.value = '';
lastname.value = '';
}}
>
<input
placeholder='Enter First name'
ref={node => {
firstname = node;
}}
/>
<input
placeholder='Enter Last name'
ref={node => {
lastname = node;
}}
/>
<button type='submit'>Submit</button>
</form>
</div>
)}
</Mutation>
</div>
)
}
}
Am I correctly redirecting the user so that react reloads (and the ApolloClient updates its headers? Or is the issue something to do with my .then functions and onAuthStateChanged isn't done running before the redirect?
Thanks!
Apollo client gets token data from localStorage before firebase set token to localstorage. you should refresh apollo header after firebase setup
I am building a React Native app, I previously implemented Facebook login using login Manager
export const onLogin = () => {
return (dispatch) => {
console.log('inside login');
dispatch({ type: ON_LOGIN });
LoginManager.logInWithReadPermissions(['public_profile',
'email']).then((res) => {
console.log(res);
MakeGraphRequest(dispatch);
},
(error) => {
console.log(error);
LoginFail(dispatch, error);
});
};
};
function MakeGraphRequest(dispatch) {
const responseInfoCallback = (error: ?Object, result: ?Object) => {
if (error) {
console.log(error);
LoginFail(dispatch, error);
} else {
axios({
method: 'post',
url: 'url',
data: {
first_name: result.first_name,
last_name: result.last_name,
profile_photo: result.picture.data.url,
email: result.email,
spend_history: []
}
}).then((res) => {
if (res.data.userid) {
const userid = res.data.userid;
LoginSuccessForUnregisteredUser(dispatch, result, userid);
} else {
LoginSuccess(dispatch, result);
}
});
}
};
const infoRequest = new GraphRequest(
'/me',
{
parameters: {
fields: {
string: 'email, first_name, last_name, picture.type(large), birthday'
}
}
},
responseInfoCallback
);
new GraphRequestManager().addRequest(infoRequest).start();
}
Also I've used Login Button and Expo Facebook login but I could not find a way to implement this kind of a login.
Should I use Login Manager or Login Button. The Facebook docs are valid for web only. Is there a way to integrate this in my RN(react native) project?
You already have the user data in the response. So you can just start your screen (like in the picture) and ask if the user really wants to sign in with this account. Only after that, call your LoginSuccess events. If the user doesn't want to login just dispose the result data.
.then((res) => {
if (res.data.userid) {
const userid = res.data.userid;
// add screen logic here
// LoginSuccessForUnregisteredUser(dispatch, result, userid);
} else {
// add screen logic here
// LoginSuccess(dispatch, result);
}
});
Same would go with the Facebook Login Button or AuthSession.
Using AsyncStorage to save/fetch the state and get wether he goes or goes not to the "continue as" screen.
try {
await AsyncStorage.setItem('#MySuperStore:key', 'I like to save it.');
} catch (error) {
// Error saving data
}
try {
const value = await AsyncStorage.getItem('#MySuperStore:key');
if (value !== null){
// We have data!!
// show "continue as" screen
console.log(value);
}
} catch (error) {
// Error retrieving data
}
I am developing an app in React Native and I want to implement logging in with Facebook.
I have an API in Node.js where I handle the logic for users to log in, etc.
I use passport.js to let users log in with either Facebook or traditional Email.
I am opening an URL in my API with SafariView which is just a regular "WebView" directly in my app.
I have tried using the following code:
class FacebookButton extends Component {
componentDidMount() {
// Add event listener to handle OAuthLogin:// URLs
Linking.addEventListener('url', this.handleOpenURL);
// Launched from an external URL
Linking.getInitialURL().then((url) => {
if (url) {
this.handleOpenURL({ url });
}
});
}
componentWillUnmount() {
Linking.removeEventListener('url', this.handleOpenURL);
}
handleOpenURL({ url }) {
// Extract stringified user string out of the URL
const [, user_string] = url.match(/user=([^#]+)/);
this.setState({
// Decode the user string and parse it into JSON
user: JSON.parse(decodeURI(user_string))
});
if (Platform.OS === 'ios') {
SafariView.dismiss();
}
}
openURL(url) {
if (Platform.OS === 'ios') {
SafariView.show({
url: url,
fromBottom: true,
});
} else {
Linking.openURL(url);
}
}
render() {
return (
<Button
onPress={() => this.openURL('https://mywebsite.com/api/auth/facebook')}
title='Continue with Facebook'
...
so I guess I will have to do the authentication on URL https://mywebsite.com/api/auth/facebook and then send the user to an url that looks something like OAuthLogin://..., but I am not entirely sure how to use it.
Can anyone help me move in the right direction?
import { LoginManager, AccessToken } from 'react-native-fbsdk'; // add this file using npm i react-native-fbsdk
Create function
const onFacebookButtonPress = async () => {
// Attempt login with permissions
const result = await LoginManager.logInWithPermissions(['public_profile', 'email']);
if (result.isCancelled) {
throw 'User cancelled the login process';
}
// Once signed in, get the users AccesToken
const userInfo = await AccessToken.getCurrentAccessToken();
if (!userInfo) {
throw 'Something went wrong obtaining access token';
}
console.log('user info login', userInfo)
// Create a Firebase credential with the AccessToken
const facebookCredential = auth.FacebookAuthProvider.credential(userInfo.accessToken);
setGoogleToken(userInfo.accessToken)
// Sign-in the user with the credential
return auth().signInWithCredential(facebookCredential)
.then(() => {
//Once the user creation has happened successfully, we can add the currentUser into firestore
//with the appropriate details.
console.log('current User ####', auth().currentUser);
var name = auth().currentUser.displayName
var mSplit = name.split(' ');
console.log("mSplit ",mSplit);
let mUserDataFacebook = {
user_registration_email: auth().currentUser.email,
user_registration_first_name: mSplit[0],
user_registration_last_name: mSplit[1],
registration_type: 'facebook',
user_registration_role: "Transporter",
token: userInfo.accessToken,
user_image : auth().currentUser.photoURL,
};
console.log('mUserDataFacebook',mUserDataFacebook)
LoginWithGoogleFacebook(mUserDataFacebook) /// Call here your API
firestore().collection('users').doc(auth().currentUser.uid) //// here you can add facebook login details to your firebase authentication.
.set({
fname: mSplit[0],
lname: mSplit[1],
email: auth().currentUser.email,
createdAt: firestore.Timestamp.fromDate(new Date()),
userImg: auth().currentUser.photoURL,
})
//ensure we catch any errors at this stage to advise us if something does go wrong
.catch(error => {
console.log('Something went wrong with added user to firestore: ', error);
})
})
}
Call this function on button press onFacebookButtonPress()
For android need to setup and add facebook id in
android/app/src/main/res/values/strings.xml file
add these two lines.
YOUR_FACEBOOK_ID
fbYOUR_FACEBOOK_ID //Don't remove fb in this string value
/////////////add this code in AndroidMainfest.xml file
//////////This code add in MainApplication.java file
import com.facebook.FacebookSdk;
import com.facebook.appevents.AppEventsLogger;
/////////add code build.gradle file
implementation 'com.facebook.android:facebook-android-sdk:[5,6)'