custom login for firebase in swift - ios

I have to implement a chat platform using firebase and swift.
I know how to create a user using emailid :
firebase.createUser(emailTextField, password: passwordTextField.text) { (error:NSError!) -> Void in
if (error != nil){
print(error.localizedDescription)
self.displayMessage(error)
} else{
print("New user created")
self.requestUsername()
}
}
But I am not taking any email id or other accounts. I want to create a custom user. For that they have mentioned to use the secure JWT Token and then use this :
let ref = Firebase(url: "https://<YOUR-FIREBASE-APP>.firebaseio.com/")
ref.authWithCustomToken(AUTH_TOKEN, withCompletionBlock: { error, authData in
if error != nil {
println("Login failed! \(error)")
} else {
println("Login succeeded! \(authData)")
}
})
But they have not mentioned how to generate secure JWT Token in swift.
Anyone know?
Here is the link i referred:
How to login in firebase

As you probably noticed, there is no helper library from Firebase for minting custom tokens on iOS. There is however a set of instructions on how to mint tokens here: https://www.firebase.com/docs/ios/guide/login/custom.html#section-tokens-without-helpers
Minting tokens in a client-app is in general a VERY bad idea, since it requires that you have your Firebase's secret in your app, where any user can find it.

Related

Getting Twitter profile info with Firebase Auth Swift

I'm trying to get basic details of a user signing into my app with their Twitter account. I am able to sign them in but not too sure where to go from here.
I'm pretty sure I need to use this get request but am unsure how to structure the request. Am also a little lost which token I include.
I haven't had much experience with the REST API as you could tell. I have Postman set up so if someone could point me in the right direction about accessing the data I could take it from there.
Thanks
#IBAction func twitterSignupPress() {
provider.getCredentialWith(nil) { credential, error in
if error != nil {
print("Error attempting to sign up using Twitter: \(error!)")
} else {
Auth.auth().signIn(with: credential!) { authResult, error in
if error != nil {
print("Error with Twitter signin")
} else {
print("Successful signin using Twitter")
let oAuthCredential = authResult?.credential as! OAuthCredential
print(oAuthCredential.accessToken!) // Prints token
print(oAuthCredential.idToken) // Prints nil
}
}
}
}
}
Was as simple as adding authResult?.additionalUserInfo?.profile

Firebase Authentication Link Facebook to Google

After many tests I decided to create a new xCode project to better understand Firebase authentication with multiple providers.
I set up in Firebase -> SignIn Methods -> An account per email address
An account per email address
Prevents users from creating multiple
accounts using the same email address with different authentication
providers
At this point I have implemented, carefully following the Firebase guide, the login with Facebook and with Google .. Everything seems to work perfectly but I always find myself with the same error that I can't manage:
When my user creates a Firebase account via Google he is no longer able to log in if he decides to use Facebook.
Facebook returns its error when it completes its authentication flow with Firebase:
Firebase Error With Facebook Provider: An account already exists with the same email address but different sign-in credentials. Sign in using a provider associated with this email address.
Continuing to follow the documentation step by step I stopped here (firebase explains how to handle this error)
I have also implemented error handling but after calling Auth.auth().fetchSignInMethods Firebase says I should authenticate the user with the existing provider, at this point how do I get the credentials for authentication with the existing provider?
I wouldn't want to reopen the existing provider controller to get new credentials
Am I obliged to ask the user to log in with the existing provider and show another access controller again (in this case that of Google)?
How should I handle this situation?
override func viewDidLoad() {
super.viewDidLoad()
facebookSetup()
}
func facebookSetup() {
let loginButton = FBLoginButton(permissions: [ .publicProfile, .email ])
loginButton.center = view.center
loginButton.delegate = self
view.addSubview(loginButton)
}
//MARK: - FACEBOOK Delegate
func loginButton(_ loginButton: FBLoginButton, didCompleteWith result: LoginManagerLoginResult?, error: Error?) {
if let error = error {
print(error.localizedDescription)
return
}
let credential = FacebookAuthProvider.credential(withAccessToken: AccessToken.current!.tokenString)
Auth.auth().signIn(with: credential) { (authResult, error) in
if let error = error {
print("\n FIREBASE: ",error.localizedDescription)
// An account with the same email already exists.
if (error as NSError?)?.code == AuthErrorCode.accountExistsWithDifferentCredential.rawValue {
// Get pending credential and email of existing account.
let existingAcctEmail = (error as NSError).userInfo[AuthErrorUserInfoEmailKey] as! String
let pendingCred = (error as NSError).userInfo[AuthErrorUserInfoUpdatedCredentialKey] as! AuthCredential
// Lookup existing account identifier by the email.
Auth.auth().fetchSignInMethods(forEmail: existingAcctEmail) { providers, error in
if (providers?.contains(GoogleAuthProviderID))! {
// Sign in with existing account.
Auth.auth().signIn(with: "? ? ? ?") { user, error in
// Successfully signed in.
if user != nil {
// Link pending credential to account.
Auth.auth().currentUser?.link(with: pendingCred) { result, error in
// Link Facebook to Google Account
}
}
}
}
}
}
}
}

Unable to link Facebook and Google in Firebase Authentication

I am trying to link Facebook and Google. So, the scenario is this:
I have already authenticated with Google. So, now I am logging in Facebook, having same email id which was used earlier with Google. So, I get the error of account Exists with a different credential. And, I did this:
func fetchUserInfo()
{
Auth.auth().signInAndRetrieveData(with:FacebookAuthProvider.credential(withAccessToken: (FBSDKAccessToken.current().tokenString)!), completion: { (result, error) in
if let error = AuthErrorCode.init(rawValue: error!._code)
{
switch error
{
case .accountExistsWithDifferentCredential :
let credential = FacebookAuthProvider.credential(withAccessToken: (FBSDKAccessToken.current()?.tokenString)!)
Auth.auth().currentUser?.linkAndRetrieveData(with: credential, completion: { (result, error) in
if let error = error
{
print("Unable to link Facebook Account", error.localizedDescription)
}
else
{
NavigationHelper.shared.moveToHome(fromVC: self)
}
})
default: break
}
}
else
{
GeneralHelper.shared.keepLoggedIn()
if let currentUser = Auth.auth().currentUser
{
print(currentUser.email!)
}
NavigationHelper.shared.moveToHome(fromVC: self)
}
})
}
Here Firebase Documentation says that we need to just link the currentUser and retrieve data. But, the issue I am facing is that the currentUser is always nil. So, how can I get the current user? I have already tried this months ago and then I was able to link Facebook, Google and Email. Do, I need to signInAndRetrieve the data from Google in order to get the currentUser?
The Error "account Exists with a different credential" is because, by default, Firebase do not allow to use the same email address for two (or more) different Sing In methods. You need to enable this option.
1 - Go to Authentication > Sign-in method
2 - Scroll down to Advanced: Multiple accounts per email address
3 - Change the option to Allow creation of multiple accounts with the same email address
FYI: You need to do whole login process for each Sign In method in your app. Each method has is own credentials.
Hope this helps.

Re-using access token in Firebase 3

I have an iOS app that uses Firebase as a backend for authentication.
Once a user logs in and then closes the app, I don't want the user to have to re-enter their email and password. My approach is to save the access token after a successful login to the Keychain, and then when the user comes back to the app, use the token from the keychain to signin.
I've tried using the method FIRAuth.auth()?.signInWithCustomToken(customToken) { (user, error) in but that's not quite right as that's for when using custom tokens, which is not what I'm doing.
Is there a way for me to do this?
// login with email / password
FIRAuth.auth()?.signInWithEmail(email, password: password, completion: { (firebaseUser, error) in
if error == nil {
FIRAuth.auth()!.currentUser!.getTokenWithCompletion({ (token, error) in
if error == nil {
// save token to keychain
} else {
print(error)
}
})
} else {
print(error)
}
})
// user comes back to app
do {
// get saved token from keychain
if let myToken = try keychain.get("token") {
FIRAuth.auth()?.signInWithCustomToken(myToken, completion: { (user: FIRUser?, error: NSError?) in
if error == nil {
// show post login screen
} else {
}
})
}
} catch {
// error getting token from keychain
}
}
I was approaching this problem in the wrong way. Saving a token is appropriate when using a 3rd party authentication provider, like Facebook, Google, etc and getting an OAuth token in return from one of those services.
In my case when logging in using email and password, a token is not required and instead the password can be securely saved in the Keychain and used later for login.

How to get Firebase JWT token to validate on server side in Latest Firebase IOS SDK

I am trying out new Firebase IOS SDK with firebase base authentication and my custom backend server . I have enabled username password authentication in firebase which works fine but I do not see any property on auth object which gives me the JWT token so that I can verify the requests on my custom backend server
FIRAuth.auth()?.createUserWithEmail(singupusername.text!, password: singuppassword.text!) { (user, error) in
print(user)
print(error)
}
the user does not have any property which gives me the firebase JWT token
I figured out method to get access token in the latest SDK I used below method to get the latest token
FIRAuth.auth()?.addAuthStateDidChangeListener { auth, user in
if let user = user{
user.getTokenWithCompletion{
(data) in
print(data.0)
}
}
}
the latest code should be
let currentUser = Auth.auth().currentUser
currentUser?.getIDTokenForcingRefresh(true) { idToken, error in
if let error = error {
// Handle error
return;
}
// Send token to your backend via HTTPS
// ...
print("JWT is< \(idToken)>")
}

Resources