Soundcloud OAuth request returns always invalid client - objective-c

Here is my objective-c code to obtain access token from SoundCloud:
- (void) authoriseSoundcloud {
NSString *apiUrl = #"https://api.soundcloud.com/oauth2/token";
NSMutableURLRequest * urlRequest = [NSMutableURLRequest requestWithURL:[ NSURL URLWithString:apiUrl]];
NSString * params = [NSString stringWithFormat:#"client_id=%#&client_secret=%#grant_type=password&username=%#&password=%#",client,secretKey,fldUsername.text,fldPassword.text ];
[urlRequest setHTTPMethod:#"POST"];
[urlRequest setHTTPBody:[params dataUsingEncoding:NSUTF8StringEncoding]];
NSURLSession *defaultSession = [NSURLSession sharedSession];
NSURLSessionDataTask * dataTask =[defaultSession dataTaskWithRequest:urlRequest
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSLog(#"Response:%# %#\n", response, error);
if(error == nil)
{
NSString * text = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
NSLog(#"Data = %#",text);
}
}];
[dataTask resume];
}
However, I always get the result 401- {"error":"invalid_client"}.
However, that client ID works perfectly with those requests, that does not need authorization and I have checked multiple times, that my client ID and secret are correct.
As there is not much samples for iOS to use those parameters in HTTP post body, I assume that maybe my parameters list is incorrect. Any ideas from Soundcloud engineers?

Just a typo mistake, simply add "&" between "client_secret=%#" and "grant_type", like this :
NSString * params = [NSString stringWithFormat:#"client_id=%#&client_secret=%#&grant_type=password&username=%#&password=%#",client,secretKey,fldUsername.text,fldPassword.text ];
Work like a charm :)

Related

I am trying to sent a record to my web server but the web server never gets hit

I have this little project
I have some recipes that I want to share with my iPhone.
the database has this fields
string id
string name
string recipe_text
byte[] image
so when I change it on the iPhone I call this function
+(void) sendRecipe:(BFRecipe *) recipe
{
NSString * imageStringData = #"";
if(recipe.recipeImage != nil)
imageStringData = [UIImagePNGRepresentation(recipe.recipeImage) base64Encoding];
NSDictionary * jsonRecord = [NSDictionary dictionaryWithObjectsAndKeys:recipe.recipeId,#"RecipeId",recipe.name,#"Name" ,recipe.recipeText,#"RecipeText",imageStringData,#"Item" , nil];
NSString *urlString = [NSString stringWithFormat:#"%#/%#",[[NSUserDefaults standardUserDefaults ] objectForKey:#"Host"],#"UpdateRecipeItem"];
NSMutableURLRequest *request = [NSMutableURLRequest new];
request.HTTPMethod = #"POST";
NSData *jsonBodyData = [NSJSONSerialization dataWithJSONObject:jsonRecord options:kNilOptions error:nil];
[request setURL:[NSURL URLWithString:urlString]];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setHTTPBody:jsonBodyData];
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:config
delegate:nil
delegateQueue:[NSOperationQueue mainQueue]];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request
completionHandler:^(NSData * _Nullable data,
NSURLResponse * _Nullable response,
NSError * _Nullable error) {
NSHTTPURLResponse *asHTTPResponse = (NSHTTPURLResponse *) response;
// set a breakpoint on the last NSLog and investigate the response in the debugger
// if you get data, you can inspect that, too. If it's JSON, do one of these:
}];
[task resume];
}
My MVC server has a function like this but it never gets called Why ?
public void UpdateRecipeImage(string id)
{
recipe_item item = Model.recipe_item.FirstOrDefault(ri => ri.recipe_id == new Guid(id));
....
.....
....
}
I see problem with your calling part in objective-c code
NSString *urlString = [NSString stringWithFormat:#"%#/%#",[[NSUserDefaults standardUserDefaults ] objectForKey:#"Host"],#"UpdateRecipeItem"];
Here you calling #"UpdateRecipeItem" but on mvc api you have UpdateRecipeImage(string id)
so problem is with your naming. Try to call proper api name that is UpdateRecipeImage(string id)
-OR-
If calling #"UpdateRecipeItem" is your attention, then post your mvc api code here with parameters. I am sure you're missing something for you api endpoint.
UPDATE: Based on your code shared in comment, try adding [FromBody] in you api method. Look at code below:
[HttpPost]
public void UpdateRecipeItem([FromBody] UpdateRecipeItem recipeItem)
{
try
{
recipe_item item = Model.recipe_item.FirstOrDefault(ri => ri.recipe_id == new Guid(recipeItem.RecipeId));
Hope you understand. Happy Coding!

Spotify request web api removing unauthenticated calls

After removing unauthenticated calls to the Web API I have problem with getting a token. I have found on developer.spotify that I need make an authorization code flow. The biggest problem is:
It provides an access token that can be refreshed. Since the token
exchange involves sending your secret key, this should happen on a
secure location, like a backend service, not from a client like a
browser or mobile apps.
Is there some another ways to use web api like "get track" or "search an item" without an authorization code flow?
Yes, you need to read about Client Credentials Flow.
The method makes it possible to authenticate your requests to the
Spotify Web API and to obtain a higher rate limit than you would get
without authentication.
You need to use your client_id and client_secret that you get after registration an app on developer.spotify.
The request will include parameter as grant_type in the request body with value "client_credentials" and a header must contain Authorization.
Required. Base 64 encoded string that contains the client ID and
client secret key. The field must have the format: Authorization:
Basic base64 encoded client_id:client_secret
All this information you can find in Web API Authorization Guide
An example how to get the token:
- (void)spotifyToken {
NSString *body = #"grant_type=client_credentials";
NSData *postData = [body dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *prepareHeader = [NSString stringWithFormat:#"%#:%#",clientId, clientSecret];
NSData *data = [prepareHeader dataUsingEncoding:NSUTF8StringEncoding];
NSString *base64encoded = [data base64EncodedStringWithOptions:0];
NSString *header = [NSString stringWithFormat:#"Basic %#", base64encoded];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc]init];
[request setURL:[NSURL URLWithString:#"https://accounts.spotify.com/api/token"]];
[request setHTTPBody:postData];
[request setHTTPMethod:#"POST"];
[request setValue:header forHTTPHeaderField:#"Authorization"];
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
[[session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (!error) {
dispatch_async(dispatch_get_main_queue(), ^{
// saving somewhere token for further using
});
}
}] resume];
}
Then you make almost the same request for for search an item. But instead POST you send GET with your token in header. It looks like:
NSString *token = [tokenData objectForKey:#"access_token"];
NSString *tokenType = [tokenData objectForKey:#"token_type"];
NSString *header = [NSString stringWithFormat:#"%# %#", tokenType, token];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"https://api.spotify.com/v1/search?%#",trackId]];
[request setValue:header forHTTPHeaderField:#"Authorization"];
[request setURL:url];
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
[[session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (!error) {
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
// JSON with song is here
}
}] resume];

Waiting or not exiting the code block in getting json

I am using GET method on Json. The GET method is inside a for loop, and the issue is it is not finishing the task or not getting the result. Instead the loop increments. I've placed a breakpoint inside the block where I am setting the result data to a NSDictionary but it never goes there.
Is it possible for the GET method to be directly called. I mean the code will be read line by line. And it will not skip or wait for the json to finish processing?
Here's what I've done:
- (void)downloadJsonFeed
{
for(int i = 1;i < self.numberOfEpisodes;i++)
{
NSString *endPoint = [[[[baseJsonUrl stringByAppendingString:getEpisodes]stringByAppendingString:self.title]stringByAppendingString:#"&episodeNumber="]stringByAppendingString:[NSString stringWithFormat:#"%i",i]];
NSLog(#"End point %#",endPoint);
[JsonDownload getJson:token andEndpointString:endPoint WithHandler:^(__weak id result)
{
NSArray *episodeArray =result;
//will do some task here
}];
}
}
- (void)getJson:(NSString *)authData andEndpointString:(NSString *)urlString WithHandler:(void(^)(__weak id result))handler
{
NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: nil delegateQueue: [NSOperationQueue mainQueue]];
NSURL * url = [NSURL URLWithString:urlString];
NSMutableURLRequest * urlRequest = [NSMutableURLRequest requestWithURL:url];
//NSString *auth = [NSString stringWithFormat:#"Bearer {%#}", authData];
[urlRequest setValue:#"application/json" forHTTPHeaderField:#"Content-type"];
[urlRequest setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[urlRequest setValue:authData forHTTPHeaderField:#"Cookie"];
[urlRequest setHTTPMethod:#"GET"];
NSURLSessionDataTask * dataTask =[defaultSession dataTaskWithRequest:urlRequest
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if(error == nil)
{
id returnedObject = [NSJSONSerialization JSONObjectWithData: data options: NSJSONReadingMutableLeaves error:nil];
handler(returnedObject);
}
else{
NSLog(#"error %#",error);
}
}];
[dataTask resume];
}
I've placed a break point in this line NSArray *episodeArray =result; and it never goes there. But when I put the break point on [JsonDownload getJson:token andEndpointString:endPoint WithHandler:^(__weak id result) line it is responding
And on the commented line //will do some task here I need to a task there before getting another json again. But I can't cause it never go inside the code block
Fixed the issue by replacing white space characters in my endPoint by %20

Server response "java.lang.Integer cannot be cast to java.lang.Double"

I'm trying to make post request using NSURLSession. I need to send data which includes double values. I used NSNumber to store double values inside NSDictionary. I am posting data like this:
-(void)sortJobsWithLat:(float)lat longt:(float)longt distance:(float)distance budget:(NSInteger)budget rating:(NSInteger)rating page:(NSUInteger)page {
NSError *error;
NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: nil delegateQueue: [NSOperationQueue mainQueue]];
NSURL * url = [NSURL URLWithString:[NSString stringWithFormat:#"%#%#",BaseURLJobs,SearchJobs]];
NSMutableURLRequest * urlRequest = [NSMutableURLRequest requestWithURL:url];
NSLog(#"url : %#", url);
NSDictionary *params=[[NSDictionary alloc]initWithObjectsAndKeys:[NSNumber numberWithDouble:lat] ,#"latitude",[NSNumber numberWithDouble:longt],#"longitude", [NSNumber numberWithDouble:distance],#"distance", [NSString stringWithFormat:#"%ld",(long)budget] ,#"budget", [NSString stringWithFormat:#"%ld",(long)rating],#"rating", [NSString stringWithFormat:#"%ld",page],#"pageNo",nil];
NSData* jsonData = [NSJSONSerialization dataWithJSONObject:params options:kNilOptions error:&error];
NSLog(#"params : %#",params);
[urlRequest addValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[urlRequest addValue:#"application/json" forHTTPHeaderField:#"Accept"];
[urlRequest setHTTPMethod:#"POST"];
[urlRequest setHTTPBody:jsonData];
NSData *postData = [NSJSONSerialization dataWithJSONObject:params options:0 error:&error];
[urlRequest setHTTPBody:postData];
dataTask =[defaultSession dataTaskWithRequest:urlRequest
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if(error == nil)
{
NSError *jsonError;
NSDictionary *jsonObject = [NSJSONSerialization JSONObjectWithData:data
options:kNilOptions
error:&jsonError];
NSLog(#"json object : %#",jsonObject);
}
else{
[AppDel showAlertWithMessage:error.localizedDescription andTitle:nil];
}
}];
[dataTask resume];
}
When I print params using NSLog, It prints like this:
params : {
budget = 1000;
distance = 50;
latitude = "30.73979949951172";
longitude = "76.78269958496094";
pageNo = 0;
rating = 4;
}
Server is returning response like:
json object : {
error = "Internal Server Error";
exception = "java.lang.ClassCastException";
message = "java.lang.Integer cannot be cast to java.lang.Double";
path = "/jobs/searchJobs";
status = 500;
timestamp = 1471760398842;
}
This error is clearly showing server is not able to caste integer value to double.I'm getting this error due to distance parameter. I'm passing distance as double value then how server is finding it as integer value?
The problem is that those parameters are not recognized by the server. The server part works correctly because I've sent a POST using Swagger UI for Google Chrome and it worked perfectly.
I was getting this error because I was sending 50.0 as double value. Objective C converts it to integer automatically. So server was getting integer value and it was unable to cast this value. I have made changes on server to solve this error..

Simple objective-c GET request

Most of the information here refers to the abandoned ASIHTTPREQUEST project so forgive me for asking again.
Effectively, I need to swipe a magnetic strip and send the track 2 data to a webservice that returns "enrolled" or "notenrolled" (depending on the status of the card...)
So my data comes in simply as
NSData *data = [notification object];
And then I need to pass this to a url to the order of
http://example.com/CardSwipe.cfc?method=isenrolled&track2=data
And then just receive a response string...
I've searched a ton and there seems to be some conflicting answers as to whether this should be accomplished simply with AFNetworking, RESTkit, or with the native NSURL/NSMutableURLRequest protocols.
The options for performing HTTP requests in Objective-C can be a little intimidating. One solution that has worked well for me is to use NSMutableURLRequest. An example (using ARC, so YMMV) is:
- (NSString *) getDataFrom:(NSString *)url{
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setHTTPMethod:#"GET"];
[request setURL:[NSURL URLWithString:url]];
NSError *error = nil;
NSHTTPURLResponse *responseCode = nil;
NSData *oResponseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&responseCode error:&error];
if([responseCode statusCode] != 200){
NSLog(#"Error getting %#, HTTP status code %i", url, [responseCode statusCode]);
return nil;
}
return [[NSString alloc] initWithData:oResponseData encoding:NSUTF8StringEncoding];
}
Update:
Your question's title, and tagging say POST, but your example URL would indicate a GET request. In the case of a GET request, the above example is sufficient. For a POST, you'd change it up as follows:
- (NSString *) getDataFrom:(NSString *)url withBody:(NSData *)body{
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:body];
[request setValue:[NSString stringWithFormat:#"%d", [body length]] forHTTPHeaderField:#"Content-Length"];
[request setURL:[NSURL URLWithString:url]];
/* the same as above from here out */
}
Update for iOS 9:
So, [NSURLConnection sendSynchronousRequest] is deprecated starting from iOS 9. Here's how to do a GET request using NSURLSession starting from iOS 9
GET Request
// making a GET request to /init
NSString *targetUrl = [NSString stringWithFormat:#"%#/init", baseUrl];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setHTTPMethod:#"GET"];
[request setURL:[NSURL URLWithString:targetUrl]];
[[[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:
^(NSData * _Nullable data,
NSURLResponse * _Nullable response,
NSError * _Nullable error) {
NSString *myString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"Data received: %#", myString);
}] resume];
POST Request
// making a POST request to /init
NSString *targetUrl = [NSString stringWithFormat:#"%#/init", baseUrl];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
//Make an NSDictionary that would be converted to an NSData object sent over as JSON with the request body
NSDictionary *tmp = [[NSDictionary alloc] initWithObjectsAndKeys:
#"basic_attribution", #"scenario_type",
nil];
NSError *error;
NSData *postData = [NSJSONSerialization dataWithJSONObject:tmp options:0 error:&error];
[request setHTTPBody:postData];
[request setHTTPMethod:#"POST"];
[request setURL:[NSURL URLWithString:targetUrl]];
[[[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:
^(NSData * _Nullable data,
NSURLResponse * _Nullable response,
NSError * _Nullable error) {
NSString *responseStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"Data received: %#", responseStr);
}] resume];
Tested 100% working
Only for Objective C
-(void)fetchData
{
NSURLSessionConfiguration *defaultSessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration:defaultSessionConfiguration];
// Setup the request with URL
NSURL *url = [NSURL URLWithString:#"https://test.orgorg.net/ios/getStory.php?"];
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url];
// Convert POST string parameters to data using UTF8 Encoding
NSString *postParams = #"";
NSData *postData = [postParams dataUsingEncoding:NSUTF8StringEncoding];
// Convert POST string parameters to data using UTF8 Encoding
[urlRequest setHTTPMethod:#"POST"];
[urlRequest setHTTPBody:postData];
// Create dataTask
NSURLSessionDataTask *dataTask = [defaultSession dataTaskWithRequest:urlRequest completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSDictionary *results = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
//JSON Parsing....
NSString *message = results[#"Message"];
BOOL status = results[#"Status"];
if (status){
// Here you go for data....
}else{
UIAlertController *alert = [UIAlertController alertControllerWithTitle:#"App"
message:message
preferredStyle:UIAlertControllerStyleAlert]; // 1
UIAlertAction *firstAction = [UIAlertAction actionWithTitle:#"Ok"
style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
NSLog(#"You pressed button one");
}]; // 2
[alert addAction:firstAction]; // 4
[self presentViewController:alert animated:YES completion:nil];
}
}];
// Fire the request
[dataTask resume];
}
For Objective c :
-(void)loadData:(NSString*)url{
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:#"https://jsonplaceholder.typicode.com/posts"]];
[request setHTTPMethod:#"GET"];
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
[[session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSMutableArray *jsonArray = (NSMutableArray *)[NSJSONSerialization JSONObjectWithData:data options:NSASCIIStringEncoding error:&error];
if([self.delegate respondsToSelector:#selector(loadingData:)]){
[self.delegate loadingData:jsonArray];
}
}] resume];
}
Swift 5.5:
// MARK: - Posts
func getPosts(endPath : String, completion: #escaping ([Post]) -> ()) {
let urlPath = Constants.Network.BASE_URL + endPath
guard let url = URL(string: urlPath) else {
print("Invalid URL")
return
}
var request = URLRequest(url: url)
request.httpMethod = Constants.Network.HTTPS_METHOD
URLSession.shared.dataTask(with: request) { data, response, error in
if let data = data {
if let decodedResponse = try? JSONDecoder().decode([Post].self, from: data) {
DispatchQueue.main.async {
completion(decodedResponse)
}
return
}
}
print("Fetch failed: \(error?.localizedDescription ?? "Unknown error")")
}.resume()
}
**Simply Call and get your JSON Data.**
-(void)getJSONData
{
NSURL *url = [NSURL URLWithString:#"http://itunes.apple.com/us/rss/topaudiobooks/limit=10/json"];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *data = [session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSError *erro = nil;
if (data!=nil) {
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&erro ];
if (json.count > 0) {
for(int i = 0; i<10 ; i++){
[arr addObject:[[[json[#"feed"][#"entry"] objectAtIndex:i]valueForKeyPath:#"im:image"] objectAtIndex:0][#"label"]];
}
}
}
dispatch_sync(dispatch_get_main_queue(),^{
[table reloadData];
});
}];
[data resume];
}