WunDaii
WunDaii

Reputation: 2312

OAuth2 to Authenticate API - Cannot Redirect Back to my App

I'm trying to use the Trakt API to get a list of TV shows and other data. However, I'm stuck on authenticating my app with Trakt. I have my API key, secret, and redirect URI, but am struggling on how to authorise my app. I've tried the following:

Method 1, using the sample code from Trakt:

-(void)authorisation{

    NSString *redirectURI = @"http://myappredirect://";
    NSString *clientID = @"MY_CLIENT_ID";
    NSString *clientSecret = @"MY_CLIENT_SECRET";
    NSString *username = @"USERNAME";
    NSString *authURL = [NSString stringWithFormat:@"https://trakt.tv/oauth/authorize?response_type=code&client_id=%@&redirect_uri=%@&state=state&username=%@", clientID, redirectURI, username];

    NSURL *URL = [NSURL URLWithString:authURL];

    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
    [request setHTTPMethod:@"GET"];

    [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];

    [[UIApplication sharedApplication] openURL:URL];

    NSURLSession *session = [NSURLSession sharedSession];
    NSURLSessionDataTask *task = [session dataTaskWithRequest:request
                                            completionHandler:
                                  ^(NSData *data, NSURLResponse *response, NSError *error) {

                                      if (error) {
                                          // Handle error...
                                          return;
                                      }

                                      if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
                                          NSLog(@"Response HTTP Status code: %ld\n", (long)[(NSHTTPURLResponse *)response statusCode]);
                                          NSLog(@"Response HTTP Headers:\n%@\n", [(NSHTTPURLResponse *)response allHeaderFields]);
                                      }

                                      NSString* body = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
                                      NSLog(@"Response Body:\n%@\n", body);
                                  }];
    [task resume];
}

This opens Safari on my iPhone, loads the web page successfully with Trakt asking to authorise my account for my app. I tap 'Authorize' and then Safari loads a URL 'myappredirect//?code=a_really_long_string_of_characters", but with an error

Safari cannot open the page because the server cannot be found.

When I enter myappredirect:// in Safari, my app opens, so I'm wondering if the URL that Safari loads is incorrect as it's missing a semi-colon before the double //?

So I tried adding a UIWebView to my app and load the URL in there. It loads the URL but this time after I tap 'Authorize', it doesn't change the webpage. The UIWebView delegate webViewDidStartLoad does tell me that it loads a page after I tap 'Authorize', but nothing changes on-screen.

Method 2, using OAuth2Client:

-(void)setupWebview{

    webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 300, 300)];
    webView.backgroundColor = [UIColor greenColor];
    webView.delegate = self;
    [self.view addSubview:webView];

}

-(void)webViewDidStartLoad:(UIWebView *)webView{
    NSLog(@"webViewDidStartLoad");
}

-(void)secondMethod{
    NSString *redirectURI = @"http://myappredirect://";
    NSString *clientID = @"MY_CLIENT_ID";
    NSString *clientSecret = @"MY_CLIENT_SECRET";
    NSString *username = @"USERNAME";
    NSString *authURL = [NSString stringWithFormat:@"https://api-v2launch.trakt.tv/oauth/authorize?response_type=code&client_id=%@&redirect_uri=%@&state=state&username=%@", clientID, redirectURI, username];
    NSString *tokenURL = @"https://api-v2launch.trakt.tv";

    [[NXOAuth2AccountStore sharedStore] setClientID:clientID
                                             secret:clientSecret
                                   authorizationURL:[NSURL URLWithString:authURL]
                                           tokenURL:[NSURL URLWithString:tokenURL]
                                        redirectURL:[NSURL URLWithString:redirectURI]
                                     forAccountType:@"Trakt"];

    [[NXOAuth2AccountStore sharedStore] requestAccessToAccountWithType:@"Trakt"
                                   withPreparedAuthorizationURLHandler:^(NSURL *preparedURL){
                                       // Open a web view or similar
                                       [webView loadRequest:[NSURLRequest requestWithURL:preparedURL]];
                                   }];
}

-(void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:YES];

    [[NSNotificationCenter defaultCenter] addObserverForName:NXOAuth2AccountStoreAccountsDidChangeNotification
                                                      object:[NXOAuth2AccountStore sharedStore]
                                                       queue:nil
                                                  usingBlock:^(NSNotification *aNotification){
                                                      // Update your UI
                                                      NSLog(@"Success");
                                                  }];

    [[NSNotificationCenter defaultCenter] addObserverForName:NXOAuth2AccountStoreDidFailToRequestAccessNotification
                                                      object:[NXOAuth2AccountStore sharedStore]
                                                       queue:nil
                                                  usingBlock:^(NSNotification *aNotification){
                                                      NSError *error = [aNotification.userInfo objectForKey:NXOAuth2AccountStoreErrorKey];
                                                      // Do something with the error
                                                      NSLog(@"Error");
                                                  }];
}

Here, I'm not sure what the token URL is. Again, my UIWebView loads the URL perfectly but after I press 'Authorize', it doesn't change its webpage. The delegate method webViewDidStartLoad does tell me that it loads another page, but nothing changes on-screen. Also, neither of the NXOAuth2 notifications are sent.

I'm new to OAuth2 and would really appreciate any help anybody may have to offer. I apologise if this is a silly question, I'm really struggling on what to do, and confused as to why Safari won't open my app after I've authorised Trakt.

Thanks.

Upvotes: 4

Views: 3069

Answers (3)

Arnaud
Arnaud

Reputation: 17737

Here's how I did it.

Step 1: Edit your Info.plist

You need to define a url scheme that will open your app instead of the browser, which is useful for the redirect at the end of the oauth process.

Let's call it yoururlscheme for the example, but you can pick whatever you want (eg: "yourappname" in lowercase, or even your bundle identifier "com.example.yourappname")

<key>CFBundleURLTypes</key>
<array>
    <dict>
        <key>CFBundleURLSchemes</key>
        <array>
            <string>yoururlscheme</string>
        </array>
    </dict>
</array>

Step 2: on trakt.tv

Step 3: your ViewController

import SafariServices

class YourViewController: UIViewController {

  var oauthSession: SFAuthenticationSession? = nil

  func signIn() {
    let clientId = "" // your client id
    let redirectUri = "yoururlscheme://oauth/token"
    let oauthURL = "https://trakt.tv/oauth/authorize?response_type=code&client_id=\(clientId)&redirect_uri=\(redirectUri)"
    oauthSession = SFAuthenticationSession(url: oauthURL, callbackURLScheme: redirectUri) { (url, error) in
        guard let url = url,
            let urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false),
            let queryItems = urlComponents.queryItems,
            let code = queryItems.first(where: {$0.name == "code"})?.value else {
            return
        }
        // Do whatever you want with the token now
        print("code: \(code)")
    }
    oauthSession?.start()
  }
}

Upvotes: 2

Murilo Alborghette
Murilo Alborghette

Reputation: 56

With the UIWebView you have interrupt the load in UIWebView delegate shouldStartLoadWithRequest when the url starts with your redirect url and get the parameter authorization code from url, concatenate with "get token url" and call [[NXOAuth2AccountStore sharedStore] handleRedirectURL:getTokenURL];

May not be the best way, but it works for me. :)

English isn’t my first language, so please excuse any mistakes. I hope this can help you.

Upvotes: 2

Jakub Vano
Jakub Vano

Reputation: 3873

NSString *redirectURI = @"myappredirect://";

instead of

NSString *redirectURI = @"http://myappredirect://";

Upvotes: 3

Related Questions