Spotify request web api removing unauthenticated calls - objective-c

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];

Related

Instagram API giving "Invalid platform app" error when I am trying to fetch the access token

I am trying to fetch the access token using this API: https://api.instagram.com/oauth/access_token. I have made sure to use the instagram app ID only and have also taken care of the content type to be "x-www-form-urlencoded" as suggested in the following answers: Authenticate the Test User { "error_type": "OAuthException", "code": 400, "error_message": "Invalid platform app" }. The API works perfectly fine in postman though but gives the following error response through my code:
{"error_type": "OAuthException", "code": 400, "error_message": "Invalid platform app"}
Here is my peice of code:
-(void)fetchAccessTokenForInsta{
NSString *targetUrl = [NSString stringWithFormat:#"%#", #"https://api.instagram.com/oauth/access_token"];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
NSDictionary *tmp = #{#"client_id":#"126.....", #"client_secret":#"c79c.....", #"grant_type":#"authorization_code", #"redirect_uri":#"https://firebase.google.com/", #"code":_codeStr};
NSError *error;
NSData *postData = [NSJSONSerialization dataWithJSONObject:tmp options:0 error:&error];
[request setHTTPBody:postData];
[request setHTTPMethod:#"POST"];
[request setURL:[NSURL URLWithString:targetUrl]];
NSDictionary *headers = #{#"Content-Type": #"application/x-www-form-urlencoded" };
[request setAllHTTPHeaderFields:headers];
[[[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];
}
Where _codeStr is the string after removing # from the code received in the earlier step. Any help is appreciated.
The only solution that worked so far is that you ask your server or backend team to develop an API for you that fetches the access token using the instagram API and gives it to you as a response.

Soundcloud OAuth request returns always invalid client

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 :)

.NET Web Api Token Authentication Rest Service "Get" Method in Objective-C

I'm trying to access the following URL:
http://appointmentreminder4.azurewebsites.net/Profile
This URL uses a "Get" method, and is supposed to provide JSON results. Before accessing the URL, you need to login using your Email Address and Password. After logging in successfully, the Web API issues a token. This token is used in ALL communications going forward.
I am currently unable to retrieve the token in Objective-C. I have attempted to google this problem, but I cannot figure out:
1) How to get the token
2) How to get the JSON output from the URL.
Here is the code I have written so far that returns neither the JSON, nor the token:
NSDictionary *postDict = [[NSDictionary alloc] initWithObjectsAndKeys:
#"Email Adress", #"MyEmailAddress",
#"Password", #"MyPassword",
nil];
NSError *error = nil;
NSData* jsonData = [NSJSONSerialization dataWithJSONObject:postDict options:kNilOptions error:&error];
NSURLResponse *response;
NSData *localData = nil;
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"http://appointmentreminder4.azurewebsites.net/home"]];
[request setHTTPMethod:#"POST"];
if (error == nil)
{
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setHTTPBody:jsonData];
// Send the request and get the response
localData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSString *result = [[NSString alloc] initWithData:localData encoding:NSASCIIStringEncoding];
NSLog(#"Post result : %#", result);
}
If the above link fails, use this link to navigate to the specific page:
http://appointmentreminder4.azurewebsites.net/home

Objective C Update RESTful Webservice

I have a web service that allows me to update records on in our database.
The columns in the table are as follows:
allowsActions
assetID
inventoryObjectID
objectDescription
quantity
retired
serialNumber
action
I'm using the following to GET data from the webservice.
NSString *urlString = [NSString stringWithFormat:#"%#", inventoryAndActionsWebservice];
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:#"GET"];
Then shoving into a dictionary like so:
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError)
{
if (data.length > 0 && connectionError == nil)
{
NSLog(#"WE HAS THE DATAS");
NSDictionary *inventory = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL];
// Then storing the values in CoreData here
}
}
What would be the syntax for updating the webservice? It expects an object in the body of the service call (POST).
NSMutableURLRequest let's you setHTTPBody: and setHTTPMethod:.#"POST"is the way to do a post. Most services need to know the body length and encoding set in headers. (seeaddValue:forHTTPHeaderField:`) for that.
The only reason this topic is tricky is because the developer is forced to grapple with two problems at once: what constitutes a valid request for my server, and (2) how do I form that request with iOS? Part (2) is actually pretty easy once you get a valid request.
The best way to proceed is to get an example working using curl (or something equivalent). Then move on to producing that request in iOS. If you have trouble, ask a question here of the form: "I know my server needs X, here's my code to produce X, but I'm getting this error Y".
So the syntax that I was looking for was ultimately this:
NSString *jSONString = [NSString stringWithFormat:#"{\"MediaInventoryObjectsId\":%d,\"AssetId\":%d,\"Quantity\":%d,\"SerialNumber\":\"%#\",\"Description\":\"%#\",\"AllowActions\":%d,\"Retired\":%d}",inventoryObjectId, assetID, quantity, serialNumber, description, allowActions, retired];
// Convert jSON string to data
NSData *putData = [jSONString dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
// Instantiate a url request
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
// Set the request url format
[request setURL:[NSURL URLWithString:[NSString stringWithFormat:#"%#/%d", inventoryAndActionsWebservice, inventoryObjectId]]];
[request setHTTPMethod:#"PUT"];
[request setHTTPBody:putData];
[request setValue:#"application/json" forHTTPHeaderField:#"content-type"];
// Send data to the webservice
NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];

How to get a new access token after expiration using OAuth 2.0 along with Youtube API in iOS application

I am using the Youtube Api in my iPad application. i managed to get authenticated and get the access token using the OAuth 2.0.
my problem is that the token expires after one hour and i don't know how to get a new one using the refresh-token without going through the authentication process again.
i am using XCode 4.5 and iOS 5.1 & 6
According do the documentation
If your application obtains a refresh token during the authorization process, then you will need to periodically use that token to obtain a new, valid access token. Server-side web applications, installed applications, and devices all obtain refresh tokens.
So if you already have your refresh token, you just need to perform a POST request configured as follows
POST /o/oauth2/token HTTP/1.1
Host: accounts.google.com
Content-Type: application/x-www-form-urlencoded
client_id=21302922996.apps.googleusercontent.com&
client_secret=<YOUR CLIENT SECRET>
refresh_token=<YOUR REFRESH TOKEN>
grant_type=refresh_token
and you'll get back a response like
{
"access_token":<A NEW ACCESS TOKEN>,
"expires_in":<AN EXPIRING TIME>,
"token_type":"Bearer"
}
Here is the full code to refresh the accessToken using AFNetworking to make the request:
NSString *refreshToken = <YOUR_REFRESH_TOKEN>;
NSString *post = [NSString stringWithFormat:#"client_secret=%#&grant_type=refresh_token&refresh_token=%#&client_id=%#",kYouTubeClientSecret,refreshToken,kYouTubeClientID];
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:#"%d", [postData length]];
NSURL *url = [NSURL URLWithString:#"https://accounts.google.com/o/oauth2/token"];
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:postData];
AFHTTPRequestOperation *httpRequest = [httpClient HTTPRequestOperationWithRequest:request
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:responseObject options:kNilOptions error:nil];
NSString *newAccessToken = json[#"access_token"];
NSLog(#"received new accessToken = %#",newAccessToken);
// store accessToken here
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"error refreshing token: %#",[error localizedDescription]);
}];
[httpClient enqueueHTTPRequestOperation:httpRequest];