i'm using swift4: i want to login to the app with twitter, but when i presses login with twitter button i got this error:
Callback URL not approved for this client application. Approved callback URLs can be adjusted in your application settings" UserInfo={NSLocalizedDescription=Callback URL not approved for this client application. Approved callback URLs can be adjusted in your application settings}
error: Optional("Request failed: forbidden (403)")
i'd followed this documentation and set all plist variables and app delegate also,
this is my code in login page:
#IBAction func loginWithTwitter(_ sender: Any) {
TWTRTwitter.sharedInstance().logIn(completion: {
(session, error) in
if let sess = session {
print("session: ",sess.authToken, sess.authTokenSecret, sess.userID, sess.userName)
self.loginWithTwitter(twitter_id: sess.userID, name: sess.userName)
} else {
print("error: ", error?.localizedDescription as Any)
}
})
}
func loginWithTwitter(twitter_id: String, name: String) {
self.deviceMac = UIDevice.current.identifierForVendor!.uuidString
KRProgressHUD.show(withMessage: "انتظر ....")
API.loginWithTwitter(mac:self.deviceMac, twitter_id: twitter_id, name: name, token: self.token) { (error: Error?, success: Bool, value: Any) in
if success {
KRProgressHUD.dismiss()
let json = JSON(value)
print(json)
if(json["token"] != "") {
let token = json["token"].string
let def = UserDefaults.standard
def.set(token, forKey: "token")
def.synchronize()
Common.setIfTwitterLogin(login: token!)
let homeViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "HomeViewController") as! HomeViewController
self.present(homeViewController, animated: false, completion: nil)
} else {
self.errorLable.text = "عذرا لقد حدث خطأ حاول مره أخري"
}
} else {
KRProgressHUD.dismiss()
self.errorLable.text = "عذرا لقد حدث خطأ حاول مره أخري"
if Connectivity.isConnectedToNetwork(){
print("Internet Connection Available!")
}else{
Common.showToast(messsage: "الرجاء التحقق من إتصالك بالإنترنت", view: self.view)
}
}
}
}
and
class func loginWithTwitter(mac:String, twitter_id: String, name: String, token: String, completion: #escaping (_ error: Error?, _ success: Bool,_ value: Any) -> Void) {
let loginURL = URLs.loginWithTwitter
let loginParameters = [
"mac": mac,
"twitter_id": twitter_id,
"token": token,
"name": name]
print(loginURL, loginParameters)
Alamofire.request(loginURL, method: .post, parameters: loginParameters, encoding: URLEncoding.default, headers: nil)
.responseJSON { reponse in
switch reponse.result {
case .failure(let error):
print("error: ", error)
completion(error, false, "")
case .success(let value):
completion(nil, true, value)
}
}
}
i'd set a call back url in twitter developer app setting, any one know what is the problem?
In your twitter dashboard Go to: https://apps.twitter.com Go into the settings tab and add following Callback URL.
twitterkit-<consumerKey>://
i.e. twitterkit-4bvXXXXXXNFfOXXwrXXXXXXmT://
Twitter dev updated there rules, you can open your developer website,find the setting of Callback URLS ,add this one :
For android
twittersdk://
For iOS, please refer
https://stackoverflow.com/a/50850233/5740236
https://stackoverflow.com/a/50662575/5740236
and it will be work, wish to solve your problem
Add twittersdk:// as one callback URL on your twitter app setting https://apps.twitter.com/ then try it. This worked for me.
Related
During the sign in flow in iOS, for few users the Authentication module of the amplify-swift library throws the error The operation couldn't be completed. (Amplify.AuthError error 2). I have searched in the amplify-swift repository for possible solutions but couldn't find any. The version of Amplify pod used in code is 1.15.1.
func nativeLogin(
email: String?, password: String?, completion: #escaping (Result<Authstate, Error>) -> Void
) {
let isAlreadySignedIn = AWSMobileClient.default().isSignedIn
if isAlreadySignedIn {
// Do signout and then sign in
let options = AuthSignOutRequest.Options(globalSignOut: true)
Amplify.Auth.signOut(options: options) {
result in
DispatchQueue.main.async {
if case .success = result {
// completion(.success(.logout))
guard let email = email,
let password = password
else {
self.response(
completion, .failure(AuthError.passwordValidationError("Missing Email/Password")))
return
}
// log event
self.signIn(email: email, password: password, completion: completion)
} else if case .failure(let error) = result {
// log event
completion(.failure(error))
}
}
}
} else {
self.signIn(email: email, password: password, completion: completion)
}
}
The reason that the signOut method is invoked before actually signing in is to ensure that last logged in user is signed out first.
Can anyone explain where am I going wrong? Or has this error been already fixed in the latest version (2.2.1) of the amplify-swift library?
I am having a very frustrating problem where the iOS app reviewer is unable to log into my app during their review. I have never had this problem with any device or simulator (iPad/iPhone/various versions) and none of my Testflight users have had this problem either. My authentication and signin code is not that complicated and I am having a hard time figuring out how it's not working.
This is the code that is run when the sign in button is tapped:
AuthManager.shared.signIn(email: email, password: password) { [weak self] result in
DispatchQueue.main.async {
switch result {
case .success:
HapticsManager.shared.vibrate(for: .success)
let vc = TabBarViewController()
vc.modalPresentationStyle = .fullScreen
self?.present(vc, animated: true, completion: nil)
case .failure(let error):
HapticsManager.shared.vibrate(for: .error)
print(error)
}
}
}
And this is the AuthManager signIn function:
public func signIn(email: String, password: String, completion: #escaping (Result<User, Error>) -> Void) {
self.auth.signIn(withEmail: email, password: password) { result, error in
guard result != nil, error == nil, let uid = result?.user.uid else {
completion(.failure(AuthError.signInFailed))
return
}
DatabaseManager.shared.findUser(uid: uid) { user in
guard let user = user else {
completion(.failure(AuthError.signInFailed))
return
}
UserDefaults.standard.setValue(user.username, forKey: "username")
UserDefaults.standard.setValue(user.uid, forKey: "uid")
completion(.success(user))
}
}
}
They are running the app on an iPad supposedly but I can not replicate the problem. I have cancelled and resubmitted as well as just updating the binary. Any ideas?
I'm trying and failing badly to implement the cool Firebase email link login feature. I successfully setup sending an email link. However, I can't get the email link to open up the app. It just opens up the preview page like it can't open the app.
I've tested the dynamic link I setup and I can get it to open up the app in a device. I just can't get the email link to do the same.
Code in my app:
func sendFirebaseEmailLink() {
let actionCodeSettings = ActionCodeSettings.init()
// userEmail comes from a textField
let email = userEmail
actionCodeSettings.url = URL.init(string: String(format: "https://<myappname>.firebaseapp.com/?email=%#", email))
// The sign-in operation has to always be completed in the app.
actionCodeSettings.handleCodeInApp = true
actionCodeSettings.setIOSBundleID(Bundle.main.bundleIdentifier!)
Auth.auth().sendSignInLink(toEmail: email,
actionCodeSettings: actionCodeSettings) { error in
if let error = error {
print(error.localizedDescription)
return
}
else {
UserDefaults.standard.set(email, forKey: "Email")
print("email sent to user")
}
}
}
When I say I've successfully gotten my dynamic link to open the app what I mean is when I follow the link I created (mylinkname.page.link/emaillogin) on a device that has the app installed, it opens the app. Because of that and [this helpful Firebase video][1] on setting up a dynamic link it seems like I've got those details correct and the issue is with the code, but I'm new to this so I'm not sure.
I've spend few days going around in circles to figure this out, and trying to parse the dense Firebase documentation, so any ideas are greatly appreciated.
I finally figured it out. The code was fine. It was an issue related to the dynamic link. I had a couple links setup in Firebase because I had to create a new Bundle ID at one point. When I deleted out the old one in Firebase the email link started working.
It shows up in my app association site like this, and oddly still does even though I deleted out the old link, but at least it works now!
{"applinks":{"apps":[],"details":[{"appID":"TEAMID.com.OLDBUNDLEIDENTIFIER.APPNAME","paths":["NOT //*","/*"]},{"appID":"TEAMID.com.NEWBUNDLEIDENTIFIER.APPNAME","paths":["NOT //","/"]}]}}
UPDATE: My full code to implement passwordless email login is below. It was painful for me to piece together using the documentation so hopefully this saves you the trouble.
Key steps assuming you understand the basics of Firebase Setup.
1) Setup a Dynamic Link Using the Firebase Video tutorial.
2) Code in View Controller:
var userEmail: String?
var link: String?
func sendFirebaseEmailLink() {
let actionCodeSettings = ActionCodeSettings.init()
let email = userEmail
actionCodeSettings.url = URL.init(string: String(format: "https://<myappname>.page.link/emaillogin/?email=%#", email!))
// The sign-in operation has to always be completed in the app.
actionCodeSettings.handleCodeInApp = true
actionCodeSettings.setIOSBundleID(Bundle.main.bundleIdentifier!)
Auth.auth().sendSignInLink(toEmail: email!,
actionCodeSettings: actionCodeSettings) { error in
if let error = error {
print(error.localizedDescription)
return
}
else {
UserDefaults.standard.set(email, forKey: "Email")
print("email sent to user")
}
// TODO: Notify user to check email and click the link.
}
}
// Sign in user after they clicked email link called from AppDelegate
#objc func signInUserAfterEmailLinkClick() {
// Get link url string from the dynamic link captured in AppDelegate.
if let link = UserDefaults.standard.value(forKey: "Link") as? String {
self.link = link
}
// Sign user in with the link and email.
Auth.auth().signIn(withEmail: userEmail!, link: link!) { (result, error) in
if error == nil && result != nil {
if (Auth.auth().currentUser?.isEmailVerified)! {
print("User verified with passwordless email")
// TODO: Do something after user verified like present a new View Controller
}
else {
print("User NOT verified by passwordless email")
}
}
else {
print("Error with passwordless email verfification: \(error?.localizedDescription ?? "Strangely, no error avaialble.")")
}
}
}
3) Code in AppDelegate
// For Passwordless Email Login to Handle Dynamic Link after User Clicks Email Link
func application(_ application: UIApplication, continue userActivity: NSUserActivity,
restorationHandler: #escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
if let incomingURL = userActivity.webpageURL {
print("Incoming URL is \(incomingURL)")
// Parse incoming
let linkHandled = DynamicLinks.dynamicLinks().handleUniversalLink(incomingURL) { (dynamicLink, error) in
guard error == nil else {
print("Found an error: \(error!.localizedDescription)")
return
}
if let dynamicLink = dynamicLink {
self.handleIncomingDynamicLink(dynamicLink)
}
}
if linkHandled {
return true
}
else {
// Maybe do other things with dynamic links in future?
return false
}
}
return false
}
// Handles the link and saves it to userDefaults to assist with login.
func handleIncomingDynamicLink(_ dynamicLink: DynamicLink) {
guard let url = dynamicLink.url else {
print("My dynamic link object has no url")
return
}
print("Incoming link parameter is \(url.absoluteString)")
let link = url.absoluteString
if Auth.auth().isSignIn(withEmailLink: link) {
// Save link to userDefaults to help finalize login.
UserDefaults.standard.set(link, forKey: "Link")
// Send notification to ViewController to push the First Time Login VC
NotificationCenter.default.post(
name: Notification.Name("SuccessfulPasswordlessEmailNotification"), object: nil, userInfo: nil)
}
}
For anyone using SwiftUI with AppDelegate and SceneDelegate files instead of UIKit, here's what I've done:
Create a function to send a link to the user's email
func sendSignLink(email: String) async throws {
do {
let actionCodeSettings = ActionCodeSettings()
actionCodeSettings.url = URL(string: "*enter your Firebase Dynamic link here*")
actionCodeSettings.handleCodeInApp = true
actionCodeSettings.setIOSBundleID(Bundle.main.bundleIdentifier!)
try await Auth.auth().sendSignInLink(toEmail: email, actionCodeSettings: actionCodeSettings)
UserDefaults.standard.set(email, forKey: "email")
}
catch {
throw error
}
}
In the SceneDelegate file, import FirebaseDynamicLinks and add the below code
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
if let incomingURL = userActivity.webpageURL {
print("\n \nIncoming URL is \(incomingURL)")
_ = DynamicLinks.dynamicLinks().handleUniversalLink(incomingURL) { (dynamicLink, error) in
guard error == nil else {
print("\n \nError with handling incoming URL: \(error!.localizedDescription)")
return
}
if let dynamicLink = dynamicLink {
guard let url = dynamicLink.url else {
print("\n \nDynamic link object has no url")
return
}
print("\n \nIncoming link parameter is \(url.absoluteString)")
let link = url.absoluteString
if Auth.auth().isSignIn(withEmailLink: link) {
// Send notification to trigger the rest of the sign in sequence
NotificationCenter.default.post(name: Notification.Name("Success"), object: nil, userInfo: ["link": link])
} else {
// Send error notification
NotificationCenter.default.post(name: Notification.Name("Error"), object: nil, userInfo: nil)
}
}
}
}
}
Create a function to handle the sign in after the user has clicked on the link in their email
func signInWithEmail(link: String) async throws {
do {
let email = UserDefaults.standard.value(forKey: "email")
try await Auth.auth().signIn(withEmail: email, link: link)
}
catch {
throw error
}
}
In a relevant view, handle the notifications which get posted
struct MyView: View {
var body: some View {
VStack {
Text("View")
}
.onReceive(NotificationCenter.default.publisher(for: Notification.Name("Success"))) { notificationInfo in
if let userInfo = notificationInfo.userInfo {
if let link = userInfo["link"] as? String {
Task.init {
do {
try await signInWithEmail(link: link)
} catch {
print(error)
}
}
}
}
}
.onReceive(NotificationCenter.default.publisher(for: Notification.Name("Error"))) { _ in
//do something with error
}
}
}
I want the user to insert the current password and the new one when updating his password.
I've searched Firebase documentation and didn't find a way to verify the user's current password.
Does anyone know if this is possible?
You will be able to achieve it using reauthenticate before changing the password.
let user = FIRAuth.auth()?.currentUser
let credential = FIREmailPasswordAuthProvider.credentialWithEmail(email, password: currentPassword)
user?.reauthenticateWithCredential(credential, completion: { (error) in
if error != nil{
self.displayAlertMessage("Error reauthenticating user")
}else{
//change to new password
}
})
Just to add more information, here you can find how to set the credential object for whatever provider you are using.
For Swift 4:
typealias Completion = (Error?) -> Void
func changePassword(email: String, currentPassword: String, newPassword: String, completion: #escaping Completion) {
let credential = EmailAuthProvider.credential(withEmail: email, password: currentPassword)
Auth.auth().currentUser?.reauthenticate(with: credential, completion: { (error) in
if error == nil {
currentUser.updatePassword(to: newPassword) { (errror) in
completion(errror)
}
} else {
completion(error)
}
})
}
Firebase Documentation can be found here
For Swift 5 to change password in firebase
import Firebase
func changePassword(email: String, currentPassword: String, newPassword: String, completion: #escaping (Error?) -> Void) {
let credential = EmailAuthProvider.credential(withEmail: email, password: currentPassword)
Auth.auth().currentUser?.reauthenticate(with: credential, completion: { (result, error) in
if let error = error {
completion(error)
}
else {
Auth.auth().currentUser?.updatePassword(to: newPassword, completion: { (error) in
completion(error)
})
}
})
}
How to use ?
self.changePassword(email: "abcemail#gmail.com", currentPassword: "123456", newPassword: "1234567") { (error) in
if error != nil {
self.showAlert(title: "Error" , message: error?.localizedDescription)
}
else {
self.showAlert(title: "Success" , message: "Password change successfully.")
}
}
Don't make it as a duplicate question, I raise this question because the answers are not helpfull,
The integration works fine for me, but the pages loads really slow.
It takes really a long time to load the login screen. Login action takes more than 8-50 seconds or more.
Sometimes for loading authentification screen takes more than 10 secs.
The Following code is for FBLoginButtonAction
func loginButton(loginButton: FBSDKLoginButton!, didCompleteWithResult result: FBSDKLoginManagerLoginResult!, error: NSError!){
if(error != nil){
print(error.localizedDescription)
return
}
if result.isCancelled{
showAlert(title: "Login Cancelled", message: "You have cancelled login through Facebook")
}
if FBSDKAccessToken.currentAccessToken() != nil{
print("Logged in")
}
}
You can make FBlogin using NSNotification method.
Just follow below steps.
set FBDelegate and set observer for NSNotification in ViewDidload like,
self.btnFBLogin.delegate = self
self.btnFBLogin.readPermissions = ["public_profile","email","user_friends"]
FBSDKProfile.enableUpdatesOnAccessTokenChange(true)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "getUserProfile:", name: FBSDKProfileDidChangeNotification, object: nil)
2.Now make one custom function for NSNotification like,
func getUserProfile(notification : NSNotification)
{
let accessToken = FBSDKAccessToken.currentAccessToken()
if(accessToken != nil)
{
let req = FBSDKGraphRequest(graphPath: "me", parameters: ["fields":"email,name"], tokenString: accessToken.tokenString, version: nil, HTTPMethod: "GET")
req.startWithCompletionHandler({ (connection, result, error : NSError!) -> Void in
if(error == nil)
{
print("result \(result)")
let userInfo = result as AnyObject
if let email = userInfo.valueForKey("email") as? NSString
{
print(email)
}
else
{
let loginManager = FBSDKLoginManager()
loginManager.logOut()
}
}
else
{
print("error \(error)")
}
})
}
}
Note : Don't write any logic in FB delegate method. Just put it there.
I think this will help u bcz it works fine for me. :)