Firebase Dynamiclinks is unable to parse universal link - ios

I have an app on TestFlight that I'm trying to setup passwordless signin using emailid from FireBase.
I've done the following:
Enabled Passwordless sign in on Firebase console
Created a Dynamic link on Firebase.
httpsdotslashslash<custom domain>/login/?link=https://<custom domain>/login&isi=<app id from itunes connect. Looks like this: 167*******>&ibi=<bundleid>
Confirmed that https://<custom domain>/apple-app-site-association returns correctly. Note that I'm using Firebase hosting to host this site. And have confirmed that https://<firebase-projectid>.firebase.app/apple-app-site-association also returns the above. i.e. custom domain is correctly resolving to this firebase hosting url.
In Info, Added a url type with identifier 'appLink' and 'url scheme'
Ensured that my GoogleService-Info is current
Enabled Associated Domains in 'Signing and Capabilities' in my project Target under 'All' (not just Debug or Release)
Added applinks:<customdomain> and activitycontinuation:<customdomain>
In my 'SceneDelegate', I'm handling the dynamic link with
private func handleIncomingDynamicLink(_ incomingURL: URL) {
DynamicLinks.dynamicLinks().handleUniversalLink(incomingURL) { dynamicLink, error in
guard error == nil else {
return print("ⓧ Error in \(#function): \(error!.localizedDescription)")
}
guard let link = dynamicLink?.url?.absoluteString else { return }
if Auth.auth().isSignIn(withEmailLink: link) {
// Save the link as it will be used in the next step to complete login
UserDefaults.standard.set(link, forKey: "Link")
}
}
}
In my viewcontroller, have copied the code from Firebase's quickstart PasswordlessViewController.swift as is.
Observed behavior:
The email link is being sent. Here's what it looks like though. Not sure if this is right.
httpsdotslashslash<custom domain>/?link=https://<firebase-projectid>.firebaseapp.com/__/auth/action?apiKey=<web api key>&mode=signIn&oobCode=25CRdL7n3qXNatDT2nEypR9UWy17E_G0ChlmqrkpznsAAAGGLYK3jQ&continueUrl=https://<custom domain>/login&lang=en&ibi=<bundleid>&ifl=https://<firebase-projectid>.firebaseapp.com/__/auth/action?apiKey=<web api key>&mode=signIn&oobCode=25CRdL7n3qXNatDT2nEypR9UWy17E_G0ChlmqrkpznsAAAGGLYK3jQ&continueUrl=https://<custom domain>/login&lang=en
Clicking on this url in my email correctly opens my app. handleIncomingDynamicLink() is also called correctly. But it throws the error ⓧ Error in handleIncomingDynamicLink(_:): The operation couldn’t be completed. Universal link URL could not be parsed by Dynamic Links.
Have tried a bunch of things.
But, unable to proceed beyond this stage. Not sure what is wrong with my link. What is it supposed to look like when behaving correctly? Should i be doing something with the oobCode? Why are there two redirections?
Happy to assist with any other information. Thank you!

I was able to solve it by adding all my url prefixes to info.plist.
<key>FirebaseDynamicLinksCustomDomains</key>
<array>
<string>https://<custom domain>/login</string>
<string>https://<custom domain>/</string>
</array>
More details at https://firebase.google.com/docs/dynamic-links/custom-domains#console

Related

I am getting Invalid Dynamic Link when clicking to the Sign-in link received through email

I am getting Invalid Dynamic Link when clicking to the Sign-in link received through email.
actionCodeSettings.url = URL(string: "https://caxxxxxxxxxxxant.page.link") //my domain prefix
actionCodeSettings.handleCodeInApp = true
actionCodeSettings.setIOSBundleID(Bundle.main.bundleIdentifier!
But when I provide the url as :
actionCodeSettings.url = URL(string: "https://caxxxxxxxxxant.page.link/open")
with custom url scheme i gave while making Dynamic Link under the domain, it's now navigating me to my app with error 'error in sign-in' by going else part of the below code. *
if Auth.auth().isSignIn(withEmailLink: link) {
guard let email = UserDefaults.standard.value(forKey: "Email") as? String else {
print("Error signing in: email does not exist")
return true
}
}
else{
print("error in sign-in")
}
return false
}
The link I am getting while receiving the dynamic link in app delegate restorationHandler: method is
<https://caxxxxxxxxxxxxant.page.link/?link=https://sxxxx-axxxxt-exxa.firebaseapp.com&isi=14xxxxxx8&ibi=com.cxxxxxr.sxxxxxt&st=Eagle+Eye+Sales+Assistant+App&sd=Now+you+can+get+all+the+Eagle+Eye+documents+and+information+within+a+fingerprint.&cid=5xxxx60xxx558&_osl=https://caxxxxxxxxant.page.link/open&_fpb=CJxxxxxHQg==&_cpt=cpit&_iumenbl=1&_iumchkactval=1&_plt=895&_uit=1062&_cpb=1>
I guess this is because my incoming link doesn't contain email with it.
Please help me, how can I get my link authenticated in Auth.auth().isSignIn(withemailLink : Link) method. How can I get the link with email.
Any help will be appreciated.
First of all, Firebase Auth doesn't support custom FDL domains with paths.
Second, if you want to use a custom FDL domain, you need to set actionCodeSettings.url to a fallback URL in case the user clicks the link on a different device (where the iOS app is not installed). You will need to set the FDL domain caxxxxxxxxxxxant.page.link in actionCodeSettings.dynamicLinkDomain.

Testing passwordless auth in Firebase test lab for iOS

I am trying to figure out how to perform e2e test via firebase test lab for iOS that allow to check passwordless authentication flow, which essentially should do following
Enters email within my app
Firebase sends auth link to such email
Somehow I need to be logged into such email somewhere in firebases test device, I assume either in mail app, or gmail?
I need to know when new email arrives and open it
Once I opened an email I need to click on auth link
This should bring me back into the app and authenticate
My biggest issue at the moment is figuring out steps that happen outside my app i.e. how can I prepare for this test and log in under my email address (is it better to log into gmail in safari for example or somehow add this acc to apples mail app?).
Testing email
In my experience, testing your own code to see if an email was sent is not straightforward beyond checking if the method call you expect to send the email has happened.
Add on top of that using Firebase, which does not expose its underlying email send code, and that looks like a challenge to me.
In terms of testing, I suggest you assert that your method calls to send email happened or that the relevant code path was reached. In Firebase web, this looks like:
firebase.auth().sendSignInLinkToEmail(email, actionCodeSettings)
.then(function() {
// The link was successfully sent. Inform the user.
// Save the email locally so you don't need to ask the user for it again
// if they open the link on the same device.
window.localStorage.setItem('emailForSignIn', email);
// TODO save email to something accessible in your iOS tests
// TODO In your tests, confirm that email was saved after it was sent
})
.catch(function(error) {
// Some error occurred, you can inspect the code: error.code
});
See: https://firebase.google.com/docs/auth/web/email-link-auth#send_an_authentication_link_to_the_users_email_address
Another option:
You could setup a test user with an email address on a mail server that you manage, and check for incoming mail for that test user with your own custom mail reading code.
I would use Firebase Admin tools for this: https://firebase.google.com/docs/auth/admin/manage-users#create_a_user
I think you should first take a look at firebase docs for iOS on how to create dynamic links that you can use for email auth.
https://firebase.google.com/docs/auth/ios/email-link-auth
https://firebase.google.com/docs/auth/ios/passing-state-in-email-actions#configuring_firebase_dynamic_links
After you're done with those two check out the following code:
func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
// [END old_delegate]
if handlePasswordlessSignIn(withURL: url) {
return true
}
}
func handlePasswordlessSignIn(withURL url: URL) -> Bool {
let link = url.absoluteString
// [START is_signin_link]
if Auth.auth().isSignIn(withEmailLink: link) {
// [END is_signin_link]
UserDefaults.standard.set(link, forKey: "Link")
(window?.rootViewController as? UINavigationController)?.popToRootViewController(animated: false)
window?.rootViewController?.children[0].performSegue(withIdentifier: "passwordless", sender: nil)
return true
}
return false
}
This is just an example on how you can handle the deep link in your app after the user taps the link. The delegate method
func application(_ application: UIApplication, open url: URL,
sourceApplication: String?, annotation: Any) -> Bool
in AppDelegate is used for all deep links into an app. You could set up for example your own scheme that your app conforms to. And you can send url type links with your custom scheme into your app from the browser for example.
To do this just Open Xcode, go to Project Settings -> Info, and add inside ‘The URL Types” section a new URL scheme. Add something of the sort of com.myApp in order for it to be as unizue as possible. Then you can just type into a browser com.myApp://main and handle that in the appDelegate.
Edit: It says so in their docs that you can present a prompt inside the app for the user to input the email. Where the user opens his email from isn't really your concern as long as your dynamic link is set up properly.

Sharing to specific Facebook page using Swift SDK GraphSharer

In my iOS app I'm trying to use the Facebook Swift SDK so that a user can post a URL to a specific Facebook page that they manage.
I've managed to get the following code working - but it only shares the post to my home timeline:
let content = LinkShareContent(url: URL(string: urlString)!)
let sharer = GraphSharer(content: content)
sharer.failsOnInvalidData = true
sharer.completion = {
(result) in
print(result)
}
do {
try sharer.share()
}
catch (let error) {
print(error.localizedDescription)
}
I believe that I need to use the graphNode property to specify the destination page and that the correct format is as follows:
sharer.graphNode = "/\(pageId)"
However, when I set this property before posting, I am getting an error:
failed(Error Domain=NSURLErrorDomain Code=-1002 "unsupported URL"
I've tried a dozen different formats to specify the node but they all return the same error and I can't find any working examples.
I managed to resolved this issue. It turns out that the graphNode path above is correct but I was looking in the wrong place due to the error message I was getting. Instead I just needed to specify the accessToken parameter.
graphSharer.accesstoken = myPageAccessToken
Note: The access token is not the user's current access token, but an access token you can retrieve when calling the /me/accounts API.
var graphPath = "/me/accounts"
I also then had an issue posting to the page because I had only requested the publish_actions permission. From the documentation, this appears to be suitable but it only worked where I requested further permissions as follows:
loginManager.logIn(withPublishPermissions: ["publish_actions",
"manage_pages", "publish_pages"], ...
Hopefully this will be of use to someone in future. :-)

Cannot create shared link with Dropbox API for Swift

This used to work before I updated to Swift 3, but I don't think this is really coming from this. Here is my problem:
I would like to create a Dropbox sharable link from my Swift app as follow:
client.sharing.createSharedLinkWithSettings(path: myPath).response { response, error in
if let link = response {
// share the link
} else {
print(error)
}
}
but this is the error I get:
[request-id 431f08cc7e243504a437cec661247dd2] API route error - {
".tag" = "email_not_verified";
}
and I don't really understand how should I verify the email.
I can log in with dropbox, I authorised the app, I can write files and folders, etc.
I didn't received a verification email on my device. I tried with a different account and received this verification email from dropbox.

Error adding Firebase users Swift

By following the information on this link, I am currently working on trying to create a user using Firebase, as shown in the code below. However, it appears no user is created when the app is run. Any input is greatly appreciated. The Firebase URL was taken from my test database.
let ref = Firebase(url: "https://test-96df2.firebaseio.com")
ref.createUser("bobtony#example.com", password: "correcthorsebatterystaple",
withValueCompletionBlock: { error, result in
if error != nil {
// There was an error creating the account
print("error creating account")
} else {
let uid = result["uid"] as? String
print("Successfully created user account with uid: \(uid)")
}
})
Edit:
The propagated error is:
Error Code: AUTHENTICATION_DISABLED) Projects created at
console.firebase.google.com must use the new Firebase Authentication
SDKs available from firebase.google.com/docs/auth/
However, as shown below, the email/password authentication is enabled in the Firebase console.
You have already authorized the email registration as I can see in your screenshot. So the problem doesnt realies on AUTHENTICATION_DISABLED.
From your error message and the snippet code I can see that you have created a new project but you are trying to use the legacy firebase SDK and so you will have compatibility issues. Also, you are looking into the old firebase documentation.
First of all you will need to make sure you have configured your project as documented in new firebase start guide.
After, you can take a look at the documentation for creating a new user with the new sdk. You can find the 3.x create user call bellow.
FIRAuth.auth()?.createUserWithEmail(email, password: password) { (user, error) in
// ...
}

Resources