Scott McKenzie
Scott McKenzie

Reputation: 16242

OAuth against LinkedIn API keeps returning a 401. What is causing this?

I'm using AFNetworking, AFOAuth1Client and AFLinkedInOAuth1Client to get the OAuth token from LinkedIn's API. This is all working well.

When I make a call using getPath to v1/people/~ I am receiving a 401, consistently.

If I push all the same values from my code into the LinkedIn console the generated link gives me the basic profile I am after.

What is causing the 401? I have a feeling it is either AFNetworking or my configuration of it.

Also, do you have any suggestions on how to diagnose the underlying issue?

Code below

+ (JJLinkedInClient *)sharedInstance {
    DEFINE_SHARED_INSTANCE_USING_BLOCK(^{
        return [[self alloc] init];
    });
}

- (id)init {
    
    if ( (self = [super init]) ) {
        _client = [[AFLinkedInOAuth1Client alloc] initWithBaseURL:[NSURL URLWithString:kJJLinkedInAPIBaseURLString]
                                                              key:@"XXXXXXXX"
                                                           secret:@"YYYYYYYY"];
        
//        [_client registerHTTPOperationClass:[AFJSONRequestOperation class]];
        [_client registerHTTPOperationClass:[AFHTTPRequestOperation class]];
//        [_client setDefaultHeader:@"Accept" value:@"application/json"];
    }
    
    return self;
}

- (void)authorize:(void(^)())success {
    
    __block JJLinkedInClient *weakSelf = self;
    
    [self.client authorizeUsingOAuthWithRequestTokenPath:@"uas/oauth/requestToken"
                                      userAuthorizationPath:@"uas/oauth/authorize"
                                                callbackURL:[NSURL URLWithString:@"XXXXXXX://linkedin-auth-success"]
                                            accessTokenPath:@"uas/oauth/accessToken"
                                               accessMethod:@"POST"
                                                    success:^(AFOAuth1Token *accessToken) {
                                                        NSLog(@"Success: %@", accessToken);
                                                        [weakSelf getProfile];
                                                        success();
                                                    } failure:^(NSError *error) {
                                                        NSLog(@"Error: %@", error);
                                                    }];
}

- (void)getProfile {
    
    [self.client getPath:@"v1/people/~"
              parameters:nil
                 success:^(AFHTTPRequestOperation *operation, id responseObject) {
                     NSLog(@"%@", responseObject);
                 }
                 failure:^(AFHTTPRequestOperation *operation, NSError *error) {
                     NSLog(@"%@", error);
                 }];    
}

Upvotes: 1

Views: 529

Answers (1)

pj4533
pj4533

Reputation: 1721

The problem is in the AFPercentEscapedQueryStringPairMemberFromStringWithEncoding function, inside AFOAuth1Client. It needs to not escape the tilde, and it needs to escape the comma.

Since this is a static function though, I don't think I can override it in AFLinkedInOAuth1Client. I'll follow up with @mattt and see what he says. For now you can change it to this, to get it working:

static NSString * AFPercentEscapedQueryStringPairMemberFromStringWithEncoding(NSString *string, NSStringEncoding encoding) {
    static NSString * const kAFCharactersToBeEscaped = @":/?&=;+!@#$(),";
    static NSString * const kAFCharactersToLeaveUnescaped = @"[].~";
//    static NSString * const kAFCharactersToBeEscaped = @":/?&=;+!@#$()~";
//    static NSString * const kAFCharactersToLeaveUnescaped = @"[].";

    return (__bridge_transfer  NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (__bridge CFStringRef)string, (__bridge CFStringRef)kAFCharactersToLeaveUnescaped, (__bridge CFStringRef)kAFCharactersToBeEscaped, CFStringConvertNSStringEncodingToEncoding(encoding));
}

Upvotes: 2

Related Questions