I am currently building an iOS app which communicates with a ruby-on-rails api. The user management(sign_in, sign_out,...) part of the api is handled with devise_token_auth gem.
I am also using Alamofire to run HTTP requests.
I am currently testing two apis:
POST /api/auth/sign_in(.:format) devise_token_auth/sessions#create
POST /api/posts(.:format) api/posts#create
The first api is used to login while the second creates posts. FYI, in my posts_controller, I am using before_action :authenticate_user! to prevent non authenticated users to create posts.
Here is what I want to do:
Sign in from the client side (iOS app) --> the sign_in api returns the access-token
Create a post from the client side using the access-token.
I managed to get the access-token using this code:
let parameters = [
"email":"omar#omar.com",
"password":"password"]
Alamofire.request(.POST, "http://localhost:3000/api/auth/sign_in", parameters: parameters)
.responseJSON { response in
// get my access token and store it.
}
When I try to create a post(2nd part), here is what I did :
let headers = ["access-token":"<my-token-value>",
"token-type": "Bearer",
"uid":"omar#omar.com"]
let parameters = [
"title":"this is a title",
"body":"this is a body"]
Alamofire.request(.POST, "http://localhost:3000/api/posts", parameters: parameters, headers: headers)
.responseJSON { response in
print(response.response) // URL response
}
When printing the response, here is what I get:
Optional(<NSHTTPURLResponse: 0x7fe422f2b670> { URL: http://localhost:3000/api/posts } { status code: 401, headers {
"Cache-Control" = "no-cache";
Connection = "Keep-Alive";
"Content-Length" = 37;
"Content-Type" = "application/json; charset=utf-8";
Date = "Thu, 03 Mar 2016 15:03:27 GMT";
Server = "WEBrick/1.3.1 (Ruby/2.2.1/2015-02-26)";
"Set-Cookie" = "request_method=POST; path=/";
Vary = Origin;
"X-Content-Type-Options" = nosniff;
"X-Frame-Options" = SAMEORIGIN;
"X-Request-Id" = "82a88799-3fac-42e0-bd01-db5b7e24fcda";
"X-Runtime" = "0.045969";
"X-Xss-Protection" = "1; mode=block";
} })
Also, on Rails server logs:
Filter chain halted as :authenticate_user! rendered or redirected
Completed 401 Unauthorized in 15ms (Views: 0.8ms | ActiveRecord: 4.4ms)
Does anyone know where the error is coming from?
I finally found the solution. Beside expecting the access-token, the token-type and the uid, my API was also expecting the client id in the headers. This client id is sent at the sign_in request response.
Related
First of all, we are using below code so as the api's works only on mobile devices and not on browsers per say.
"
$iPod = stripos($_SERVER['HTTP_USER_AGENT'], "iPod");
$iPhone = stripos($_SERVER['HTTP_USER_AGENT'], "iPhone");
$iPad = stripos($_SERVER['HTTP_USER_AGENT'], "iPad");
$Android = stripos($_SERVER['HTTP_USER_AGENT'], "Android");
$json_data = json_decode(file_get_contents('php://input'));
if ($json_data) {
$username_1 = $json_data->username;
if ($Android || $iPad || $iPhone || $iPod) {}
Secondly, the api's are working on android(using volley) and in ios objective-c using AFNetworking. But, now i am porting the project to swift3 and i am using "Alamofire" for network calls.
Method:: (This is how i make POST request):
let headers : HTTPHeaders = [
"Accept" : "application/json"
]
Alamofire.request("API URL", method: .post, parameters: parameters, encoding: JSONEncoding.default, headers: headers)
.responseJSON{
response in
if let json = response.result.value{
}
But, i am getting error 404, which we usually get when we hit api in browser.
After that i removed that backend check and the request worked fine and got the proper response. But, we can't remove that check. So help me, if i am making any mistakes with headers of something else.
This is what i am getting in debugPrint(response)::
{ status code: 200, headers {
"Access-Control-Allow-Origin" = "*";
"Cache-Control" = "no-store, no-cache, must-revalidate, post-check=0, pre-check=0";
Connection = "Keep-Alive";
"Content-Encoding" = gzip;
"Content-Length" = 84;
"Content-Type" = "text/html; charset=UTF-8";
Date = "Thu, 14 Sep 2017 17:03:17 GMT";
Expires = "Thu, 19 Nov 1981 08:52:00 GMT";
"Keep-Alive" = "timeout=5";
Pragma = "no-cache";
Server = "Apache/2.4.25";
Vary = "Accept-Encoding,User-Agent";
"X-Powered-By" = "PHP/5.6.31";
} }
[Data]: 80 bytes
[Result]: SUCCESS: {
"is_valid" = 0;
status = 404;
"status_message" = "access denied";
success = 0;
}
Alomafire sends a default header parameter User-Agent alright but its value is something like this iOS Example/1.0 (com.alamofire.iOS-Example; build:1; iOS 10.0.0) Alamofire/4.0.0.
This is from their readme:
You can obviously provide your own custom headers:
let headers: HTTPHeaders = [
"User-Agent": "iPhone",
"Accept": "application/json"
]
Alamofire.request("<Ypur URL>", headers: headers)
.responseJSON { response in
debugPrint(response)
}
Or if you want to keep other default header parameters
var headers = Alamofire.SessionManager.defaultHTTPHeaders
headers["User-Agent"] = "iPhone"
I'am using a REST API which returns some JSON block as a response.Here my request fulfills successfully but it returns some header block as a response instead of JSON. What does this code block means ?
P.S : I'm using NSURLSessionDataTask for hitting API.
{
status code: 200, headers {
"Access-Control-Allow-Credentials" = true;
"Access-Control-Allow-Headers" = "origin, content-type, accept, authorization";
"Access-Control-Allow-Methods" = "GET, POST, DELETE, PUT";
"Access-Control-Allow-Origin" = "*";
"Content-Type" = "application/json;charset=utf-8";
Date = "Thu, 08 Sep 2016 08:19:00 GMT";
Server = "Apache-Coyote/1.1";
"Transfer-Encoding" = Id
}
header properties are your servis properties. for example;
Access-Control-Allow-Methods -> Which can call Methods. You can call get, post, delete and put function or services in your services project.
Content-Type -> Services return object type.
I hope that helps.
I am trying to send a post request for the twilio api using swift and Alamofire, but I am having some issues.
This is the function that should send the text:
func sendSMS() {
let parameters = [
"To": "+12036044632",
"From": "+13852322267",
"Body": "Hi daddy"
]
Alamofire.request(.POST, "https://MY SID:MY SECRET#api.twilio.com/2010-04-01/Accounts/MY SID/Messages", parameters: parameters).response { response in
print(response.0)
print(response.1)
print(response.2)
print(response.3)
}
}
When I run this, I get this printed in the console:
`Optional(<NSMutableURLRequest: 0x7a844a30> { URL: https://AC11ed62fdb971a8f56d9be531a5ce40c2:UKCkDN1ojSeT4L27lc8uaNQ5qsvPJgMxd#api.twilio.com/2010-04-01/Accounts/AC11ed62fdb971a8f56d9be531a5ce40c2/Messages })
Optional(<NSHTTPURLResponse: 0x7a9f91f0> { URL: https://AC11ed62fdb971a8f56d9be531a5ce40c2:UKCkDN1oj2SeT4L7lc8uaNQ5qsvPJgMxd#api.twilio.com/2010-04-01/Accounts/AC11ed62fdb971a8f56d9be531a5ce40c2/Messages } { status code: 401, headers {
"Access-Control-Allow-Credentials" = true;
"Access-Control-Allow-Headers" = "Accept, Authorization, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since";
"Access-Control-Allow-Methods" = "GET, POST, DELETE, OPTIONS";
"Access-Control-Allow-Origin" = "*";
"Access-Control-Expose-Headers" = ETag;
Connection = "keep-alive";
"Content-Length" = 327;
"Content-Type" = "application/xml";
Date = "Tue, 02 Aug 2016 02:21:01 GMT";
"Twilio-Request-Duration" = "0.004";
"Twilio-Request-Id" = RQ36001aed85114ea18c7eac4f20caaf59;
"Www-Authenticate" = "Basic realm=\"Twilio API\"";
"X-Powered-By" = "AT-5000";
"X-Shenanigans" = none;
} })
Optional(<3c3f786d 6c207665 7273696f 6e3d2731 2e302720 656e636f 64696e67 3d275554 462d3827 3f3e0a3c 5477696c 696f5265 73706f6e 73653e3c 52657374 45786365 7074696f 6e3e3c43 6f64653e 32303030 333c2f43 6f64653e 3c446574 61696c3e 596f7572 20416363 6f756e74 53696420 6f722041 75746854 6f6b656e 20776173 20696e63 6f727265 63742e3c 2f446574 61696c3e 3c4d6573 73616765 3e417574 68656e74 69636174 696f6e20 4572726f 72202d20 4e6f2063 72656465 6e746961 6c732070 726f7669 6465643c 2f4d6573 73616765 3e3c4d6f 7265496e 666f3e68 74747073 3a2f2f77 77772e74 77696c69 6f2e636f 6d2f646f 63732f65 72726f72 732f3230 3030333c 2f4d6f72 65496e66 6f3e3c53 74617475 733e3430 313c2f53 74617475 733e3c2f 52657374 45786365 7074696f 6e3e3c2f 5477696c 696f5265 73706f6e 73653e>)
nil`
I then do not get a text message, and also on the Twilio console, it does not count and does not charge me. Am I getting some kind of error? What am I doing wrong?
Note: I understand the security risks of having the auth in the url, and that is not the fix I am looking for so please do not post or comment about that. Thanks
Instead of:
Alamofire.request(.POST, "https://MY SID:MY SECRET#api.twilio.com/2010-04-01/Accounts/MY SID/Messages", parameters: parameters).response { response in
print(response.0)
print(response.1)
print(response.2)
print(response.3)
}
Try this:
Alamofire.request(.POST, "https://MY SID:MY SECRET#api.twilio.com/2010-04-01/Accounts/MY SID/Messages", parameters: parameters)
.authenticate(user: user, password: password)
.responseJSON { response in
let response = String(response.result.value)
print(response)
}
You have to authenticate correctly into Twilio using Alamofire, and that is what ".authenticate" is for. Change the variable user to your account SID, and change the variable password to your auth token. Reference https://www.twilio.com/console/account/settings to find your account SID and auth token.
You can then manipulate the response string however you'd like.
Hope this helps.
{ status code: 401
It means you're not authenticated. It is possible that your AccountSid or AuthToken was incorrect. If you like to check your credentials, you can try first from your computer with curl and once you get it working you can move to Alamofire.
Example request with curl
curl -X POST 'https://api.twilio.com/2010-04-01/Accounts/ACc0966dd96e4d55d26ae72df4d6dc3494/Messages.json' \
--data-urlencode 'To=+16518675309' \
--data-urlencode 'From=+14158141829' \
--data-urlencode 'Body=Hey Jenny! Good luck on the bar exam!' \
-u ACc0966dd96e4d55d26ae72df4d6dc3494:[AuthToken]
docs at https://www.twilio.com/docs/api/rest/sending-messages
Im getting this error while posting image to Pinterest
Domain=com.alamofire.error.serialization.response Code=-1011 "Request failed: unauthorized (401)" UserInfo={com.alamofire.serialization.response.error.response=<NSHTTPURLResponse: 0x144603bd0> { URL: https://api.pinterest.com/v1/pins/ } { status code: 401, headers {
"Accept-Ranges" = bytes;
"Cache-Control" = private;
Connection = close;
"Content-Length" = 177;
"Content-Type" = "application/json";
Date = "Sun, 10 Jul 2016 19:38:00 GMT";
"Pinterest-Generated-By" = "devplatform-devapi-prod-de3d740a";
"Pinterest-Version" = bcdafd3;
Server = nginx;
"X-Content-Type-Options" = nosniff;
"X-Pinterest-RID" = 480720869025;
"X-Varnish" = 2958547338;
} }, NSErrorFailingURLKey=https://api.pinterest.com/v1/pins/, com.alamofire.serialization.response.error.data=<7b227374 61747573 223a2022 6661696c 75726522 2c202263 6f646522 3a20332c 2022686f 7374223a 20226465 76706c61 74666f72 6d2d6465 76617069 2d70726f 642d6465 33643734 3061222c 20226765 6e657261 7465645f 6174223a 20225375 6e2c2031 30204a75 6c203230 31362031 393a3338 3a303020 2b303030 30222c20 226d6573 73616765 223a2022 41757468 6f72697a 6174696f 6e206661 696c6564 2e222c20 22646174 61223a20 6e756c6c 7d>, NSLocalizedDescription=Request failed: unauthorized (401)}
Here is my code:
PDKClient.sharedInstance().createPinWithImage(image, link: NSURL(string:"http://domain"), onBoard: "MyBoard", description: caption, progress: {percent in
print(percent)
}, withSuccess: {PDKResponseObject in
print("ok")
print(PDKResponseObject.boards())
}, andFailure: {error in
print(error)
})
Error 401 means one of the following.
1.Authentication failed.
2.Authorization failed.
3.You are not permitted to access that resource.
Double check your permissions, check your session token expired or not.
So I think that there is nothing wrong with your code, or the request. It's something with the permissions you have in your Pinterest app.
Try changing the request URL from http to https.
Check the parameters you sending to Pinterest, check whether the parameter names are correct or not, as specified in Pinterest documentation. Also those parameters has the proper type of data, I mean do not pass String in the place of Integer value.
.
I'm using AFNetworking version 3.0 for handling a POST request.
When I run the code I get an error that says:enter code here
2016-01-26 16:48:50.181 Voluntree[3590:1749083] In order to validate a domain name for self signed certificates, you MUST use pinning.
2016-01-26 16:48:50.905 Voluntree[3590:1748745] Error: Error Domain=com.alamofire.error.serialization.response Code=-1016 "Request failed: unacceptable content-type: text/plain" UserInfo={com.alamofire.serialization.response.error.response=<NSHTTPURLResponse: 0x13deb83d0> { URL: https://voluntree.imrapid.io/signup_by_email } { status code: 200, headers {
"Access-Control-Allow-Headers" = "Origin, X-Requested-With, Content-Type, Accept";
"Access-Control-Allow-Methods" = "POST, GET, OPTIONS, PUT, DELETE, HEAD";
"Access-Control-Allow-Origin" = "*";
Connection = "keep-alive";
"Content-Length" = 4;
"Content-Type" = "text/plain";
Date = "Tue, 26 Jan 2016 14:48:50 GMT";
Server = Cowboy;
Via = "1.1 vegur";
"X-Powered-By" = Express;
} }, NSErrorFailingURLKey=https://voluntree.imrapid.io/signup_by_email, com.alamofire.serialization.response.error.data=<32343634>, NSLocalizedDescription=Request failed: unacceptable content-type: text/plain}
You should change the header "Content-Type" value to application/www-x-form-urlencoded and not "text/plain" as it right now.
For application/x-www-form-urlencoded, the body of the HTTP message sent to the server is essentially one giant query string -- name/value pairs are separated by the ampersand (&), and names are separated from values by the equals symbol (=). An example of this would be:
MyVariableOne=ValueOne&MyVariableTwo=ValueTwo