dropbox / dropbox/dropbox-sdk-rust

Fails to refresh API token due to API quirk (unlike Python SDK)

Open
#207 0 comments 0 reactions 0 assignees View on GitHub
bug
Dominant language
Rust
Stars
91
Forks
19
PR merge metrics
No merged PRs in 30d

Description

**Describe the bug**
The Dropbox API has a peculiar quirk where it wraps an authentication error on content endpoints such as `files/upload` and `files/download` into `"other"`, losing the actual structured error classification. For example, for an expired token it would normally be `"expired_access_token"`.

**To Reproduce**
The actual error is instead JSON-encoded inside `user_message.text`. This can be reproduced directly with curl:

```sh
BAD='sl.this-is-not-a-valid-dropbox-token-0123456789012345678901234567890123456789'

curl -sS https://api.dropboxapi.com/2/files/get_metadata \
-H "Authorization: Bearer $BAD" \
-H 'Content-Type: application/json' \
-d '{"path":"/does-not-exist"}'

printf test | curl -sS https://content.dropboxapi.com/2/files/upload \
-H "Authorization: Bearer $BAD" \
-H 'Dropbox-API-Arg: {"path":"/does-not-exist"}' \
-H 'Content-Type: application/octet-stream' \
--data-binary @-
```

**Expected Behavior**
Either the Rust SDK handles the above by unwrapping, or the API returns something that isn't `"other"`.

**Actual Behavior**
The first request returns:

```json
{"error":{".tag":"invalid_access_token"},"error_summary":"invalid_access_token/"}
```

The content request returns:

```json
{
"error": {".tag": "other"},
"error_summary": "other/...",
"user_message": {
"locale": "en",
"text":
"{\"error\":{\".tag\":\"invalid_access_token\"},\"error_summary\":\"invalid_access_token/\"}"
}
}
```

The same wrapping has been observed for `"expired_access_token"`.

**Versions**
* Reproduced with `dropbox-sdk` 0.20.3.
* Rust 1.97.1
* Linux 6.18.44, x86-64, NixOS 26.05

**Additional context**
This behavior has also been mentioned in a forum post at:

The Rust SDK does support automatic token refresh after receiving `ExpiredAccessToken`, which gets masked by the `Other` wrapping. It lacks proactive expiration-based refresh, unlike e.g. the Python SDK.

Someone writing code will likely assume `Other` is not fixable by refreshing a token and thus have an app that does not survive the four-hour token lifetime if its first request after expiry is a content request (ask me how I know!).

I'm not sure what the best fix is. It could be any of:

- Dropbox fixing its upstream API
- Adding proactive automatic token refresh to the Dropbox SDK, which may or may not be feasible depending on its structure
- Unwrapping other errors by trying to deserialize the contents of `user_message.text` in the Rust SDK

In the meantime, treating `Other` as an expired token in the consuming app and performing a bounded refresh-and-retry works, but I shudder to think what happens if an actual `Other` error comes around.

Contributor guide

Open the contributing guide

Research direction

Reproduce the discrepancy with the supplied curl requests against files/get_metadata and files/upload, then trace how the Rust SDK handles Other and ExpiredAccessToken responses. Compare the available approaches—unwrapping user_message.text, proactive refresh, or another bounded retry strategy—and define done as preserving correct token-refresh behavior without misclassifying genuine Other errors.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
api, authentication
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.