Flutter + Firebase paswordless authentication not working - firebase

I am trying to implement passwordless authentication in my Flutter app using dynamic links, but the link the app receives always returns false for the isSignInWithEmailLink() method.
The dynamic link I created in the firebase console is the following:
Dynamic Links configuration
And the code I am using to send it is:
var acs = ActionCodeSettings(
url: "https://XXXXXX.page.link/eP3A",
handleCodeInApp: true,
iOSBundleId: "com.example.XXXXX",
androidPackageName: "com.example.XXXXXX",
androidInstallApp: true,
androidMinimumVersion: "12",
);
FirebaseAuth.instance.sendSignInLinkToEmail(
email: email, actionCodeSettings: acs)
.catchError((onError) =>
print('Error sending email verification $onError'))
.then((value) => print('Successfully sent email verification'));
I am able to receive the link in the email, and when clicking on it, it opens the app. However, the link always return false in isSignInWithEmailLink(). Am I missing something? I've tried different combinations on the ActionCodeSettings object but none of them seem to work. I am using the latest versions of firebase_auth and firebase_dynamic_links.

Related

Firebase dynamic links to reset password : not configured for the current project

I am using a Cloud Function to generate a password-reset-link through the admin sdk.
I need to handle the action link in my website and not my mobile app.
my action code settings looks like :
ActionCodeSettings codeSettings = ActionCodeSettings(
url: "https://example.com/links/reset",
handleCodeInApp: false,
dynamicLinkDomain: "https://example.com/links"
);
and i have also tried :
ActionCodeSettings codeSettings = ActionCodeSettings(
url: "https://example.com/links/reset",
handleCodeInApp: false,
);
Both gives me the following error :
FirebaseAuthError: The provided dynamic link domain is not configured or authorized for the current project.
I am simply using the : admin.auth().generatePasswordResetLink(data.email, actionCodeSettings) method in an onCall https request to my function.
I have of course setup dynamic links for my project and my project is hosted fine with Firebase Hosting.
I have also added this to my firebase.json file :
"rewrites": [ {
"source": "/links/**",
"dynamicLinks": true
} ]
As stated in the documentation.
What i am doing wrong ?
If i generate the ActionCodeSettings from flutter it doesn't work.
However, if in my NodeJS code I implement :
const actionCodeSettings = {
url: "https://example.com/links",
handleCodeInApp: false
};
It's working.
In the logs i could see that the param dynamicLinkDomain was set to null and passed even if i was not using it.

How to get Google refresh token with knpuniversity/oauth2-client-bundle?

I use knpuniversity/oauth2-client-bundle and league/oauth2-google to connect users in my Symfony 4 web app using a "Sign in with Google" feature. I followed this tuto. I registered my app in Google.
I set access_type: offline in the knpu.oauth2.client.google configuration (config/packages/knpu_oauth2_client.yaml file)
I try to get the user refresh token in my GoogleAuthenticator::getUser(League\OAuth2\Client\Token\AccessToken $credentials) method (which extends KnpU\OAuth2ClientBundle\Security\Authenticator\SocialAuthenticator).
Unfortunately, $credentials->getRefreshToken() always returns null.
Why don't I get the user refresh token ?
As per documentation, "Refresh tokens are only provided to applications which request offline access". So, when instantiating the provider you need to set the accessType.
use League\OAuth2\Client\Provider\Google;
$provider = new Google([
'clientId' => '{google-client-id}',
'clientSecret' => '{google-client-secret}',
'redirectUri' => 'https://example.com/callback-url',
'accessType' => 'offline',
]);
In knpu_oauth2_client configuration, you can do:
google:
type: google
client_id: '%env(OAUTH_GOOGLE_CLIENT_ID)%'
client_secret: '%env(OAUTH_GOOGLE_CLIENT_SECRET)%'
redirect_params: {}
access_type: offline

How to use Sign-In User ID to send push notifications

I have some users signed into my actions-on-google app via Google Sign-In ( https://developers.google.com/actions/identity/google-sign-in )
I want to sent push notifications to one of those users.
For getting push notifications work with actions in the first place, I tried this sample: https://github.com/actions-on-google/dialogflow-updates-nodejs/blob/master/functions/index.js but I only can get this to work without this commit: https://github.com/actions-on-google/dialogflow-updates-nodejs/commit/c655062047b49e372da37af32376bd06d837fc7f#diff-1e53ef2f51bd446c876676ba83d7c888
It works fine, but I think const userID = conv.user.id; returns the deprecated Anonymous User ID. The commit suggests to use const userID = conv.arguments.get('UPDATES_USER_ID'); which returns undefined.
I use this nodejs code to send the push notifications.
const request = require('request');
const {JWT} = require('google-auth-library');
const serviceAccount = require('./service-account.json');
let jwtClient = new JWT(
serviceAccount.client_email, null, serviceAccount.private_key,
['https://www.googleapis.com/auth/actions.fulfillment.conversation'],
null
);
jwtClient.authorize((authErr, tokens) => {
let notification = {
userNotification: {
title: process.argv[2],
},
target: {
userId: USERID,
intent: 'tell_latest_status',
// Expects a IETF BCP-47 language code (i.e. en-US)
locale: 'en-US'
},
};
request.post('https://actions.googleapis.com/v2/conversations:send', {
'auth': {
'bearer': tokens.access_token,
},
'json': true,
'body': {
'customPushMessage': notification, 'isInSandbox': true
},
}, (reqErr, httpResponse, body) => {
console.log(httpResponse.statusCode + ': ' + httpResponse.statusMessage);
});
});
I simply can't get this to work with the const userID = conv.arguments.get('UPDATES_USER_ID'); version, because as I said
When I use conv.user.profile.payload.sub as suggested here: https://developers.google.com/actions/identity/user-info the AoG API returns "SendToConversation response: Invalid user id for target."
Is there any way to make this work with Google Sign-In?
Has anyone made this work? I mean with the UPDATES_USER_ID field?
I already created an issue on the samples repo: https://github.com/actions-on-google/dialogflow-updates-nodejs/issues/15 but I was sent here.
Thanks!
While researching why I sometimes got undefined I found an answer on this question that solved my issue.
I've found solution for this problem. While getting UPDATES_USER_ID
conv.arguments.get() only works for first attempt. So, while building
your action you must save it. If you didn't store or save, you can
reset your profile and try again, you will be able to get.
You can reset your user profile for the action here.

Firebase sign in with email link giving ERROR_UNAUTHORIZED_DOMAIN in flutter

I am setting up a password-less environment for my Flutter app and I am having issues with the FirebaseAuth.instance.sendSignInWithEmailLink command.
await FirebaseAuth.instance.sendSignInWithEmailLink(
email: email,
url: url// Using whitelisted url,
handleCodeInApp: true,
iOSBundleID: bundleId // bundle id for ios app,
androidPackageName: androidId // package name for android,
androidInstallIfNotAvailable: false,
androidMinimumVersion: "18",
);
The error I get is the following:
Exception has occurred.
PlatformException (PlatformException(ERROR_UNAUTHORIZED_DOMAIN, Domain not whitelisted by project, null))
Even though the url I have attempted to us is on the white list under Authentication > Sign In Methods > Authorized Domains.
Any help would be greatly appreciated.

Should firebase auth onCreate trigger have more data?

I'm using functions.auth.user().onCreate() as part of a firestore project, and trying to set up some default data when a new user registers. For the front end, I'm using firebase-ui, with Google and Email/Password providers enabled.
When I sign in with an email and password, the UI widget prompts to enter a name and set a password. I was expecting to see the name as part of the user parameter in the onCreate() function call, but I'm getting practically nothing:
user: { email: 'xxx#yyyy.co.uk',
emailVerified: false,
displayName: null,
photoURL: null,
phoneNumber: null,
disabled: false,
providerData: [],
customClaims: {},
passwordSalt: null,
passwordHash: null,
tokensValidAfterTime: null,
metadata:
UserRecordMetadata {
creationTime: '2018-11-20T15:06:01Z',
lastSignInTime: '2018-11-20T15:06:01Z' },
uid: 'QDJ5OJTwbvNo2QNDVQV9VsxC2pz2',
toJSON: [Function] }
Not even getting the provider info so I can tell which 'kind' of user registered. It's almost like this function is triggered before the user record has been populated (except the email address does get through). Also, registrations via the Google provider come with a fully-populated user record, so I guess this is a problem with Email/Password specifically.
Is this a bug, or am I missing something? I didn't see anything else useful in the context parameter either.
The fact that displayName is not populated in the Cloud Functions onCreate trigger for email+password is expected. The function is triggered from the first API call (createUserWithEmailAndPassword()), while the display name is set with a second API call (updateProfile).
The usual workaround would be to create a Cloud Function to update the user profile, as shown here: Firebase Auth+Functions | create user with displayName
I also highly recommend filing a feature request to be able to have a Cloud Function triggered on profile changes.

Resources