cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Announcements
Want to learn some quick and useful tips to make your day easier? Check out how Calvin uses Replay to get feedback from other teams at Dropbox here.

Dropbox API Support & Feedback

Find help with the Dropbox API from other developers.

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

URI HTTPS request

URI HTTPS request

Mark L.45
Collaborator | Level 8

Hi,

I am trying to follow this dropbox tutorial; but with success

https://blogs.dropbox.com/developers/2013/07/using-oauth-2-0-with-the-core-api/

I tried this call using the parameters shown and it worked, at least tried to redirect me to the localhost. But what does this mean? I simply want to be able to ask a user of app to grant dropbox permission to access a shared directory within their dropbox, so I need their bearer-id in calls my app makes to dropbox.

I setup my own authorisation key thru the dropbox, but what prey ask is a URI in this context? what can use as a redirect URL in this call, assuming I have no plans to set up a web server behind this; its an app that is making this call and I am more than happy to redirect users to dropbox if need be to get the credentials to continue?

https://www.dropbox.com/1/oauth2/authorize?client_id=<appkey>&response_type=code&redirect_uri=<redirect URI>&state=<CSRF token>

client_id I have?
redirect URI I don't have; I set it to https://localhost in my app, but it makes no sense?
CSRF token I can generate?

I am looking to do an “implicit grant” (for client-side apps like mobile or JavaScript apps). I don't want to have to try to implement Swifty API if I can avoid doing so since I want my code to be as simple as possible?

--- posted and partly answered...

If you want to use the implicit flow, your response_type should be set to "token". The client_id should be your app key, and the redirect URI should be some URI where you want the user sent back to after they approve your app to connect to their account. For the implicit a.k.a. token flow, the access token is returned to the redirect URI on the URL fragment.

While in development, you may use localhost, which points to your local machine, to handle the redirect. You may also want to use localhost in general if your app only runs on the client.

There's an OAuth guide here that may be useful:

https://www.dropbox.com/developers/reference/oauthguide

Which I did, but now it is telling me it cannot open the URL I gave it, localhosts; which makes sense cause it isn't a real URL? Do I simply process the result in the https returned?

On that note I still missed something here? If my app that is making this call needs to access the local dropbox, how do I get the client-id with asking the client to visit dropbox and fetch this technical string; a app killer of a setup. I??

10 Replies 10

Greg-DB
Dropbox Staff

It sounds like you're making a client-side app, so the implicit flow using a localhost redirect URI is a reasonable approach. As you saw though, by default there isn't anything being served at localhost, so you're getting that error. You can just grab the access token anyway, but you may want to run a small web server to receive it in order to polish the experience. (Alternatively, you can use an actual web address, such as this one that we provide for purposes like this: https://www.dropbox.com/1/oauth2/redirect_receiver )

Also, to clarify, the client ID is just your app key, which should just be embedded in your app for use by all users of your app to start the app authorization flow. Only the resulting access token is user-specific. You can store and re-use the resulting access token for each user so that they don't have to repeatedly go through that flow.

Mark L.45
Collaborator | Level 8

OK, I tried the redirect_receiver and got nothing back I understand. Here is my code. Tried this with a simple curl too... 

 let request = NSMutableURLRequest(URL: NSURL(string: "https://www.dropbox.com/oauth2/authorize?client_id=X&response_type=token&redirect_uri=https://www.dropbox.com/1/oauth2/redirect_receiver&state=MTIzNDEyMzQ=")!)

        let session = NSURLSession.sharedSession()

        request.HTTPMethod = "GET"

        let task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in

            if let error = error {

                completion(string: nil, error: error)

                return

            }

            let strData = NSString(data: data!, encoding: NSUTF8StringEncoding)

            print("getAuth: \(strData)\n\n")

            do {

                let jsonResult = try NSJSONSerialization.JSONObjectWithData(data!, options:NSJSONReadingOptions.MutableContainers);

                completion(string: ", error: nil)

            } catch {

                completion(string: nil, error: error)

            }

        })

        task.resume()

Obviously X here, is my client ID. It returns data, which presumably is parsable if you're running this thru a web browser which as you can see I am not. The guide talks about acting on the authorisation code? which is found where in this 128 lines of text that comes back? I need to run the subsequent http request as I understand the guide? But using the auth code I find under what  in this response?

https://www.example.com/mycallback?code=<authorization code>&state=<CSRF token>

Still lost on the client ID? How does it know the login credentials of the client if all I am giving it is the app ID I setup; I need this to be accessing the local dropbox of the client it is running under.

 

Greg-DB
Dropbox Staff

It looks like you're trying to access the /authorize page programmatically, but this is actually just a web page that you should be presenting to the user in a browser.

For reference, while you can certainly implement this manually, I recommend checking out the example for the SwiftyDropbox library just as a sample of how this should work:

https://github.com/dropbox/PhotoWatch

Here's the library itself:

https://github.com/dropbox/SwiftyDropbox

Also, note that the "authorization code" only applies to the "code" flow, which you're not using. 

Finally, your app only provides the client ID a.k.a. app key, which identifies the app. It should never have the user's credentials (username and password) which should only be provided by the user on the Dropbox site during the app authorization flow.

Mark L.45
Collaborator | Level 8

Gregory,

Thanks for your help! I managed to get it working, the 128 lines were in fact an invitation to sign into dropbox. I tried the URL you suggested and it was a cleaner transaction; But have as yet not managed to workout how to get the access token back if not in the error thrown by localhost within Swift.

Luke

Greg-DB
Dropbox Staff

Have you tried to use the redirect receiver page in the latest version of your code? If you post the code I'll be happy to try to help with it further.

Mark L.45
Collaborator | Level 8

Hi Gregory,

Here is a code; based on an app coda tutorial by Joyce Echessa; I hope she doesn't mind me posting it here. This is the View Controller: The App Delegate is a simply the template code.  I have commented out the clientID since this is a public post.

If I use localhost I find the data I need in WKNavigation error field; if I use the dropbox URL you gave me; I don't get an error... but don't know where I can find the access_token using Swift.

import UIKit

import WebKit

//  Created by Joyce Echessa on 1/6/15.

//  Copyright (c) 2015 Appcoda. All rights reserved.

class ViewController: UIViewController, UITextFieldDelegate, WKNavigationDelegate {

    

    var webView: WKWebView

    @IBOutlet weak var barView: UIView!

    @IBOutlet weak var urlField: UITextField!

    

    @IBOutlet weak var backButton: UIBarButtonItem!

    @IBOutlet weak var forwardButton: UIBarButtonItem!

    @IBOutlet weak var reloadButton: UIBarButtonItem!

    

    @IBOutlet weak var progressView: UIProgressView!

    

    required init?(coder aDecoder: NSCoder) {

        self.webView = WKWebView(frame: CGRectZero)

        super.init(coder: aDecoder)

        

        self.webView.navigationDelegate = self

    }

 

    override func viewDidLoad() {

        super.viewDidLoad()

        // Do any additional setup after loading the view, typically from a nib.

        

        barView.frame = CGRect(x:0, y: 0, width: view.frame.width, height: 30)

        

        view.insertSubview(webView, belowSubview: progressView)

        

        webView.translatesAutoresizingMaskIntoConstraints = false

        let height = NSLayoutConstraint(item: webView, attribute: .Height, relatedBy: .Equal, toItem: view, attribute: .Height, multiplier: 1, constant: -44)

        let width = NSLayoutConstraint(item: webView, attribute: .Width, relatedBy: .Equal, toItem: view, attribute: .Width, multiplier: 1, constant: 0)

        view.addConstraints([height, width])

        

        webView.addObserver(self, forKeyPath: "loading", options: .New, context: nil)

        webView.addObserver(self, forKeyPath: "estimatedProgress", options: .New, context: nil)

        

    // let url = NSURL(string:"https://www.dropbox.com/oauth2/authorize?client_id=X&response_type=token&redirect_uri=https://www.dr...")

        let url = NSURL(string:"https://www.dropbox.com/oauth2/authorize?client_id=X&response_type=token&redirect_uri=https://localh...")

        let request = NSURLRequest(URL:url!)

        print("request \(request)")

        webView.loadRequest(request)

        

        //backButton.enabled = false

        //forwardButton.enabled = false

        

    }

 

    override func didReceiveMemoryWarning() {

        super.didReceiveMemoryWarning()

        // Dispose of any resources that can be recreated.

    }

    

    override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {

        barView.frame = CGRect(x:0, y: 0, width: size.width, height: 30)

    }

    

    func textFieldShouldReturn(textField: UITextField) -> Bool {

        urlField.resignFirstResponder()

        webView.loadRequest(NSURLRequest(URL:NSURL(string: urlField.text!)!))

        print("urlField.text \(urlField.text!)")

        return false

    }

    

    

    @IBAction func back(sender: UIBarButtonItem) {

        webView.goBack()

    }

    

    @IBAction func forward(sender: UIBarButtonItem) {

        webView.goForward()

    }

    

    @IBAction func reload(sender: UIBarButtonItem) {

        let request = NSURLRequest(URL:webView.URL!)

        print("reload \(request)")

        webView.loadRequest(request)

    }

    

    override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<()>) {

        if (keyPath == "loading") {

            backButton.enabled = webView.canGoBack

            forwardButton.enabled = webView.canGoForward

        }

        if (keyPath == "estimatedProgress") {

            progressView.hidden = webView.estimatedProgress == 1

            progressView.setProgress(Float(webView.estimatedProgress), animated: true)

        }

    }

    

    func webView(webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: NSError) {

        print("WKNavigation \(error)")

        let alert = UIAlertController(title: "Error", message: error.localizedDescription, preferredStyle: .Alert)

        alert.addAction(UIAlertAction(title: "Ok", style: .Default, handler: nil))

        presentViewController(alert, animated: true, completion: nil)

    }

    

    func webView(webView: WKWebView, didFinishNavigation navigation: WKNavigation!) {

        progressView.setProgress(0.0, animated: false)

    }

 

 

}

 

 

Greg-DB
Dropbox Staff

Thanks! This is helpful. You're using WKWebView, and you already have didFinishNavigation implemented, which is where you'll grab the token from the URL. That is, switch to the redirect receiver version and access webView.URL inside didFinishNavigation. You can check if webView.URL is the redirect receiver, and parse the token from the URL if so.

For example, you can do something like this:

 if (webView.URL?.scheme == "https" && webView.URL?.host == "www.dropbox.com" && webView.URL?.path == "/1/oauth2/redirect_receiver") {
print(webView.URL?.fragment)
// parse out access token
}

Here's how SwiftyDropbox does the parsing:

https://github.com/dropbox/SwiftyDropbox/blob/abb413a4788bd8c2dade1103414d52330e1cb552/Source/OAuth....

Also, don't forget to check your state parameter, which should be randomly generated each time. 

Finally, note you'll also need to set disable_signup=true on /authorize to comply with Apple's rules.

Mark L.45
Collaborator | Level 8

Thanks Gregory,

Works perfectly even with the dropBox URL now, although I am not sure where I need to set the disable_signup? Need a little bit more help on that.. 

On a related note; here my code to parse the token,which works and is easier than yours 🙂 although maybe I'v missed something... saving it to defaults too so that the user only needs to set this up once...

 let tokenText = String(webView.URL!.fragment)

            if (tokenText.rangeOfString("access_token=") != nil) {

                let tokenStart = tokenText.rangeOfString("access_token=")!.startIndex.advancedBy(13)

                let tokenText2 = tokenText.substringFromIndex(tokenStart)

                let tokenEnd = tokenText2.rangeOfString("token_type")!.startIndex.advancedBy(-1)

                token2Save = tokenText2.substringToIndex(tokenEnd)

                let defaults = NSUserDefaults.standardUserDefaults()

                defaults.setObject(token2Save, forKey: "dropBoxAuth")

            }

 

Steve M.
Dropbox Staff

disable_signup=true goes on your /authorize URL. E.g. https://www.dropbox.com/1/oauth2/authorize?...&disable_signup=true. See https://www.dropbox.com/developers/documentation/http/documentation#oauth2-authorize.

Your code for finding the access token will break if the parameters come in a different order.

 

Need more support?
Who's talking

Top contributors to this post

  • User avatar
    Mark L.45 Collaborator | Level 8
  • User avatar
    Steve M. Dropbox Staff
  • User avatar
    Greg-DB Dropbox Staff
What do Dropbox user levels mean?