Dropbox API Support & Feedback
Find help with the Dropbox API from other developers.
Dear greg-DB,
sorry, but I have to come back to this topic again, since I couldn't solve it in the recent weeks despite all these valuable hints in this forum and the description for the Swift SDK.
I'm writing an app with Swift and I originally set it up with a long-term token, which was changed by Dropbox in the meantime.
I do the setup in the appDelegate with (dropboxAppKey is the key I created in the Dropbox-portal for my App)
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
UIApplication.shared.registerForRemoteNotifications()
DropboxClientsManager.setupWithAppKey(dropboxAppKey)
...
}
and I'm doing the connect as decribed with
func connectDropbox() {
let scopeRequest = ScopeRequest(scopeType: .user, scopes: ["files.content.write", "files.content.read", "account_info.read"], includeGrantedScopes: false)
DropboxClientsManager.authorizeFromControllerV2(
UIApplication.shared,
controller: self,
loadingStatusDelegate: nil,
openURL: { (url: URL) -> Void in UIApplication.shared.open(url, options: [:], completionHandler: nil) },
scopeRequest: scopeRequest
)
}
and as described in appDelegate with:
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
let oauthCompletion: DropboxOAuthCompletion = {
if let authResult = $0 {
switch authResult {
case .success:
print("Success! User is logged into DropboxClientsManager.")
case .cancel:
print("Authorization flow was manually canceled by user!")
case .error(_, let description):
print("Error: \(String(describing: description))")
}
}
}
let canHandleUrl = DropboxClientsManager.handleRedirectURL(url, completion: oauthCompletion)
return canHandleUrl
}
respectively as described in the SDK for the SceneDelegate.
Everything works fine and I can access data from and save data to the Dropbox for a certain while (it seems to be even less than 4 hours) and then out of a sudden the connection is interrupted.
Within my app I check the availability of the dropbox before saving or retrieving data with:
if let client = DropboxClientsManager.authorizedClient {
dropboxClient = client
dropboxClient!.files.download(path: ... )
.response { response, error in
if let response = response {
let _ = response.0
let fileContents = response.1
<code>
} else if let error = error {
switch error as CallError {
case .routeError:
<code>
default:
<code>
return
}
}
}
}
Unfortunately, I can't manage the described automatic refresh for my app. Is there a certain coding I have to call if the above mentioned availability-check ("if let client = DropboxClientsManager.authorizedClient ") provides nil?
Thanks for your support
Can you elaborate on what you mean when you say "the connection is interrupted"? Do you get a particular error? If so, please share it here. Or, do you mean that DropboxClientsManager.authorizedClient just becomes nil at that point?
Dear Greg-DB,
it is the latter one - I get the "nil" as response in the availability check. I understood the whole discussion that this shouldn't be the case and the refresh should happen automatically via the refresh token in the background instead. Is this correct?
Thanks for the support
Thanks for clarifying. That's correct, the refresh process should be handled for you automatically as long as you've processed the authorization flow using authorizeFromControllerV2.
Even if you did only have a short-lived access token stored though, or if the refresh process failed and the SDK wasn't able to get a new short-lived access token, you would still have the expired access token stored so you would have a non-nil authorizedClient and should get back a specific error like 'expired_access_token' when attempting a call.
So, from your description, with the issue occurring sooner than four hours, and with authorizedClient itself being nil, it sounds like the issue isn't actually with the access token expiration itself. It seems as if the token isn't being persisted successfully. The SDK uses the system's keychain functionality to store and retrieve the tokens.
Does the authorizedClient seem to get lost after any particular event, such as when the app (or device) is restarted?
Does this happen on multiple different devices? (I've occasionally heard of issues with the keychain not working properly on specific devices.)
Do you perhaps get any error/output during the authorizeFromControllerV2/handleRedirectURL flow?
Dear Greg-DB,
I don't get any error messages when initially connecting or reconnecting to the Dropbox. Nor is there a pattern when the reconnection doesn't work. It even happens during working with the app for a longer time when the user wants to store data on Dropbox. It happens on different devices e.g. iPhone 8 and iPhone 12.
Is there a command in swift to to initiate the refresh of the token programmatically?
There is a refreshAccessToken method, but you don't need to call that. (That's used internally, or if you want to switch to a smaller subset of scopes.) The SDK automatically performs the normal refresh process for you.
It doesn't sound like that's the issue anyway though, as the local client wouldn't get set to nil if the access token expires. The server would just return an error when an expired access token is used. Also, it doesn't seem like expiration is the issue since you're seeing this occur sooner than four hours after authorization.
Are you calling anything like unlinkClients, resetClients, or clearStoredAccessToken(s)?
Dear greg-DB,
thanks for your quick replies - highly appreciated.
No, I'm not using unlinkClients, resetClients, or clearStoredAccessToken(s) or something like it. As quoted above, I only do the setup with the DropboxClientsManager.setupWithAppKey() in appDelegate und authorize with the DropboxClientsManager.authorizeFromControllerV2(). After it I only do read and write tasks - all checked with
if let client = DropboxClientsManager.authorizedClient {... }
where sometimes the nil-value is returned, in which cases then the reconnection is initiated.
In which cases turns the DropboxClientsManager.authorizedClient to nil? Do I have to handle it differently, when it is nil? Currently I'm calling the DropboxClientsManager.authorizeFromControllerV2() in these cases.
The authorizedClient should only be nil if the clients were reset, or if after a relaunch the SDK wasn't able to retrieve the token from the Keychain. There isn't anything else you need to be doing to keep the authorizedClient available. Calling authorizeFromControllerV2 when you don't have an authorizedClient and need to connect to an account is the right procedure. Seeing authorizedClient automatically revert to nil is just unexpected.
Anyway, I don't see anything you're doing wrong here that should cause this, and I can't reproduce the issue here myself. Apologies for the bother, but would you be able to share a small sample project that reproduces the issue so we can investigate here? Thanks in advance!
That may not be helpful as we wouldn't be able to inspect or debug the code directly.
I've put together a small sample project using the code snippets you provided here, just filling in the gaps as necessary. It doesn't reproduce the issue for me. (It retains the authorizedClient and can successfully make calls even after more than four hours after authorization.) Could you try it though and see if produces the issue for you?
Hi there!
If you need more help you can view your support options (expected response time for a ticket is 24 hours), or contact us on X or Facebook.
For more info on available support options for your Dropbox plan, see this article.
If you found the answer to your question in this Community thread, please 'like' the post to say thanks and to let us know it was useful!