## TL;DR

Stop using the long-lived token and switch to the refresh-token flow: exchange the refresh token for a short-lived access token, then keep refreshing on expiry. Dropbox retired long-lived tokens, so any code still holding one gets invalid_access_token. Refresh once, cache the short-lived token, refresh again when it expires.

```text
dropbox API error: invalid_access_token on long-lived token refresh
```

## Steps

1. Confirm your app has a stored refresh token (issued when the user authorized with offline access). Expected: you can find a refresh token in your credential store, not just the old access token.

2. Exchange the refresh token for a fresh access token by calling the Dropbox token endpoint with the refresh grant type, your app key, and your app secret. Expected: the endpoint returns a new short-lived access token.

3. Replace every stored use of the old long-lived token with the new short-lived token. Expected: no code path still sends the retired token.

4. Add refresh-on-expiry logic: when a call returns invalid_access_token or the token nears its expiry time, repeat the exchange automatically. Expected: the client recovers from expiry without manual steps.

5. Retry the original API call with the fresh token. Expected: Dropbox accepts the call and the error is gone.

## Use this when

- Dropbox returns exactly "invalid_access_token" on a refresh attempt.
- The integration was built when Dropbox still issued long-lived tokens.
- Token refresh worked before and broke without a code change.

## Not for this skill when

- The app key or app secret is wrong (that fails at the token endpoint differently).
- The user revoked access (refresh tokens stop working too; re-authorize instead).
- The provider is not Dropbox; other OAuth providers keep long-lived tokens.

## Variant phrasings

- Dropbox refresh token returns invalid_access_token
- Dropbox long lived token no longer works
- Dropbox oauth token refresh invalid access token

## Why it happens

Dropbox moved to short-lived access tokens plus refresh tokens and retired the old long-lived tokens. Generated clients built against the old model keep sending or trying to refresh the retired token, and the API answers invalid_access_token. The fix is the standard OAuth refresh flow, which the client simply never implemented.

## Edge cases

- Refresh tokens can be revoked by the user or by Dropbox; when the refresh itself fails with invalid_grant, send the user through authorization again.
- The token endpoint needs the app secret, so this exchange must run server-side, never in browser code.
- Clock skew does not matter much here, but caching the expiry timestamp from the token response avoids refreshing on every call.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_RtkI1XZSr8oU023Xd9GpMg
