title: FatSecret API "invalid signature"
body: <p>Using this <a href="https://github.com/mysterioustrousers/FatSecretKit" rel="nofollow noreferrer">repository</a> I was not able to make the queries work when <code>oauth_token</code> must be provided. I always get invalid signature. Tried a lot of solutions and tweaks in the code, nothing worked. Please help.</p>
  
  <p>This is the code from the git mentioned:</p>
  
  <pre><code>NSString *OAuthorizationHeader(NSURL *url, NSString *method, NSData *body, NSString *_oAuthConsumerKey, NSString *_oAuthConsumerSecret, NSString *_oAuthToken, NSString *_oAuthTokenSecret)
  {
      NSString *_oAuthNonce = [NSString ab_GUID];
      NSString *_oAuthTimestamp = [NSString stringWithFormat:@"%d", (int)[[NSDate date] timeIntervalSince1970]];
      NSString *_oAuthSignatureMethod = @"HMAC-SHA1";
      NSString *_oAuthVersion = @"1.0";
  
      NSMutableDictionary *oAuthAuthorizationParameters = [NSMutableDictionary dictionary];
      [oAuthAuthorizationParameters setObject:_oAuthNonce forKey:@"oauth_nonce"];
      [oAuthAuthorizationParameters setObject:_oAuthTimestamp forKey:@"oauth_timestamp"];
      [oAuthAuthorizationParameters setObject:_oAuthSignatureMethod forKey:@"oauth_signature_method"];
      [oAuthAuthorizationParameters setObject:_oAuthVersion forKey:@"oauth_version"];
      [oAuthAuthorizationParameters setObject:_oAuthConsumerKey forKey:@"oauth_consumer_key"];
      if(_oAuthToken)
          [oAuthAuthorizationParameters setObject:_oAuthToken forKey:@"oauth_token"];
  
      // get query and body parameters
      NSDictionary *additionalQueryParameters = [NSURL ab_parseURLQueryString:[url query]];
      NSDictionary *additionalBodyParameters = nil;
      if(body) {
          NSString *string = [[NSString alloc] initWithData:body encoding:NSUTF8StringEncoding];
          if(string) {
              additionalBodyParameters = [NSURL ab_parseURLQueryString:string];
          }
      }
  
      // combine all parameters
      NSMutableDictionary *parameters = [oAuthAuthorizationParameters mutableCopy];
      if(additionalQueryParameters) [parameters addEntriesFromDictionary:additionalQueryParameters];
      if(additionalBodyParameters) [parameters addEntriesFromDictionary:additionalBodyParameters];
  
      // -&gt; UTF-8 -&gt; RFC3986
      NSMutableDictionary *encodedParameters = [NSMutableDictionary dictionary];
      for(NSString *key in parameters) {
          NSString *value = [parameters objectForKey:key];
          [encodedParameters setObject:[value ab_RFC3986EncodedString] forKey:[key ab_RFC3986EncodedString]];
      }
  
      NSArray *sortedKeys = [[encodedParameters allKeys] sortedArrayUsingFunction:SortParameter context:(__bridge void *)(encodedParameters)];
  
      NSMutableArray *parameterArray = [NSMutableArray array];
      for(NSString *key in sortedKeys) {
          [parameterArray addObject:[NSString stringWithFormat:@"%@=%@", key, [encodedParameters objectForKey:key]]];
      }
      NSString *normalizedParameterString = [parameterArray componentsJoinedByString:@"&amp;"];
  
      NSLog(@"normalizedParameters: %@", normalizedParameterString);
  
      NSString *normalizedURLString;
      if ([url port] == nil) {
          normalizedURLString = [NSString stringWithFormat:@"%@://%@%@", [url scheme], [url host], [url path]];
      } else {
          normalizedURLString = [NSString stringWithFormat:@"%@://%@:%@%@", [url scheme], [url host], [url port], [url path]];
      }
  
      NSString *signatureBaseString = [NSString stringWithFormat:@"%@&amp;%@&amp;%@",
                                       [method ab_RFC3986EncodedString],
                                       [normalizedURLString ab_RFC3986EncodedString],
                                       [normalizedParameterString ab_RFC3986EncodedString]];
  
      NSLog(@"signature base: %@", signatureBaseString);
  
      NSString *key = [NSString stringWithFormat:@"%@&amp;%@&amp;",
                       [_oAuthConsumerSecret ab_RFC3986EncodedString],
                       [_oAuthTokenSecret ab_RFC3986EncodedString]];
  
      NSLog(@"key codes: %@", key);
  
      NSData *signature = HMAC_SHA1(signatureBaseString, key);
      NSString *base64Signature = [signature base64EncodedString];
  
      // PARKER CHANGE: changed oAuthAuthorizationParameters to parameters
      NSMutableDictionary *authorizationHeaderDictionary = [parameters mutableCopy];
      [authorizationHeaderDictionary setObject:base64Signature forKey:@"oauth_signature"];
  
      NSMutableArray *authorizationHeaderItems = [NSMutableArray array];
      for(NSString *key in authorizationHeaderDictionary) {
          NSString *value = [authorizationHeaderDictionary objectForKey:key];
  
          NSLog(@"KEY: %@", key);
          NSLog(@"VALUE: %@", value);
          // PARKER CHANGE: removed quotes that surrounded each value
          [authorizationHeaderItems addObject:[NSString stringWithFormat:@"%@=%@",
                                               [key ab_RFC3986EncodedString],
                                               [value ab_RFC3986EncodedString]]];
      }
  
      // PARKER CHANGE: changed concatentation string from ", " to "&amp;"
      NSString *authorizationHeaderString = [authorizationHeaderItems componentsJoinedByString:@"&amp;"];
  //  authorizationHeaderString = [NSString stringWithFormat:@"OAuth %@", authorizationHeaderString];
  
      NSLog(@"final: %@", authorizationHeaderString);
  
      return authorizationHeaderString;
  }
  </code></pre>
  
  <p>And this is how I'm calling it:</p>
  
  <pre><code>- (void) makeUserRequestWithMethod:(NSString *)method
                      parameters:(NSDictionary *)params
                      completion:(void (^)(NSDictionary *data))completionBlock {
  
      NSLog(@"%s", __func__);
  
      NSMutableDictionary *parameters = [params mutableCopy];
      [parameters addEntriesFromDictionary:[self defaultParameters]];
      [parameters addEntriesFromDictionary:@{ @"method" : method }];
  
      NSString *queryString = [self queryStringFromDictionary:parameters];
      NSData *data          = [NSData dataWithBytes:[queryString UTF8String] length:queryString.length];
      NSString *authHeader  = OAuthorizationHeader([NSURL URLWithString:FAT_SECRET_API_ENDPOINT],
                                                   @"POST",
                                                   data,
                                                   _oauthConsumerKey,
                                                   _oauthConsumerSecret,
                                                   _oAuthToken,
                                                   _oAuthTokenSecret
                                                   );
  
      NSLog(@"header: %@", authHeader);
  
      NSURL *url = [NSURL URLWithString:[FAT_SECRET_API_ENDPOINT stringByAppendingFormat:@"?%@", authHeader]];
      [[[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
          if (data) {
              id JSON = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
              completionBlock(JSON);
          } else {
              completionBlock(nil);
          }
      }] resume];
  }
  </code></pre>