Twitter REST API oauth '215 Bad Authentication data' using fetch in react-native - rest

I'm trying to build a react native app to show a user's twitter timeline, but can't manage to access the twitter REST api because I am getting a
215 Bad Authentication data
error.
I've signed in the user correctly, gotten all the access tokens, and using fetch to make a request.
I've also verified that all my keys and tokens are correct, yet I still can't manage to figure out why I'm getting this error, my code is available below;
Can anyone please advise me on how to debug this or tell me what's wrong with my code?
thanks.
code:
let header = this._buildRequestHeader(twitter_token, twitter_tokenSecret);
console.log(header);
fetch('https://api.twitter.com/1.1/statuses/home_timeline.json', {
method: 'GET',
headers: {
'Accept': '*/*',
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': ' '+header
}
}).then((response) => response.json())
.then((json) => {
console.log(json);
})
_getBaseString:
_getBaseString(method, url, parameter_string){
return method+'&'+
encodeURIComponent(url)+'&'+encodeURIComponent(parameter_string);
}
_getSignature:
_getSignature(user_auth_token, accesstoken_secret, data){
// let signing_key = encodeURIComponent(Constants.TWITTER_CONSUMER_SECRET)+'&'+
// encodeURIComponent(Constants.ACCESS_TOKEN_SECRET);
let signing_key = encodeURIComponent(Constants.TWITTER_CONSUMER_SECRET)+'&'+
encodeURIComponent(accesstoken_secret);
console.log('signing data');
console.log(data);
return this.b64EncodeUnicode(hmacsha1(signing_key, data));
}
_buildRequestHeader:
_buildRequestHeader(user_auth_token, accesstoken_secret){
// https://dev.twitter.com/oauth/overview/creating-signatures
// https://dev.twitter.com/oauth/overview/authorizing-requests
let include_entities_key = encodeURIComponent('include_entities');
let include_entities_val = encodeURIComponent('false');
let oauth_consumer_key_key = encodeURIComponent('oauth_consumer_key');
let oauth_consumer_key_val = encodeURIComponent(Constants.TWITTER_COMSUMER_KEY);
let oauth_nonce_key = encodeURIComponent('oauth_nonce');
let oauth_nonce_val = encodeURIComponent(this._getNonce());
let oauth_signature_method_key = encodeURIComponent('oauth_signature_method');
let oauth_signature_method_val = encodeURIComponent('HMAC-SHA1');
let oauth_timestamp_key = encodeURIComponent('oauth_timestamp');
var val = Date.now() / 1000;
console.log(val);
console.log('parse'+parseInt(val));
let oauth_timestamp_val = encodeURIComponent(parseInt(val));
let oauth_token_key = encodeURIComponent('oauth_token');
// let oauth_token_val = encodeURIComponent(Constants.ACCESS_TOKEN);
let oauth_token_val = encodeURIComponent(user_auth_token);
let oauth_version_key = encodeURIComponent('oauth_version');
let oauth_version_val = encodeURIComponent('1.0');
// let parameter_string = include_entities_key+'='+include_entities_val+'&'+
let parameter_string = oauth_consumer_key_key+'='+oauth_consumer_key_val+'&'+
oauth_nonce_key+'='+oauth_nonce_val+'&'+
oauth_signature_method_key+'='+oauth_signature_method_val+'&'+
oauth_timestamp_key+'='+oauth_timestamp_val+'&'+
oauth_token_key+'='+oauth_token_val+'&'+
oauth_version_key+'='+oauth_version_val;
let data = this._getBaseString('GET', 'https://api.twitter.com/1.1/statuses/home_timeline.json',
parameter_string);
let signature = this._getSignature(user_auth_token, accesstoken_secret, data)
console.log('signature'+signature);
// 1499887682711
// 1318622958
let oauth_signature_key = encodeURIComponent('oauth_signature');
let oauth_signature_val = encodeURIComponent(signature);
let request_header_string = 'OAuth '+
oauth_consumer_key_key+'="'+oauth_consumer_key_val+'", '+
oauth_nonce_key+'="'+oauth_nonce_val+'", '+
oauth_signature_key+'="'+oauth_signature_val+'", '+
oauth_signature_method_key+'="'+oauth_signature_method_val+'", '+
oauth_timestamp_key+'="'+oauth_timestamp_val+'", '+
oauth_token_key+'="'+oauth_token_val+'", '+
oauth_version_key+'="'+oauth_version_val+'"';
return request_header_string;
}
But I get a 215 Bad Authentication data. Can someone please advise?

Have You try to use this package?
https://www.npmjs.com/package/react-native-twitter
or
https://github.com/GoldenOwlAsia/react-native-twitter-signin
let me know did it help.
Best Regards.
Maciej Adamczewski

I figured out what the problem was: The HMAC-SHA1 functionI was using was already doing the base-64 encoding for me.
and as Maciej Adamczewski pointed out, there was an unnecessary whitespace in the header string

Related

401 Error on CloudKit Server-to-Server Authentication on Node JS

I'm trying to query my public CloudKit database using server-to-server authentication. I've generated the key according to Apple's docs, but no matter what I do I get this error:
401 - Unauthorized
data: {
uuid: '...',
serverErrorCode: 'AUTHENTICATION_FAILED',
reason: 'no auth method found'
}
As far as I can tell, I've set everything up per the docs, but obviously I'm doing something wrong. Here's what I've got in my Node app so far:
let date = moment().format('YYYY-MM-DD[T]HH:mm:ss[Z]')
let domain = 'https://api.apple-cloudkit.com'
let subpath = '/database/1/iCloud.<my container>/development/public/users/current'
let key = fs.readFileSync(__dirname +'/../eckey.pem', 'utf8')
let keyID = 'abc123...'
let requestBody = ''
let bodyHash = crypto.createHash('SHA256').update(requestBody).digest('base64')
let message = date+':'+bodyHash+':'+subpath
let signature = crypto.createSign('RSA-SHA256').update(message).sign(key, 'base64')
let headers = {
'X-Apple-CloudKit-Request-KeyID': keyID,
'X-Apple-CloudKit-Request-ISO8601Date': date,
'X-Apple-CloudKit-Request-SignatureV1': signature
}
try{
await axios.post(domain+subpath, requestBody, { headers: headers })
console.log('--- :) ---')
}catch(error){
console.log('=== :( ===')
console.log(error)
}
I've already reviewed this helpful SO post, but I'm still stuck.
Can anyone see what I might be doing wrong?
I had to do a ton of troubleshooting to figure this out, but for the sake of posterity, here's what I had wrong:
=== Fix # 1 ===
My date was generating local time which was inaccurate because the format implies Zulu/UTC time (because of the Z).
The fix was to add .utc() to the Moment:
let date = moment().utc().format('YYYY-MM-DD[T]HH:mm:ss[Z]')
=== Fix # 2 ===
Apparently Axios didn't like how I was formatting the request. Changing it to this (with the baseURL and url separate) works:
let response = await axios({
method: 'post',
baseURL: baseURL,
url: '/records/modify',
data: query,
headers: headers
})
Seems to be working great now with these fixes in place.

Kraken EAPI: Invalid key

I am trying to do a client with swift however I cannot communicate with the private api {"error": ["EAPI: Invalid key"]}
I use CCHmac function and tried to have a look at different api implementation.
I just can't get whats wrong...
Here is my code:
func getTradeBalance(basedAsset: String, completionBlock: #escaping BlockResult) {
guard let url = URL(string: "\(krakenUtils.rootUrl)/\(krakenUtils.version)/private/Balance") else {
return
}
let nonce: String = String(Int(Date().timeIntervalSince1970.rounded()))
let path = "/\(krakenUtils.version)/private/Balance"
let pubKey = krakenUtils.publicKey
let params = ["nonce": nonce]
//Sign = HMAC-SHA512 of URI + SHA256-POSTDATAS + base64decodedSecret
let sign = getMessageSignature(path: path,
nonce: nonce)
Alamofire.request(url, method: .post,
parameters: params, encoding: JSONEncoding.default,
headers: ["API-Key": pubKey,
"API-Sign": sign])
.responseJSON { resp in
let result = self.handleResponse(result: resp)
guard let json = result.0 else {
completionBlock(nil, result.1)
return
}
print(json)
}
}
private func getMessageSignature(path: String, nonce: String) -> String {
let secretDecoded = Data(base64Encoded: krakenUtils.privateKey, options: Data.Base64DecodingOptions.init(rawValue: 0))!
let np = (nonce + "nonce=" + nonce).sha256().data(using: .utf8, allowLossyConversion: false)!
var pathNP = path.data(using: .utf8, allowLossyConversion: false)!
pathNP.append(contentsOf: np)
let lRet = HMAC.sign(data: pathNP, algorithm: .sha512, key: secretDecoded).base64EncodedString()
return lRet
}
public static func sign(data: Data, algorithm: Algorithm, key: Data) -> Data {
let signature = UnsafeMutablePointer<CUnsignedChar>.allocate(capacity: algorithm.digestLength)
data.withUnsafeBytes { dataBytes in
key.withUnsafeBytes { keyBytes in
CCHmac(algorithm.algorithm, keyBytes, key.count, dataBytes, data.count, signature)
}
}
return Data(bytes: signature, count: algorithm.digestLength)
}
This is guide for authenticated call HTTPS Header:
API-Key = API key
API-Sign = Message signature using HMAC-SHA512 of (URI path + SHA256(nonce + POST data)) and base64 decoded secret API key
This is guide for authenticated call POST Data:
nonce = always increasing unsigned 64 bit integer
otp = two-factor password (if two-factor enabled, otherwise not required)
For the API-Key you use krakenUtils.publicKey. The name suggests you use some public key (do not know where you got it)
However this should be your personal API-Key. You can get it at the kraken site (login with your account) and create an API key. You also get your API-code here. They go together as a pair
Although this is an old question, many users (including myself) who have attempted to use Kraken’s API have encountered and reported similar problems (INVALID KEY). Recently I reported the issue I was having to a Kraken rep…after an exchange with several reps it was discovered that there was a flaw in the posted Kraken example on their website. Here is some of the exchange:
...”In the method QueryPrivateEndpoint there is a line of code (should be line 256 from the file downloaded) that looks like this:
String apiEndpointFullURL = baseDomain + privatePath + endPointName + "?" + inputParameters;
It needs to be modified to look like this:
String apiEndpointFullURL = baseDomain + privatePath + endPointName;
After you make that code change, the Invalid Key error should go away.
…….
Thank you for your gratitude and pointing out the mistake to our attention.
We are pleased to know the issue has been resolved.
“……
They will post the update to their example code on their website.
Also, it’s worth noting that an improper/inconsistent ORDER of the parameters in a call that has parameters associated with it can cause an INVALID KEY error.

Unable to query PG database using koa-pg middleware on Koa on localhost

In the past I've been able to connect to a postgres db using koa-pg middleware connected to a database hosted on Heroku, but I'm having problems connecting to a locally-hosted database.
Specifically, the error I have is TypeError: Cannot read property 'client' of undefined.
The following is my setup on the single-file app:
const koa = require('koa');
let route = require('koa-route'); // For calling specific routes
let request = require('koa-request'); // For RESTful requests
let paramify = require('koa-params');
var koaPg = require('koa-pg');
let pg = require('pg'); // .native;
let cors = require('koa-cors');
let parser = require('xml2js').parseString;
// pg.defaults.ssl = true;
route = paramify(route);
let param = route.param;
let get = route.get;
let app = koa();
let appPort = (process.env.PORT || 3000)
app.use(cors());
app.use(koaPg('postgres://localhost:5432/ttc_clustering_dev'));
And the following is the route where the issue lies:
app.use(route.get('/initialDefaultRouteQuery', function *() {
let options = {
url: 'http://webservices.nextbus.com/service/publicXMLFeed?command=vehicleLocations&a=ttc&r=60'
}
let xmlResponse = yield request(options)
let jsResponse = ''
parser(xmlResponse.body, function(err,result){
//Extract the value from the data element
jsResponse = result
if (err !== null) {
console.log(`Error: ${err}`)
} else {
console.log('Success in parsing from XML to JSON')
}
});
let i = 0
while (i < jsResponse.body.vehicle.length) {
let query_content = `INSERT INTO temp_records (route_id, bus_id, capture_time, geometry) VALUES ('60', '${jsResponse.body.vehicle[i].$.id}', ${Date.now() - (jsResponse.body.vehicle[i].$.secsSinceReport * 1000)}, ST_GeomFromText('POINT(${jsResponse.body.vehicle[i].$.lng} ${jsResponse.body.vehicle[i].$.lat})'))`
let result = yield pg.db.client.query_(query_content)
console.log('result:' + result)
i += 1;
}
this.body = 'Finished!'
}));
It appears I've used the proper setup according to the docs, but there's likely something I'm missing here. Does anyone else see where I'm falling flat?
The full file can be found here: https://github.com/brianbancroft/ttc-clustering/blob/add-records-to-db/server/app.js
Due to the docs it should be:
let result = yield this.pg.db.client.query_(query_content)
instead of
let result = yield pg.db.client.query_(query_content)
So the this. is missing.
And reviewing your code, you are explicitly requiring pg, so your code is calling that one instead the one from koa-pg. Therefore pg.db seems not to be defined. Makes sense?

Cloudant function-clause error at HTTP GET request

This is my first question here and I have not much experience in coding so please bear with me. Thanks!
I defined some documents in my Bluemix Cloudant account with different cars which have different characteristics. I want to get one entry from an IOS Swift front-end App.
This is an example query url:
https://$ACCOUNT-bluemix.cloudant.com/cars/_design/car_index/_search/car_index_name?q=size:small
Now the problem: If I use this url in a browser I get the correct results in JSON format back without any error. But if the app makes the request a function-clause error is logged while the request itself seems to be successful.
I read that a function_clause error is caused by some bug in the Javascript Cloudant uses for indexing the documents. The Javascript I'm using is exactely the same as Cloudant states it in the tutorials.
Has anyone an idea why it works in the browser but not in the App?
Thank you very much for any help!
Here is all the code:
This is the method I use in swift to make the request:
func databaseRequest(size: String, interior: String, fuel: String) {
let baseURL = "https://$ACCOUNT-bluemix.cloudant.com/cars/_design/car_index/_search/car_index_name?q="
let queryURL = "size:\(size)"
let completeURL: String = baseURL + queryURL
let completeURLModified = completeURL.addingPercentEncoding(withAllowedCharacters: NSCharacterSet.urlQueryAllowed)
let requestURL = URL(string: completeURLModified!)
var request = URLRequest(url: requestURL!)
request.httpMethod = "GET"
request.setValue("Basic \(credentials)", forHTTPHeaderField: "Authorization")
let task = URLSession.shared.dataTask(with: request){data, response, error in
guard error == nil else{
print("There was an error:", error as Any)
return
}
guard data == data else{
print("Data is empty")
return
}
let jsonResponse = try! JSONSerialization.jsonObject(with: data!, options: [])
print("This is JSON Response", jsonResponse)
}; task.resume()
}
This is the response from the JSON answer:
This is JSON Response {
error = "unknown_error";
reason = "function_clause";
ref = 1944801346;
}
The rest of log from http headers if this is helpful:
Optional(<NSHTTPURLResponse: 0x6080000349c0> { URL: https://$ACCOUNT-bluemix.cloudant.com/cars/_design/car_index/_search/car_index_name?q=size:small } { status code: 500, headers {
"Cache-Control" = "must-revalidate";
"Content-Length" = 70;
"Content-Type" = "application/json";
Date = "Thu, 24 Nov 2016 04:41:03 GMT";
Server = "CouchDB/2.0.0 (Erlang OTP/17)";
"Strict-Transport-Security" = "max-age=31536000";
Via = "1.1 lb1.bm-cc-dal-01 (Glum/1.31.3)";
"X-Cloudant-Backend" = "bm-cc-dal-01";
"X-Content-Type-Options" = nosniff;
"X-Couch-Request-ID" = 51e5e0b5e1;
"X-Couch-Stack-Hash" = 1944801346;
"X-CouchDB-Body-Time" = 0;
Last but not least the Javascript file I use as Index in the design document in Cloudant:
function (doc) {
index("name", doc.name, {"store": true});
if (doc.fuel){ index("fuel", doc.fuel, {"store": true});}
if (doc.interior){ index("interior", doc.interior, {"store": true});}
if (doc.size){index("size", doc.size, {"store": true});
}}
I think this error is due to cloudant trying to decode whatever you passed as \(credentials) as a base64 encoded string. If \(credentials) is not a valid base64 encoded string (e.g. contains characters other than a-z, A-Z, 0-9, +, / and =), then my guess is that cloudant's base64 decoding function fails with the above error.
You need to make sure that \(credentials) is the string <your_username>:<your_password> encoded correctly. E.g. if your username is john and your password is doe, then \(credentials) should be am9objpkb2U=.

xcode error 'consecutive statements on a line must be separated by' when creating endpoint URL for REST API datatask

I am a beginner, trying to code a POST datarequest to post a vote to the 'rating' field of a Drupalnode (so that users can rate movies). I have followed online guides, carefully copying the syntax, but in Xcode am receiving this error for for this line:
let movieEndpoint: String = https://www.examplesitename.com/film1
The red error message is "consecutive statements on a line must be separated by a ';'
The error highlights the ':' after https, and suggests "fix it" with an ';' but changing it to https;www.examplesitename.com/film1 then brings up another red error 'expected expression' (and doesn't seem correct as it is a URL)
For context, below is my code, (which I hope will work to post my data request but haven't been able to check yet)
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: config)
let movieEndpoint: String = https://www.sitename.com/film1
guard let movieURL = NSURL(string: movieEndpoint) else {
print("Error: cannot create URL")
return
}
let movieUrlRequest = NSMutableURLRequest(URL: movieURL)
movieUrlRequest.HTTPMethod = "POST"
let task = session.dataTaskWithRequest(movieUrlRequest, completionHandler:{ _, _, _ in })
let newRating = ["rating": 50, "userId": 1,]
let jsonRating: NSData
do {
jsonRating = try NSJSONSerialization.dataWithJSONObject(newRating, options: [])
movieUrlRequest.HTTPBody = jsonRating
} catch {
print("Error: cannot create JSON from todo")
return
}
movieUrlRequest.HTTPBody = jsonRating
task.resume()
}
Thank you for any help you can give me.
The proper way to declare a String in Swift is to add " " around the string.
Fix your code like this:
let movieEndpoint: String = "https://www.sitename.com/film1"