Reputation: 1638
I'm trying to create an iOS app that uses OAuth2 authentication using the native iOS NSURLSession
URL loading classes. I gain an access token fine using the directions here:
I subsequently launch the application and run a search query
https://www.freesound.org/apiv2/search/text/?query=snare
The request header fields looks like this (note my access token is not expired and I have confirmed it is the same as I received from performing the steps above)
{
"Authorization: Bearer" = MY_ACCESS_TOKEN;
}
This fails with:
{"detail": "Authentication credentials were not provided."}
The response headers look like this:
{
Allow = "GET, HEAD, OPTIONS";
Connection = "keep-alive";
"Content-Type" = "application/json";
Date = "Sat, 31 Jan 2015 13:56:32 GMT";
Server = "nginx/1.2.1";
"Transfer-Encoding" = Identity;
Vary = "Accept, Cookie";
"Www-Authenticate" = "Bearer realm=\"api\"";
}
The funny thing is that this does not always happen. If I repeat this entire process a number of times, deleting the app in between, it will eventually work. Once it works, it will continue to work while I'm developing. Sometimes then when I come back to it, say the next day, it stops working and I need to repeat this deleting and re-installing routine to get it back working again!
There's an authentication challenge delegate method on NSURLSession that will get called if implemented. It's a 'server trust' challenge. Could this be something to do with it? Would you even expect an authentication challenge of this nature? There's nothing mentioned about it in the docs alluded to above.
Any help would be much appreciated.
EDIT
This is how the search text ("snare") GET call is made.
I basically pass in an NSMutableURLRequest
with the URL set to the above (https://www.freesound.org/apiv2/search/text/?query=snare
). useAccessToken
is set to YES
.
- (void)makeRequest:(NSMutableURLRequest *)request useAccessToken:(BOOL)useAccessToken completion:(CompletionBlock)completion {
NSAssert(completion, @"No completion block.");
if (useAccessToken) {
NSString *accessToken = [[ODMFreesoundTokenCache sharedCache] accessToken];
NSAssert(accessToken.length, @"No access token.");
[request addValue:accessToken forHTTPHeaderField:@"Authorization: Bearer"];
}
NSLog(@"Making request: %@ \n\nWith access token: %@", request, [[ODMFreesoundTokenCache sharedCache] accessToken]);
NSURLSessionDataTask *task = [self.session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSInteger code = [(NSHTTPURLResponse *)response statusCode];
if (code == 200) {
if (!error) {
id json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSLog(@"json: %@", json);
completion(json, error);
}
else {
completion(nil, error);
}
}
else {
NSString *reason = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSError *error = [NSError errorWithDomain:@"Request Error" code:code userInfo: reason ? @{NSLocalizedDescriptionKey : reason} : nil];
NSLog(@"error: %@", error);
completion(nil, error);
}
}];
[task resume];
}
Upvotes: 1
Views: 332
Reputation: 14212
The 2 flows for authentication described in the doc are not "safe" for a device. Using API keys would require the secret to be stored in the device.
The OAuth2 flow they support (authorization_code) requires a server to server call to exchange a code for the actual token (This step: http://www.freesound.org/docs/api/authentication.html#step-3). This call requires another credential (the client_secret
that you probably should not store in the device either.
You need a server in between that negotiates this for you. Or a server that translates the code flow
into token
one. (Illustrated here: https://auth0.com/docs/protocols#5).
Upvotes: 1