Error while doing phone number verification using twilio in swift - swift

I want to verify phone number by getting one time password. But I am getting some error. Please look into the code bellow and help me to resolve it. I am using Twilio for mobile verification. And Alamofire for API request. But the error I am getting like:-
Authentication Error - No credentials provided.
The data couldn’t be read because it isn’t in the correct format
My code is:-
Here is my model class: -
...struct SendVerificationCode: Codable {
let status: String?
let payee: String?
let dateUpdated: Date?
let sendCodeAttempts: [SendCodeAttempt]?
let accountSid, to: String?
let amount: Int?
let valid: Bool?
let lookup: Lookup?
let url: String?
let sid: String?
let dateCreated: Date?
let serviceSid, channel: String?
enum CodingKeys: String, CodingKey {
case status, payee
case dateUpdated = "date_updated"
case sendCodeAttempts = "send_code_attempts"
case accountSid = "account_sid"
case to, amount, valid, lookup, url, sid
case dateCreated = "date_created"
case serviceSid = "service_sid"
case channel
}
}
struct Lookup: Codable {
let carrier: Carrier?
}
struct Carrier: Codable {
let mobileCountryCode, type: String?
let errorCode: String?
let mobileNetworkCode, name: String?
enum CodingKeys: String, CodingKey {
case mobileCountryCode = "mobile_country_code"
case type
case errorCode = "error_code"
case mobileNetworkCode = "mobile_network_code"
case name
}
}
struct SendCodeAttempt: Codable {
let channel, time: String?
}...
Api Request:-
...func sendcode(mobileWithCode: String, completion: #escaping sendTwillioVerificationCodeCompletion) {
let url = URL(string: SEND_TWILIO_VERIFICATION_CODE)
var urlRequest = URLRequest(url: url!)
urlRequest.httpMethod = HTTPMethod.post.rawValue
urlRequest.addValue(userNameData, forHTTPHeaderField: "Username")
urlRequest.addValue(PasswordData, forHTTPHeaderField: "Password")
urlRequest.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
Alamofire.request(urlRequest).responseJSON { (response) in
if let error = response.result.error {
debugPrint(error.localizedDescription)
completion(nil)
return
}
guard let data = response.data else { return completion(nil)}
Common.sharedInstance().printRequestOutput(data: data)
let jsonDecoder = JSONDecoder()
do {
let clear = try jsonDecoder.decode(SendVerificationCode.self, from: data)
completion(clear)
} catch {
debugPrint(error.localizedDescription)
completion(nil)
}
}
}...
But i am getting error:-
{"code": 20003, "detail": "Your AccountSid or AuthToken was incorrect.", "message": "Authentication Error - No credentials provided", "more_info": "https://www.twilio.com/docs/errors/20003", "status": 401}
"The data couldn’t be read because it isn’t in the correct format."
Also i have tried the following code:-
import Foundation
semaphore = DispatchSemaphore (value: 0)
let parameters = "To=+919778882332&Channel=sms"
let postData = parameters.data(using: .utf8)
var request = URLRequest(url: URL(string: myUrl)!,timeoutInterval: Double.infinity)
request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.addValue(requestData, forHTTPHeaderField: "Authorization")
request.httpMethod = "POST"
request.httpBody = postData
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data else {
print(String(describing: error))
return
}
print(String(data: data, encoding: .utf8)!)
semaphore.signal()
}
task.resume()
semaphore.wait()
But i am getting error like
"Invalid parameter"

Twilio developer evangelist here.
It looks as though your code is trying to call the Twilio API directly from the device and that you weren't setting your Account SID or Auth Token in that.
The issue here is that you should not store or access your auth token from within your application. That would make your account sid and auth token vulnerable to be stolen and then used to abuse your account.
Instead, you should create a server side application that talks to the Twilio API and then call that from your application.
As Jamil pointed out, there is a blog post you can follow on performing phone verification in iOS with Twilio Verify and Swift and I recommend you go through that. It includes an example server side application to call the Twilio Verify API built in Python, but you could build your own too.

Here is sample code:
import UIKit
class ViewController: UIViewController {
static let path = Bundle.main.path(forResource: "Config", ofType: "plist")
static let config = NSDictionary(contentsOfFile: path!)
private static let baseURLString = config!["serverUrl"] as! String
#IBOutlet var countryCodeField: UITextField! = UITextField()
#IBOutlet var phoneNumberField: UITextField! = UITextField()
#IBAction func sendVerification() {
if let phoneNumber = phoneNumberField.text,
let countryCode = countryCodeField.text {
ViewController.sendVerificationCode(countryCode, phoneNumber)
}
}
static func sendVerificationCode(_ countryCode: String, _ phoneNumber: String) {
let parameters = [
"via": "sms",
"country_code": countryCode,
"phone_number": phoneNumber
]
let path = "start"
let method = "POST"
let urlPath = "\(baseURLString)/\(path)"
var components = URLComponents(string: urlPath)!
var queryItems = [URLQueryItem]()
for (key, value) in parameters {
let item = URLQueryItem(name: key, value: value)
queryItems.append(item)
}
components.queryItems = queryItems
let url = components.url!
var request = URLRequest(url: url)
request.httpMethod = method
let session: URLSession = {
let config = URLSessionConfiguration.default
return URLSession(configuration: config)
}()
let task = session.dataTask(with: request) {
(data, response, error) in
if let data = data {
do {
let jsonSerialized = try JSONSerialization.jsonObject(with: data, options: []) as? [String : Any]
print(jsonSerialized!)
} catch let error as NSError {
print(error.localizedDescription)
}
} else if let error = error {
print(error.localizedDescription)
}
}
task.resume()
}
}
For more please check this link: Link.

Related

Make a Get Request api to a JWT enabled endpoint

I am trying to make a get request to a JWT enabled API but I am getting my result in bytes instead of objects
after the user logs in it is expected to go the next page where it lists user projects, at the moment I've created a button which when clicked, should send a Get Request with the JWT token received from the API function below.
I have tried:
func getUserProject(token: String, completion: #escaping (Result<[Project], NetworkError>) -> Void) {
guard let url = URL(string: "https://api.t.io/api/manage/user/projects?archived=false&logic=and&page=0&size=10") else {
completion(.failure(.invalidURL))
print("unable to connect URL🆘")
return
}
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.addValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
guard let data = data, error == nil else {
completion(.failure(.noData))
print("Bad🥺")
return
}
guard let Projects = try? JSONDecoder().decode([Project].self, from: data) else {
completion(.failure(.decodingError))
print(data)
print("Error Decoding Data🥵")
return
}
completion(.success(Projects))
}
task.resume()
}
This is the error I am getting from my logs:
this is my project model:
let createdBy: String
let createdDate: EdDate
let lastModifiedBy: String
let lastModifiedDate: EdDate
let id: Int
let name: String
let customID: JSONNull?
let shared: Bool
let salt: JSONNull?
let isCOMRequestAutomatic: Bool
let client: Client
let company: Company
let projectKeywords: [JSONAny]
let projectStartDate, projectEndDate: JSONNull?
enum CodingKeys: String, CodingKey {
case createdBy, createdDate, lastModifiedBy, lastModifiedDate, id, name, status
case imageURL
case customID
case shared, salt
case isCOMRequestAutomatic
case client, company, projectKeywords, projectStartDate, projectEndDate
}
} ```

Swift: Get value from a JSON

I'm totally new with swift, it's my first iOs app
I would like to retrieve a value from an http POST response
struct represCode: Codable{
var CODE: String?
}
var table = [represCode]()
func httpPost(completion: #escaping (_ json: Any?)->()) {
let json: [String: Any] = ["login": usernameText.text!.uppercased(),
"pass": mdpText.text!]
let urlPath = url.chaine + "login.php"
let jsonData = try? JSONSerialization.data(withJSONObject: json)
let url = URL(string: urlPath)!
var request = URLRequest(url: url)
request.httpMethod = "POST"
// insert json data to the request
request.httpBody = jsonData
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
print(error?.localizedDescription ?? "No data")
return
}
do {
self.table = try JSONDecoder().decode([represCode].self, from: data)
print(self.table)
self.dl = true
}catch _ {
print ("JSON Error")
}
completion(json)
}
task.resume()
}
When I "print(self.table)" I get this
[Mobois.LoginViewController.represCode(CODE: Optional("AG"))]
And I would like to store the "AG" in a specific var (ex: var represCode: String?)
I tried many solutions that I found here but most of time I get errors like "Cannot assign value of type '[LoginViewController.represCode]' to type 'String'"
There are two serious mistakes.
The root object is an array (represented by the [] in [represCode].self)
The value AG is the value for key CODE
First of all to conform to the naming convention declare the struct this way
struct RepresCode: Decodable {
let code: String
private enum CodingKeys: String, CodingKey { case code = "CODE" }
}
and
var table = [RepresCode]()
..
JSONDecoder().decode([RepresCode].self ...
You can access the value by getting the value for property code of the first item in the array
let represCode = table.first?.code ?? "unknown code"

Why doesn't the text from the YELP API display on to my label?

Basically Im receiving reviews for a specific restaurant using the YELP API and I want to display the reviews to my SKLabel. I can see the reviews in my console printing out but when I try to get the text value from my struct it doesn't appear on to the SKLabel. Here is the code Im working with. Thank you!
extension GameScene {
func fetchReviews(id: String, //Required
locale: String, //Optional
completionHandler: #escaping ([Reviews]?, Error) -> Void) {
// MARK: Retrieve venues from Yelp API
let apikey = "API KEY"
/// create URL
let baseURL = "https://api.yelp.com/v3/businesses/\(id)/reviews"
let url = URL(string: baseURL)
print("this is the url for reviews : \(url)")
/// Creating request
var request = URLRequest(url: url!)
request.setValue("Bearer \(apikey)", forHTTPHeaderField: "Authorization")
request.httpMethod = "GET"
URLSession.shared.dataTask(with: request) { (data, response, error) in
if let err = error {
print(err.localizedDescription)
}
do {
let json = try JSONSerialization.jsonObject(with: data!, options: []) as! [String: Any]
print(">>>>>", json, #line, "<<<<<<<<<")
} catch {
print("caught")
}
}.resume()
}
}
//Reviews.swift
struct Reviews {
var text : String?
var locale : String?
var id : String?
var total : Int?
var rating: Int?
}
//GameScene.swift
fetchReviews(id: venue.id!, locale: "en_US") { (response, error) in
for review in response! {
reviewLabel.text = review.text //Doesn't work here
reviewLabel.position = CGPoint(self.size.width / 2, self.size.height / 2)
reviewLabel.fontColor = .white
reviewLabel.fontSize = 20
addChild(reviewLabel)
}
}

Swift used Codable, but the type is not correct

I know that Codable = Decodable & Encodable but when calling json from xcode,
Codable was given as a struct, but an error saying
Argument type'login.Type' does not conform to expected type'Encodable' appears.
json code
struct login: Codable {
var userId: String?
var userPw: String?
class func LoginBoard(_ completeHandler: #escaping (login) -> Void) {
let loginboard: String = MAIN_URL + "/member/login"
guard let url = URL(string: loginboard) else {
print("Error: cannot create URL")
return
}
var urlRequest = URLRequest(url: url)
urlRequest.httpMethod = "POST"
urlRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
urlRequest.addValue("application/json", forHTTPHeaderField: "Accept")
urlRequest.httpBody = try? JSONEncoder().encode(login) // ERROR [Argument type 'login.Type' does not conform to expected type 'Encodable']
let session = URLSession.shared
let task = session.dataTask(with: urlRequest) { (data, response, error) in
guard error == nil else {
print("error calling Post on /todos/1")
print(error!)
return
}
guard let responseData = data else {
print("Error: did not receive data")
return
}
do {
let decoder = JSONDecoder.init()
let LoginList = try decoder.decode(login.self, from: responseData)
completeHandler(LoginList)
}
catch {
print("error trying to convert data to JSON")
return
}
}
task.resume()
}
There is no error in try decoder.decode
but only in urlRequest.httpBody = try? JSONEncoder().encode(login) what is the problem?
You need to have something like this to set the values.
let loginvalues = login(userId: "john", userPw: "adfadfa")
urlRequest.httpBody = try? JSONEncoder().encode(loginvalues)
If you place this inside a play ground and run it you will see that you get the json data.
struct Login: Codable {
var userId: String?
var userPw: String?
}
let loginvalues = Login(userId: "john", userPw: "adfadfa")
let test = try? JSONEncoder().encode(loginvalues)
print(String(data: test!, encoding: .utf8)!)

POST method in Swift4 urlSession Decodable not working(What goes wrong here?)

I am trying to post 2 parameters (email: and password) to get a response from the server with detailed user information, I build API to handle this and get a good response using Postman, but when I tried to implement this with Swift4 new urlsession JSON decode and encode, it keeps failing and I got error on decoding the response data.
this my JSON response when using Postman:
{
"error": "false",
"message": "downloaded",
"UserInfo": {
"id": 5,
"email": "abc#hotmail.com",
"lastname": "Bence",
"name": "Mark",
"phone": "1234567",
"add1": "333",
"add2": "444",
"city": "ott",
"postalcode": "tttttt"
}
}
My struct file:
import UIKit
struct loginPost: Encodable {
let email: String
let password: String
}
struct User: Decodable {
let error: String?
let message: String?
let UserInfo: [UserData]
}
struct UserData: Codable {
let id: Int?
let email: String?
let lastname: String?
let name: String?
let phone: String?
let add1: String?
let add2: String?
let city: String
let postalcode: String?
}
My Function
func downloadJson() {
let url = URL(string: http://192.168.0.10/api/login_hashed.php)
guard let downloadURL = url else { return }
//POST Req
var request = URLRequest(url: downloadURL)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
let newpost = loginPost(email: "abc#hotmail.com", password: "123456")
do {
let jsonBody = try JSONEncoder().encode(newpost)
request.httpBody = jsonBody
print(jsonBody)
}catch{
print("some error")
}
URLSession.shared.dataTask(with: request) { data, urlResponse, error in
guard let data = data, error == nil, urlResponse != nil else {
print("something is wrong with url")
return
}
print("downloaded..")
do
{
let decoder = JSONDecoder()
let downloaduser = try decoder.decode(User.self, from: data)
self.logmessage = downloaduser.message!
print(self.logmessage)
DispatchQueue.main.async {
// self.tableView.reloadData()
}
} catch {
print("something wrong with decode")
}
}.resume()
}
I have figured it out finally, thanks,.
I just want to mention the cause of this error and share my experience.
The main cause is the way you send JSON and receive the incoming response. you should know exactly how the data look in order to create your struct the acceptable way.
My return data is just simple 2 line of text and array of text, my struct was:
import UIKit
struct loginPost: Encodable {
let email: String
let password: String
}
struct User: Decodable {
let error: String?
let message: String?
let UserInfo: [UserData]
}
struct UserData: Codable {
let id: Int?
let email: String?
let lastname: String?
let name: String?
let phone: String?
let add1: String?
let add2: String?
let city: String
let postalcode: String?
}
my mistake on line 18
let UserInfo: [UserData]
it should be
let UserInfo: UserData?
without the square bracket.
one more important point, always try to catch the decode error and it's dicription by implementing }catch let JsonErr {, it will give you exactly why the decode not working.
in my case:
downloaded.. something wrong after downloaded
typeMismatch(Swift.Array, Swift.DecodingError.Context(codingPath:
[h2h.User.(CodingKeys in _E33F61CC43E102744E4EF1B7E9D7EDDE).UserInfo],
debugDescription: "Expected to decode Array but found a
dictionary instead.", underlyingError: nil))
And make sure to make your server API to accept JSON format application/json and
decode what you send in order to receive what you looking for;
php code service API
$UserData = json_decode(file_get_contents("php://input"), true);
Simplest and easy way to decode the json.
MUST TRY
struct Welcome: Codable {
let error, message: String?
let userInfo: UserInfo?
enum CodingKeys: String, CodingKey {
case error, message
case userInfo = "UserInfo"
}
}
// MARK: - UserInfo
struct UserInfo: Codable {
let id: Int?
let email, lastname, name, phone: String?
let add1, add2, city, postalcode: String?
}
After that in your code , when you get response from api then write
let decoder = JSONDecoder()
let obj = try! decoder.decode(Welcome.self, from: jsonData!)
Print(obj)
List item
This Will work Are You Creating Model Is Wrong
struct loginPost: Encodable {
let email: String
let password: String
}
struct Users:Codable {
var error:String?
var message:String?
var UserInfo:UserDetails?
}
struct UserDetails:Codable {
let id: Int?
let email: String?
let lastname: String?
let name: String?
let phone: String?
let add1: String?
let add2: String?
let city: String
let postalcode: String?
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
downloadJson()
}
func downloadJson() {
let url = URL(string: "http://192.168.0.10/api/login_hashed.php")
guard let downloadURL = url else { return }
//POST Req
var request = URLRequest(url: downloadURL)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
let newpost = loginPost(email: "abc#hotmail.com", password: "123456")
do {
let jsonBody = try JSONEncoder().encode(newpost)
request.httpBody = jsonBody
print(jsonBody)
}catch{
print("some error")
}
URLSession.shared.dataTask(with: request) { data, urlResponse, error in
guard let data = data, error == nil, urlResponse != nil else {
print("something is wrong with url")
return
}
print("downloaded..")
do
{
let decoder = JSONDecoder()
let downloaduser = try decoder.decode(Users.self, from: data)
// self.logmessage = downloaduser.message!
// print(self.logmessage)
DispatchQueue.main.async {
// self.tableView.reloadData()
}
} catch {
print("something wrong with decode")
}
}.resume()
}
}