401 alamofire get request with headers - swift

I'm getting error 401 trying to make a request using custom headers, when I print the headers, it is there, just like I make a call using postman, the difference is that in postman the request works, but in the app I get that error, I don't think it is the headers, because as I said they are there, what am I missing here?
func getUserByID(completion: #escaping CompletionHandler) {
let url_id = URL_USER_ID + String(self.userID)
let header:HTTPHeaders = [
"Content-Type": "application/json",
"Authorization": "Token " + AuthService.instance.authToken
]
Alamofire.request(url_id, method: .get, parameters: nil, encoding: JSONEncoding.default, headers: header).responseJSON{
(response) in
guard let data = response.data else {return}
let json = try? JSON(data: data)
if response.response?.statusCode == 200 {
let user = json!["user"]
let id = user["id"].stringValue
let email = user["email"].stringValue
let img = user["img"].stringValue
let tipo_usuario = user["tipo_usuario"].intValue
let nome_comp = user["nome_comp"].stringValue
let end_cep = user["end_cep"].stringValue
let end_logr = user["end_logr"].stringValue
let end_num = user["end_num"].stringValue
let end_bairro = user["end_bairro"].stringValue
let end_complm = user["end_complm"].stringValue
let cidade = user["cidade"]
let cidadeID = cidade["id"].intValue
let cidadeNome = cidade["nome"].stringValue
let cidadeEstado = cidade["estado"].stringValue
let telefone = user["telefone"].stringValue
let whatsapp = user["whatsapp"].stringValue
let pontos = user["pontos"].intValue
let cnpj_cpf = user["cnpj_cpf"].stringValue
let razao_social = user["razao_social"].stringValue
let nome_fantasia = user["nome_fantasia"].stringValue
let insc_estadual = user["insc_estadual"].stringValue
let categoria = user["categoria"].intValue
let nota = user["nota"].stringValue
let cidadeUser = Cidades(id: cidadeID, nome: cidadeNome, estado: cidadeEstado)
UserDataService.instance.setUserData(id: id, email: email, img: img, tipo_usuario: tipo_usuario, nome_comp: nome_comp, end_cep: end_cep, end_logr: end_logr, end_num: end_num, end_bairro: end_bairro, end_complm: end_complm ,cidade: cidadeUser, telefone: telefone, whatsapp: whatsapp, pontos: pontos, cnpj_cpf: cnpj_cpf, razao_social: razao_social, nome_fantasia: nome_fantasia, insc_estadual: insc_estadual, categoria: categoria, nota: nota)
self.userEmail = email
self.userID = Int(id)!
completion(true)
} else if response.response?.statusCode == 400 {
completion(false)
} else {
debugPrint(response.result.error as Any)
}
}
}enter code here
and the error message:
Error=-25300, query={
atyp = http;
class = inet;
"m_Limit" = "m_LimitAll";
ptcl = http;
"r_Attributes" = 1;
sdmn = "api.ddns.net";
srvr = "api.ddns.net";
sync = syna;
}
$ curl -v \
-H "Content-Type: application/json" \
-H "Accept-Language: en;q=1.0, pt-BR;q=0.9" \
-H "Authorization: Token 4e97e608c72636052583a1bb1c170485417a739b" \
-H "User-Agent: clubelocal/1.0 (com.api; build:1; iOS 11.2.0) Alamofire/4.7.0" \
-H "Accept-Encoding: gzip;q=1.0, compress;q=0.5" \
"http://api.ddns.net:8000/users/25"
Optional({
"detail" : "the user credentials was not provided."
})

I faced similar issue like:
Postman performed request with success, but alamofire
with 401 JWT Token not found. So the response was a failure, but server performed action for the request like it was success.
In my case it turned out to be redirection.
You should check if it is not due to redirection, because by default Alamofire doesn't pass authorization field in header to redirected request (this seems to be reasonable behavior in such case).
So to make authorization transmissible you can do it like:
Alamofire.SessionManager.default.delegate.taskWillPerformHTTPRedirection = { session, task, response, request in
var redirectedRequest = request
if let originalRequest = task.originalRequest,
let headers = originalRequest.allHTTPHeaderFields,
let authorizationHeaderValue = headers["Authorization"]
{
var mutableRequest = request
mutableRequest.setValue(authorizationHeaderValue, forHTTPHeaderField: "Authorization")
redirectedRequest = mutableRequest
}
return redirectedRequest
}
//now use your requests i.e:
Alamofire.request(url, method: .post, parameters: params, encoding: JSONEncoding.default, headers: header)
.validate()
.responseJSON(completionHandler: { (response) in
switch response.result {
case .success:
//success
break
case .failure(let error):
//fail
break
}
})
If you want to return to default behavior just simply:
Alamofire.SessionManager.default.delegate.taskWillPerformHTTPRedirection = nil

Related

Upload image with Alamofire , Swift 3

For upload image to server I am using Alamofire 4.4 and Swift 3.
Swager information:
curl -X POST "url/id/upload" -H "accept: application/json" -H "Authorization: Bearer token" -H "Content-Type: multipart/form-data" -F "file=#craneB.png;type=image/png"
My Swift code:
let headers = [
"Authorization": "Bearer \(GlobalToken.appToken)",
"Content-Type": "multipart/form-data" ]
let url = BaseUrl+"1f510b93-5177-4880-447d-08d6fe7a9498"+"/upload"
let data = UIImageJPEGRepresentation(selectedImage, 0.9)
Alamofire.upload(multipartFormData: { (multipartFormData) in
if let data = data{
multipartFormData.append(data, withName: "name", fileName: "filename", mimeType: "image/png")
}
}, usingThreshold: UInt64.init(), to: url, method: .post, headers: headers) { (result) in
switch result{
case .success(let upload, _, _):
// upload.validate(statusCode: 200..<299)
upload.responseJSON{ response in
print("Succesfully uploaded")
switch response.result {
case .success(let JSON):
case .failure(_):
}
if let err = response.error{
print(err)
return
}
}
upload.uploadProgress(closure: { (progress) in
})
case .failure(let error):
print("Error in upload: \(error.localizedDescription)")
}
}
Respons:
Upload Progress: 1.0
Succesfully uploaded .
But I have error :
POST BaseUrl/1f510b93-5177-4880-447d-08d6fe7a9498/upload (500) {
Message = "Internal Server Error. - System.NullReferenceException: Object reference not set to an instance of an object. \n at
MaterialService.UploadAsync(Guid Id, IFormFile file)
I guid Id send in URL, file with multipartFormData. Upload on Sawager is work. TY

PayPal SDK request for access token returns code 401 (unauthorized)

I am trying to receive an access token from PayPal's server using the authorization code in a Sandbox environment. I believe the problem is in converting curl to an Alamofire request, but I'm not sure. Any help is appreciated.
Here is my code for sending authorization to server:
func sendAuthorizationToServer(authorization: [AnyHashable: Any]) {
let jsonAuth = JSON(authorization)
let headers = [
"content-type": "application/x-www-form-urlencoded; charset=utf-8",
]
let parameters = [
"client_id": Constants.payPalSandboxID,
"client_secret": Constants.payPalSandboxSecret,
"grant_type": "authorization_code",
"redirect_uri": "urn:ietf:wg:oauth:2.0:oob",
"code": jsonAuth["response"]["code"].stringValue
]
Alamofire.request("https://api.sandbox.paypal.com/v1/oauth2/token", method: .post, parameters: parameters, encoding: URLEncoding.default, headers: headers).responseJSON { response in
print(response.request)
print(response.response)
print(response.data)
print(response.error)
}
}
I've checked jsonAuth["response"]["code"].stringValue and it is returning a correct authorization code.
My doubts are if it should be a .post request or a .get request, and if my credentials in the parameters are in the correct order/structure.
Here is the output of the last print statements:
Here is the SDK link for exchanging an authorization code for the access token:
https://github.com/paypal/PayPal-iOS-SDK/blob/master/docs/future_payments_server.md#exchange-authorization-code-for-refresh--access-tokens
import SwiftyJSON
import Alamofire
// ... ...
// ... ...
// ... ...
let credentialData = "\(paypalClientId):\(paypalSecret)".data(using: String.Encoding.utf8)!
let base64Credentials = credentialData.base64EncodedString(options: [])
let headers = [
"Authorization": "Basic \(base64Credentials)",
]
let params:[String: Any] = [
"grant_type": "client_credentials",
]
Alamofire.request(tokenAPI, method: .post, parameters: params, encoding: URLEncoding.default, headers: headers)
.validate()
.responseJSON { (response) in
debugPrint(response)
switch response.result {
case .success(let data):
let json = JSON(data)
let accessToken = json["access_token"].stringValue
break;
case .failure(let error):
debugPrint(error)
debugPrint(response.data)
}
}
Please note that encoding must be URLEncoding.default not the JSONEncoding.default

Authenticate with WhenIWork API using AlmamoFire (Swift)

UPDATED Question:
I got in touch with the WhenIWork Team and discovered that they need the username and password to be passed in the body but with our a form. So I have solved. If you look at the answer below, it works.
Thanks everyone!
I am trying to get the access token from WhenIWork using Swift and Alamofire on Xcode, the json returned Success but says "Application Not Found Error"
I've been looking for documentation from WhenIWork Doc but without success on error code. (They don't have any error in the 1xxx range)
Ideas? I am new to Swift (and coding in general) so any help would be appreciated.
Thanks!
Below is the Terminal answer:
SUCCESS: {
code = 1110;
error = "Application not found";
}
[Request]: POST https://api.wheniwork.com/2/login/
[Response]: <NSHTTPURLResponse: 0x6080000325e0> { URL: https://api.wheniwork.com/2/login/ } { status code: 401, headers {
"Access-Control-Allow-Headers" = "Authorization, Origin, X-Requested-With, W-Date-Format, Content-Type, Accept, W-Token, W-UserId, W-Key, branch";
"Access-Control-Allow-Methods" = "GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS";
"Access-Control-Allow-Origin" = "*";
"Cache-Control" = "no-cache";
Connection = "keep-alive";
"Content-Type" = "application/json";
Date = "Thu, 17 Aug 2017 17:11:08 GMT";
Server = nginx;
"Transfer-Encoding" = Identity;
"X-Database" = ro;
"X-State" = "RequestId: 0f853dd4-836f-11e7-90f4-0242e14cb0c5, LoginId: 0, AccountId: 0";
"X-Timer-Database" = "0.0052359104156494";
"X-Timer-Total" = "0.012078046798706";
} }
Code:
func logInWhenIWork() {
let parameters: Parameters = [
"username": "cxxxx#xxxx.ca",
"password": "xxxxxxx",
"W-Key": "xxxxxxxxxxxxxsxx"
]
Alamofire.request("https://api.wheniwork.com/2/login", method: .post, parameters: parameters, encoding: JSONEncoding.default).responseJSON { response in
print(response)
debugPrint(response)
if let json = response.result.value {
print("JSON: \(json)")
} else {
print(response)
}
}
I don't use Alamofire much but I tried the following:
let parameters = ["username":"user#example.com",
"password": "*******"]
let headers = ["W-Key": "iworksoharditsnotfunny"]
var req = Alamofire.request("https://api.wheniwork.com/2/login",
parameters: parameters,
encoding: JSONEncoding.default,
headers: headers)
The request ends up looking like this:
curl -v \
-H "Content-Type: application/json" \
-H "Accept-Language: en-US;q=1.0" \
-H "User-Agent: Unknown/Unknown (Unknown; build:Unknown; OS X 10.12.6) Alamofire/1.0" \
-H "W-Key: iworksoharditsnotfunny" \
-H "Accept-Encoding: gzip;q=1.0, compress;q=0.5" \
-d "{\"username\":\"user#example.com\",\"password\":\"*******\"}" \
"https://api.wheniwork.com/2/login"
Which seems to pretty much match the example given in the WhenIWork API documentation. I don't have an account so I can't test it directly.
For those of you who wanted the answer. I finally figured it out. Here it is
func logInWhenIWork() {
let url = URL(string: "https://api.wheniwork.com/2/login")!
var urlRequest = URLRequest(url: url)
urlRequest.httpMethod = "POST"
urlRequest.allHTTPHeaderFields = ["W-Key": "xxxxxxxxxxx","Content-Type":"application/json"]
let parameters = ["username": "ss#xxx.ca", "password": "sssdsds"]
do {
urlRequest.httpBody = try JSONSerialization.data(withJSONObject: parameters, options: [])
} catch {
// No-op
}
urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
Alamofire.request(urlRequest).responseJSON { response in
switch response.result {
case .success(let value):
let json = JSON(value)
// print("JSON: (json)")
let token = json["token"].stringValue
let newUserID = json["users"][0]["id"].int
print(newUserID)
self.wUserID = String(describing: newUserID)
// print(token)
self.wToken = token
if self.wToken != "" {
print("Successfully logged in")
} else {
print("Log In Failed")
}
case .failure(let error):
print(error)
}
}
}

CURL command in Alamofire with swift

I have the following working curl command which I need to run in Swift using Alamofire.
curl -k -i -d '{ "user": {"displayName":"My Test" ,"email":"test#xxtest.com","pwd":"test","roles":["stu"]}}' -H "Content-Type: application/json;charset=UTF-8" -u web:web -X POST 'https://test.herokuapp.com/xtest/auth/register'
I tried out the following method with Swift by using Alamofire. I have the impression that I do -u web:web wrong, but I have no means to confirm that.
The console gives me the following error which I don't understand:
print response object
nil
print error
Optional(Error Domain=NSCocoaErrorDomain Code=3840 "Invalid value around character 0." UserInfo={NSDebugDescription=Invalid value around character 0.})
Can someone point out what is wrong in here? Thx.
This is the function which translates the CURL command into Swift
func registerNewStudent(displayName: String, email: String, password: String, completionHandler: (AnyObject?, NSError?) -> ()) {
//Basic HTTP auth
let user = "web"
let password = "web"
let credentialData = "\(user):\(password)".dataUsingEncoding(NSUTF8StringEncoding)!
let base64Credentials = credentialData.base64EncodedStringWithOptions([])
let headers = ["Authorization": "Basic \(base64Credentials)"]
//example for a nested array query
let parameters = [
"user": [
"displayName": displayName,
"email": email,
"pwd": password,
"roles":["stu"]
]
]
Alamofire.request(
.POST,
registerURL,
headers: headers,
parameters: parameters
)
.responseJSON { response in
switch response.result {
case .Success(let value):
completionHandler(value, nil)
case .Failure(let error):
completionHandler(nil, error)
}
}
}
I call this function in the following way:
func okButtonTapped(sender: UIButton) {
let displayNameText = displayNameInput.text
let emailText = emailInput.text
let passwordText = passwordInput.text
restApi.registerNewStudent(displayNameText!,emailInput: emailText!, passwordInput: passwordText!) {responseObject, error in
// use responseObject and error here
print("print response object")
print(responseObject)
print("print error")
print(error)
}
Response from the CURL call:
{"result":{"email":"trrrrrest#xxtest.com","display_name":"My Test","pwd":"test","fb_id":null,"roles":["stu"]
I could resolve it from here: http://www.ceus-now.com/curl-d-to-alamofire/
Adding the following line after the JSON response did the trick (not before).
.authenticate(user: "web", password: "web")
so the method looks like:
Alamofire.request(
.POST,
registerURL,
parameters: parameters
)
.responseJSON { response in
switch response.result {
case .Success(let value):
completionHandler(value, nil)
case .Failure(let error):
completionHandler(nil, error)
}
}
.authenticate(user: "web", password: "web")
}

401 error using Alamofire and swift when trying to connect to my server

Ok so I am trying to download a json file as a string and parse it out latter. But I have to download it from my webpage first. This webpage needs a username and password to get to it. This has been giving me a 401 error so its not sending the username or password. How can I add the username and password to the request?
print("Downloading the json file")
let plainString = "\(myUserName):\(myPassword)" as NSString
let plainData = plainString.dataUsingEncoding(NSUTF8StringEncoding)
let base64String = plainData?.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0))
Alamofire.Manager.sharedInstance.session.configuration.HTTPAdditionalHeaders = ["Authorization": "Basic " + base64String!]
Alamofire.request(.GET, promoUrl)
.response {(request, response, _, error) in
print(response)
}
This is the result from it
Optional(<NSHTTPURLResponse: 0x7fe103818790> { URL: http://xxxapi/1.0/promotions } { status code: 401, headers {
"Cache-Control" = "no-cache, no-store, max-age=0, must-revalidate";
Connection = "keep-alive";
"Content-Length" = 186;
"Content-Type" = "application/json;charset=UTF-8";
Date = "Thu, 12 May 2016 01:36:33 GMT";
Expires = 0;
Pragma = "no-cache";
Server = "Apache-Coyote/1.1";
"Www-Authenticate" = "Basic realm=\"Realm\"";
"X-Content-Type-Options" = nosniff;
"X-Frame-Options" = DENY;
"X-XSS-Protection" = "1; mode=block";
Thank you very much for any help with this
Hi every one so after working on it a bit more i got it to work. I got rid of all the stuff on top and went simple. It worked better and is easier to do
here is the working code for anyone who wants it
Alamofire.request(.GET, promoUrl, parameters: [myUserName:myPassword])
.authenticate(user: myUserName, password: myPassword)
.response {(request, response, data, error) in
print(response)
}
The key difference is this
parameters: [myUserName:myPassword]
This loads my password and username into the url. It may not be the best way of doing this but it works for my needs for now