Firebase Phone Auth with React Native does not accept certain real numbers - javascript

I seem to have broken something in the Firebase Phone Auth. I am using my own backend system and Firebase with React Native only for Phone Auth and FCM.
The background is that I had an old project which I was using for auth. Later there had to be another app, so instead of having multiple apps under the same project, I created two new projects for each of the apps. Then I removed all apps from the old project.
Now when I use the real phone numbers which were used with the old project, they no longer seem to work. Test numbers set up under the new projects are all fine.
I can't afford to "waste" any more real numbers in case they become unusable too for further testing.
Using the React Native Firebase module, it looks something like:
auth()
.signInWithPhoneNumber(phoneNumber)
.then(confirmation => {
dispatch({
type: PHONENUMBER_SIGNIN_SUBMIT_SUCCESS,
payload: confirmation,
});
})
.catch(error => {
console.log('received error from firebase auth', JSON.stringify(error));
dispatch({
type: PHONENUMBER_SIGNIN_SUBMIT_FAIL,
payload: error,
});
});
With the phone numbers which were used with the old project, it ends up in the catch block, with a cryptic error message {"line":7186,"column":64,"sourceURL":"http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.xxx.yyy&modulesOnly=false&runModule=true"}
This line 7186 is in a code block that looks like this
7172 module.exports = _wrapNativeSuper = function _wrapNativeSuper(Class) {
7173 if (Class === null || !_$$_REQUIRE(_dependencyMap[0], "./isNativeFunction.js")(Class)) return Class;
7174
7175 if (typeof Class !== "function") {
7176 throw new TypeError("Super expression must either be null or a function");
7177 }
7178
7179 if (typeof _cache !== "undefined") {
7180 if (_cache.has(Class)) return _cache.get(Class);
7181
7182 _cache.set(Class, Wrapper);
7183 }
7184
7185 function Wrapper() {
7186 return _$$_REQUIRE(_dependencyMap[1], "./construct.js")(Class, arguments, _$$_REQUIRE(_dependencyMap[2], "./getPrototypeOf.js")(this).constructor);
7187 }
7188
7189 Wrapper.prototype = Object.create(Class.prototype, {
7190 constructor: {
7191 value: Wrapper,
7192 enumerable: false,
7193 writable: true,
7194 configurable: true
7195 }
7196 });
7197 return _$$_REQUIRE(_dependencyMap[3], "./setPrototypeOf.js")(Wrapper, Class);
7198 };
Since I have no clue what could be causing this problem, any help and solution approach will be very appreciated.

Related

React Native: AWS amplify requires that I tap `federatedSignIn` twice for google to succeed

My app is requiring that google oauth (via federatedSignIn) be tapped twice in iOS devices, prior to actually signing the user in.
Process:
Upon the first tap, inapp browser opens up and you select which account you're intending to sign in with. Inapp browser closes and seems like all the rest of my logic is not being hit.
Upon the second tap, the inapp browser re-opens up again for a split second (screen is blank), and then closes and THEN the user is actually signed in.
On the iOS simulator/android, however, it seems like it works as expected. Another strange thing is that it works as expected for oauth'ing in with Apple on all devices.
Wondering if anyone else has run into this issue and if y'all have a suggestion?
Where I instantiate the hub listener:
useEffect(() => {
// NOTE: amplify hub listener
const listener = async (data: any) => {
switch (data.payload.event) {
case "signIn":
case "cognitoHostedUI":
await signInUser();
break;
case "signOut":
setUser(null);
break;
default:
break;
}
};
Hub.listen("auth", listener);
}, []);
My google oauth button component:
export function GoogleSignInButton({ title }: GoogleSignInButtonProps) {
return (
<SocialIcon
button
type="google"
title={title}
style={{ padding: 50, marginBottom: 10 }}
onPress={() =>
Auth.federatedSignIn({
provider: "Google" as any,
}).catch(federatedSignInError => {
console.log({ federatedSignInError });
throw new Error(federatedSignInError);
})
}
/>
);
}
I'm also using the react-native-inappbrowser-reborn npm package to have an internal webview when signing in, if that's relevant:
async function urlOpener(url: string, redirectUrl: string) {
await InAppBrowser.isAvailable();
const { type, url: newUrl } = (await InAppBrowser.openAuth(url, redirectUrl, {
showTitle: false,
enableUrlBarHiding: true,
enableDefaultShare: false,
ephemeralWebSession: false,
})) as RedirectResult;
if (type === "success") {
Linking.openURL(newUrl);
}
}
const appsyncAuthenticationTypeOverride = {
...config,
oauth: {
...config.oauth,
urlOpener,
},
aws_appsync_authenticationType: "AWS_IAM",
};
Amplify.configure(appsyncAuthenticationTypeOverride);
i had the same issue.
It seems to be related to Cookies in navigator, you seem to be loading the during the first logging attempt, and using the during the second one.
Also it seems to be sometimes related to redirection errors in Cognito Auth Flow.
I managed to solve it by finding this issue :
https://github.com/aws-amplify/amplify-js/issues/7468
Especially this comment :
https://github.com/aws-amplify/amplify-js/issues/7468#issuecomment-816853703

How to hit/consume post and get api in React Native with Ignite Bowser 2 Boilerplate. (Mobx state stree, type script)

I am new to React Native, please provide some Github link or your own code for reference. Consider me as a beginner in RN.
I found very less open support for RN, Mobx State tree, Ignite and all, so not just post and get API reference, if you find anything helpful related to these above-mentioned topics, Feel free to share.
Thanks in advance.
Mobx State Tree, With Ignite Bowler you would have api.ts file where you can specify API calls.
async getUser(userToken: string): Promise<Types.GetUserResult> {
// make the api call
const response: ApiResponse<any> = await this.apisauce.post(`api/v1/sales/login?authCode=${userToken}`)
if (!response.ok) {
const problem = getGeneralApiProblem(response)
if (problem) return problem
}
// transform the data into the format we are expecting
try {
try {
const rawUser = response.data
console.log('rawUser'+ rawUser)
const user: UserSnapshot = convertRawUserToUserStore(rawUser)
return { kind: "ok", user }
console.log({ user })
} catch (e) {
__DEV__ && console.tron.log(e.message)
return { kind: "bad-data" }
}
} catch {
return { kind: "bad-data" }
}
}
Consider, we will be getting user data from this API call,
you can notice that there is UserSnapshot which belongs to User Model, Snapshot will save the data automatically, you don't need Aysnc storage to save or retrieve data.

Unable to bind 'this' to callback function of AcquireTokenSilent - Azure AD MSAL & ReactJS

I am setting up authentication in ReactJS app using AzureAD MSAL. I am able to obtain id_token and access_token. But while getting access token, I am not able tot refer to local variables via this keyword. I tried to bind 'this' to the call back function but that leads to other issues.
I am implementing all the login functionality as a class.
import { UserAgentApplication } from "msal";
export default class AuthService {
constructor() {
this.applicationConfig = {
clientID: "<clientId>",
authority: "<azureADTenantUrl>"
};
this.scopes = [
"openid",
"<Other scopes>"
];
this.client = new UserAgentApplication(
this.applicationConfig.clientID,
this.applicationConfig.authority,
this.authCallback,
{
redirectUri: "http://localhost:3000/"
}
);
}
login = () => {
this.client.loginRedirect(this.scopes);
};
logout = () => {
this.client.logout();
};
authCallback = (erroDesc, token, error, tokenType) => {
if (tokenType == "id_token") {
this.acquireTokenSilent(this.scopes).then(
function(accessToken) {
console.log(accessToken);
},
function(error) {
console.log(error);
}
);
}
};
}
(this is not the actual error message, but a friendly description)
this.scopes is undefined as 'this' is scoped to UserAgentApplication.
to avoid this, I tried to bind the this to the callback function. I have added the following statement in the constructor.
this.authCallback = this.authCallback.bind(this);
this leads to another error.
(this is not the actual error message, but a friendly description)
this.acquireTokenSilent is undefined and 'this' do not have a definition for client to reference using this.client.acquireTokenSilent
So I have hard coded the scopes in the original code and was able to get access token, but again same problem in the call back. This time 'this' is null in the call back.
I tried to move the authCallback to the react component and pass it as a parameter to the service, but that also has same kind of problems.
Any help with how to configure this properly is really appreciated. thanks.
Try this replacement for authCallback. It doesn't entirely solve the problem, but can get you past the UserAgentApplication's hijacking of "this" object.
authCallback = (erroDesc, token, error, tokenType) => {
const client = window.client as Msal.UserAgentApplication;
if (tokenType == "id_token") {
client.acquireTokenSilent(["openid"]).then(
function(accessToken) {
console.log(accessToken);
},
function(error) {
console.log(error);
}
);
}
};
Alternatively, use the loginPopup function instead of loginRedirect as it does not have "this" problem that still exists in current MSAL v0.2.3.
I was able to get it working in msal 1.1.1. Try this way:
this.msalClient = new Msal.UserAgentApplication(config);
this.msalClient.handleRedirectCallback(authCallback.bind(this));
function authCallback(error,response)
{
if (response.tokenType === 'access_token' && response.accessToken)
{
this.accesstoken = response.accessToken;
}
}

Returning a record with a string in ember

I am trying to implement a search function where a user can return other users by passing a username through a component. I followed the ember guides and have the following code to do so in my routes file:
import Ember from 'ember';
export default Ember.Route.extend({
flashMessages: Ember.inject.service(),
actions: {
searchAccount (params) {
// let accounts = this.get('store').peekAll('account');
// let account = accounts.filterBy('user_name', params.userName);
// console.log(account);
this.get('store').peekAll('account')
.then((accounts) => {
return accounts.filterBy('user_name', params.userName);
})
.then((account) => {
console.log(account);
this.get('flashMessages')
.success('account retrieved');
})
.catch(() => {
this.get('flashMessages')
.danger('There was a problem. Please try again.');
});
}
}
});
This code, however, throws me the following error:
"You cannot pass '[object Object]' as id to the store's find method"
I think that this implementation of the .find method is no longer valid, and I need to go about returning the object in a different manner. How would I go about doing this?
You can't do .then for filterBy.
You can't do .then for peekAll. because both will not return the Promise.
Calling asynchronous code and inside the searchAccount and returning the result doesn't make much sense here. since searchAccount will return quickly before completion of async code.
this.get('store').findAll('account',{reload:true}).then((accounts) =>{
if(accounts.findBy('user_name', params.userName)){
// show exists message
} else {
//show does not exist message
}
});
the above code will contact the server, and get all the result and then do findBy for the filtering. so filtering is done in client side. instead of this you can do query,
this.store.query('account', { filter: { user_name: params.userName } }).then(accounts =>{
//you can check with length accounts.length>0
//or you accounts.get('firstObject').get('user_name') === params.userName
//show success message appropriately.
});
DS.Store#find is not a valid method in modern versions of Ember Data. If the users are already in the store, you can peek and filter them:
this.store.peekAll('account').filterBy('user_name', params.userName);
Otherwise, you'll need to use the same approach you used in your earlier question, and query them (assuming your backend supports filtering):
this.store.query('account', { filter: { user_name: params.userName } });

Meteor - How to find out if Meteor.user() can be used without raising an error?

I'm looking for a way to determine if Meteor.user() is set in a function that can be called both from the server and client side, without raising an error when it is not.
In my specific case I use Meteor server's startup function to create some dummy data if none is set. Furthermore I use the Collection2-package's autoValue -functions to create some default attributes based on the currently logged in user's profile, if they are available.
So I have this in server-only code:
Meteor.startup(function() {
if (Tags.find().fetch().length === 0) {
Tags.insert({name: "Default tag"});
}
});
And in Tags-collection's schema:
creatorName: {
type: String,
optional: true,
autoValue: function() {
if (Meteor.user() && Meteor.user().profile.name)
return Meteor.user().profile.name;
return undefined;
}
}
Now when starting the server, if no tags exist, an error is thrown: Meteor.userId can only be invoked in method calls. Use this.userId in publish functions.
So in other words calling Meteor.user() on the server startup throws an error instead of returning undefined or null or something. Is there a way to determine whether it will do so prior to calling it?
I cannot solve this simply by wrapping the call with if (Meteor.isServer) within the autoValue function, as the autoValue functions are normally called from server side even when invoked by the user, and in these cases everything in my code works fine.
Note that this is related to How to get Meteor.user() to return on the server side?, but that does not address checking if Meteor.user() is available in cases where calling it might or might not result in an error.
On the server, Meteor.users can only be invoked within the context of a method. So it makes sense that it won't work in Meteor.startup. The warning message is, unfortunately, not very helpful. You have two options:
try/catch
You can modify your autoValue to catch the error if it's called from the wrong context:
autoValue: function() {
try {
var name = Meteor.user().profile.name;
return name;
} catch (_error) {
return undefined;
}
}
I suppose this makes sense if undefined is an acceptable name in your dummy data.
Skip generating automatic values
Because you know this autoValue will always fail (and even if it didn't, it won't add a useful value), you could skip generating automatic values for those inserts. If you need a real name for the creator, you could pick a random value from your existing database (assuming you had already populated some users).
Been stuck with this for two days, this is what finally got mine working:
Solution: Use a server-side session to get the userId to prevent
"Meteor.userId can only be invoked in method calls. Use this.userId in publish functions."
error since using this.userId returns null.
lib/schemas/schema_doc.js
//automatically appended to other schemas to prevent repetition
Schemas.Doc = new SimpleSchema({
createdBy: {
type: String,
autoValue: function () {
var userId = '';
try {
userId = Meteor.userId();
} catch (error) {
if (is.existy(ServerSession.get('documentOwner'))) {
userId = ServerSession.get('documentOwner');
} else {
userId = 'undefined';
}
}
if (this.isInsert) {
return userId;
} else if (this.isUpsert) {
return {$setOnInsert: userId};
} else {
this.unset();
}
},
denyUpdate: true
},
// Force value to be current date (on server) upon insert
// and prevent updates thereafter.
createdAt: {
type: Date,
autoValue: function () {
if (this.isInsert) {
return new Date;
} else if (this.isUpsert) {
return {$setOnInsert: new Date};
} else {
this.unset();
}
},
denyUpdate: true
},
//other fields here...
});
server/methods.js
Meteor.methods({
createPlant: function () {
ServerSession.set('documentOwner', documentOwner);
var insertFieldOptions = {
'name' : name,
'type' : type
};
Plants.insert(insertFieldOptions);
},
//other methods here...
});
Note that I'm using the ff:
https://github.com/matteodem/meteor-server-session/ (for
ServerSession)
http://arasatasaygin.github.io/is.js/ (for is.existy)

Categories