Amplify CUSTOM_AUTH login issue on iOS swift - swift

I am new to Amplify and want to integrate it with iOS swift. I followed amplify_doc
to and created amplifyconfiguration.json and added it to the project. Configured with credentials provided such as PoolId, Region, AppClientId and web domain. Set authentication flow type as "authenticationFlowType": "CUSTOM_AUTH".
I tried with simple sign-in API with username as:
Amplify.Auth.signIn(username: userName) { result in
switch result {
case .success:
print("Sign in succeeded")
case .failure(let error):
print("Sign in failed \(error)")
if let err = error.underlyingError as NSError? {
print("Cast to nserror:", err)
}
}
Error: Sign in failed AuthError: Incorrect username or password.
This was password less authentication which works on Android but facing issues on iOS.
Also tried with Amplify.Auth.signIn(username: <username>, password: nil) still no success.
When nothing worked I tried with signUp API it worked and I received OTP on email successfully. The issue seems to be in the sign-in API.
Had a discussion on this bug with amplify team. For detailed response you can check Amplify Issue

First, you will have to signup the user, then sign in.
let attribute = [AuthUserAttribute(.phoneNumber, value: username)]
let options = AuthSignUpRequest.Options(pluginOptions: attribute)
Amplify.Auth.signUp(username: username, password: password, options: options) { result in
switch result {
case .success(let data):
onCompletion(data,nil)
case .failure(let error):
onCompletion(nil,error)
}
}

Related

How to renew the id token using auth0 in SwiftUI app

I'm using Auth0 for login and logout in my iOS app. after the user logs in I get an id token which I use to make the further api calls in my app. we need to keep updating the token with auth0 as mentioned in their doc
My function is as follows
struct UpdateToken {
let credentialsManager: CredentialsManager
init() {
self.credentialsManager = CredentialsManager(authentication: Auth0.authentication())
}
func updateToken() {
guard credentialsManager.canRenew() else {
// Present login screen
print("not renewing")
return
}
Auth0
.webAuth()
.scope("openid profile offline_access")
.audience("\(audience)/userinfo")
.start {
switch $0 {
case .failure(let error):
print("token update failed")
break
// Handle error
case .success(let credentials):
// Pass the credentials over to the Credentials Manager
credentialsManager.store(credentials: credentials)
UserDefaults.standard.set(credentials.idToken, forKey: "id_token")
print("token updated")
}
}
}
}
it is printing not renewing in my console. I'm not sure what I am missing here.
the login function works perfectly fine
func login() {
Auth0
.webAuth()
.start { result in
// Handle the result of the authentication
switch result {
case .failure(let error):
// If the authentication fails, print the error message
print("Failed with: \(error)")
case .success(let credentials):
// If the authentication is successful, store the credentials and user information in UserDefaults
self.userProfile = Profile.from(credentials.idToken)
self.userIsAuthenticated = "1"
print("Credentials: \(credentials)")
// Store the ID token
print("ID token: \(credentials.idToken)")
UserDefaults.standard.set(credentials.idToken, forKey: "id_token")
// Print and store the token type and access token
print("token type: \(credentials.tokenType)")
print("access token \(credentials.accessToken)")
// Extract and store the user ID, name, and email from the user profile
print("userID is \(userProfile.id)")
let fullString = userProfile.id
let parts = fullString.split(separator: "|")
let desiredPart = String(parts[1])
print(desiredPart)
UserDefaults.standard.set(desiredPart, forKey: "userId")
UserDefaults.standard.set(userProfile.name, forKey: "userName")
UserDefaults.standard.set(userProfile.email, forKey: "userEmail")
}
}
}
It sounds like canRenew() is unable to find any stored credentials - Try using credentialsManager.store on initial login similar to how you are in updateToken(). This way the credentials are stored in the keychain when a user logs in to begin with.

RestAPI response is not same as Postman Response

I am facing a very strange issue while calling RESTful API. I have a login API, I tested it in Postman and it's working perfectly fine. Here is a screenshot.
But once I call it using Alamofire, I get the response as "status :" 1 and "message" : 'Incorrect Credentials' It's the same email and password that I'm using in postman but still I get this response even though my email and password is correct. I have tested it on multiple email and passwords, and for every user it gives me same error.
Here is my login Function..
public func login(email: String, password: String, success: #escaping (UserData) -> (), failure: errorClosure)
{
let parameters: Parameters = [
"email": "\(email)",
"password": "\(password)"
]
session.request(Config.loginURL, method: .post, parameters: parameters, encoding: JSONEncoding.default).responseJSON
{ response in
switch response.result
{
case .success(_):
let json = response.value
print("JSON: \(json ?? "errr")")
MappingHelper.ModelFromResponse(UserData.self, response: response, success: { (result) in
success(result)
}, failure: failure)
case .failure(let error):
failure?(error)
}
}
}
This is how i'm calling it..
helper.login(email: email, password: password) { (UserData) in
print(UserData)
} failure: { (error) in
print(error)
}
Debugging..
The reason I am using session.request instead of AF.request is because when I use AF.request it throws me a certificate error.
The certificate for this server is invalid. You might be connecting to a server that is pretending to be "DOMAIN NAME" which could put your confidential information at risk.
So to bypass this error I created a session with the help of some answer from SO.
private let session: Session = {
let manager = ServerTrustManager(evaluators: ["******.com": DisabledTrustEvaluator()])
let configuration = URLSessionConfiguration.af.default
return Session(configuration: configuration, serverTrustManager: manager)
}()
I think the error is JSONEncoding.default because you don't want to send a JSON body according to your Postman screenshot. You'll want to use a url-form-encoded as defined here

Auth0 swift4 failing to handle gist scope

I am trying to use Auth0 to authorise a my app to allow Gist comments.
I am not able to get "gist" scope back.
I have configured Auth0 account correctly. Also Github account correct and everything is setup.
My login code is as follows.
Auth0
.webAuth()
.scope("gist")
.audience("https://pjdavis1970.eu.auth0.com/userinfo")
.start {
switch $0 {
case .failure(let error):
print("Error: \(error)")
case .success(let credentials):
credentialsManager.store(credentials: credentials)
DispatchQueue.main.async {
AppData.sharedInstance.setLoggedIn(loggedIn: true)
self.setButtonStatus()
}
}
}
This is returning nil in scopes. This means I am unable to use gist api to post comments. Any ideas?

Microsoft Azure mobile SDK custom provider login IOS

I have followed this tutorial to implement a login with custom provider on an Azure mobile app. The backend works perfectly but when I try to login to my new custom controller I'm not able to do it. It's possible to implement it with Xamarin and also with java Android but is no way to do it with Objective C or Swift.
The object MSClient on Microsoft Azure mobile SDK only has two login implementations.
I have tried both but without luck, the callback always returns an empty client.
I also have tried to store the token created by own API use it for login call but without luck again.
Here is my Swift code:
let client = MSClient(applicationURLString: "https://myApp.azurewebsites.net")
client.login(withProvider: "custom", urlScheme: "myApp", parameters: ["username": "pau", "password": "123456"], controller: self, animated: true) {user, error in
print("USER", user)
print("ERROR", error)
}
We found a solution, it's really easy but the msclient documentation is not clear enough. You just need to pass whatever you need (i.e: username,password) as dictionary in token parameter.
Client.msClient.login(withProvider: "auth", token: params, completion: {user, error in
print("USER", user)
print("ERROR", error)
print("USER ID", user?.userId)
print("TOKEN", user?.mobileServiceAuthenticationToken)
if let user: MSUser = user {
guard let username: String = user.userId else { return }
guard let token: String = user.mobileServiceAuthenticationToken else { return }
Client.username = username
Client.msClient.currentUser = user
completion(true)
}else {
completion(false)
}
})

Firebase authentication: linking multiple accounts in Swift

I've set up Firebase authentication for my iOS app using Facebook, Google & email/password sign in and it's all working fine. This authentication only happens when the user wants to access high-priority parts of my app (i.e. I don't require users to sign in to start using the app).
On app start up, I sign users in anonymously in the background and that's working fine too.
I've read the documentation but I'm struggling to understand the code required to enable me to link an anonymous account to a Facebook/email signed in account in the following flow:
new user opens app
user signed in anonymously in the background (new user.uid "A" created)
low priority data stored against anonymous user in Firebase realtime DB
user hits a high-priority area so needs to authenticate
user signs in using Facebook (new user.uid "B" created)
previous user.uid "A" needs to be linked to user.uid "B"
My method currently looks like this:
func signupWithFacebook(){
// track the anonymous user to link later
let prevUser = FIRAuth.auth()?.currentUser
FBSDKLoginManager().logInWithReadPermissions(["public_profile", "email"], fromViewController: self) { (result, error) in
if let token = result?.token?.tokenString {
let credential = FIRFacebookAuthProvider.credentialWithAccessToken(token)
FIRAuth.auth()?.signInWithCredential(credential, completion: { (user, error) in
if user != nil && error == nil {
// Success
self.success?(user: user!)
dispatch_async(dispatch_get_main_queue(), {
self.dismissViewControllerAnimated(true, completion: nil)
})
}
})
}
}
}
Any pointers to remove the confusion would be great.
UPDATE:
I've realised I was confused about the app logic because of users being created during testing. Instead of 2 separate users being created for the above scenario (one authenticated via Facebook and another anonymously), all that happens is that the original anonymous user.uid "A" is "linked" to some Facebook authentication credentials. In the Firebase console this is shown by the anonymous uid changing from anonymous to one with the Facebook logo next to it.
This is what my working method looks like:
func signupWithFacebook(){
FBSDKLoginManager().logInWithReadPermissions(["public_profile", "email"], fromViewController: self) { (result, error) in
if let token = result?.token?.tokenString {
let credential = FIRFacebookAuthProvider.credentialWithAccessToken(token)
FIRAuth.auth()?.currentUser!.linkWithCredential(credential) { (user, error) in
if user != nil && error == nil {
// Success
self.success?(user: user!)
dispatch_async(dispatch_get_main_queue(), {
self.dismissViewControllerAnimated(true, completion: nil)
})
} else {
print("linkWithCredential error:", error)
}
}
}
}
}
So your code follows the first 2 steps in this link. But the documentation explicity says not to call signInWithCredential but instead call
FIRAuth.auth()?.currentUser.linkWithCredential(credential) { (user, error) in
// ...
}
After getting your credential from Facebook's SDK.
Quote from link: "If the call to linkWithCredential:completion: succeeds, the user's new account can access the anonymous account's Firebase data."