cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Announcements
Share your feedback on the Document Scanning Experience in the Dropbox App right 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: 

How can i get lifetime Access Token

How can i get lifetime Access Token

Ghost Mjrm
Explorer | Level 4

i have android app connected to my Dropbox folder using access token but every 4 hour should i edit my code and input the new access token is there any method to make the app working 24h without any interact from me

and fix the message that show access token error uploading to Dropbox: expired access token

 

 

private void uploadToDropbox(File photoFile) {
if (photoFile == null || !photoFile.exists()) {
runOnUiThread(() -> Toast.makeText(MainActivity.this, "Error: Photo file does not exist", Toast.LENGTH_SHORT).show());
return;
}

DbxRequestConfig config = DbxRequestConfig.newBuilder("Decamera").build();
DbxClientV2 client = new DbxClientV2(config, DROPBOX_ACCESS_TOKEN);

try {
String remotePath = "/Decamera/" + photoFile.getName();

try (InputStream in = new FileInputStream(photoFile)) {
client.files().uploadBuilder(remotePath)
.withMode(WriteMode.ADD)
.uploadAndFinish(in);

runOnUiThread(() -> Toast.makeText(MainActivity.this, "Photo uploaded to Dropbox", Toast.LENGTH_SHORT).show());
}

} catch (Exception e) {
e.printStackTrace();
runOnUiThread(() -> Toast.makeText(MainActivity.this, "Error uploading to Dropbox: " + e.getMessage(), Toast.LENGTH_SHORT).show());
}
}
private static final String DROPBOX_ACCESS_TOKEN = my access token

 

41 Replies 41

Ghost Mjrm
Explorer | Level 4

this androidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.decamera">

<!-- Permissions -->
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.location.gps" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />

<!-- Features -->
<uses-feature android:name="android.hardware.camera" />

<application
android:allowBackup="true"
android:icon="@mipmap/logo"
android:label="@string/app_name"
android:roundIcon="@mipmap/logo_round"
android:supportsRtl="true"
android:theme="@style/Theme.DeCamera"
tools:targetApi="31">

<!-- Activity for handling Dropbox authorization callback -->
<activity
android:name=".MainActivity"
android:exported="true">

<!-- Intent filter for main activity -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>

<!-- Intent filter for handling Dropbox authorization redirect -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="decamera" android:host="auth-finish" />
</intent-filter>
</activity>
</application>

</manifest>

Здравко
Legendary | Level 20

@Ghost Mjrm wrote:

...

error 400 invalid redirect_uri. when response_type=code without PKCE,redirect_uri must start with "https://", unless its a localhost URI


@Ghost Mjrm, you posted already the answer of your question (part of error message). To be able set scheme different than "https" (or similar) you need PKCE auth flow (something you skipped). :winking_face: That's it - forget about app secret; focus on code challenge and code verifier (parts of PKCE).

 

PS: Why don't you use the SDK as is (including authentication) and skip re-implementing something already existing there? 🤷

Ghost Mjrm
Explorer | Level 4

yeah i have noticed it but honestly i don't know what PKCE mean but i will search about it

but im little bit confuse should i create a input key that can the user insert in it  the obtained access token to success the upload to dropbox operation or is there another way that the app automatically read it form the browser and use it

i already have this mechanism in my code but it dont know if it work

i told you im little bit confused and i don't get the complete idea or redirected url so i used ChatGPT To make to me this mechanism so can you please check my code if it good? >:

i just want when the user click on the corner button to start oAuth 2 operation and get access token then my app use this access token to upload the photo to dropbox

Best Regards

 

Здравко
Legendary | Level 20

@Ghost Mjrm wrote:

...

i just want when the user click on the corner button to start oAuth 2 operation and get access token then my app use this access token to upload the photo to dropbox

...


If you get access token directly then this token will expire in 4 hours or so. So you go beck at the beginning.

 


@Ghost Mjrm wrote:

yeah i have noticed it but honestly i don't know what PKCE mean but i will search about it

...


PKCE is an alternative way to perform OAuth flow, nothing more. Instead of using app secret, dynamic pair of keys is used (code challenge and code verifier). One is passed in OAuth initiation and other in token receiving (something that guarantees avoid "man in middle" - the same thing what app secret does - just more secure way). 🤫 That's it.

As the message shows, your code is erroneous. You don't need any additional "input key" (whatever it means). Don't rely on AI, but rather on your own intelligence and don't be lazy in reading documentation. :winking_face::beaming_face_with_smiling_eyes: AI (of any kind) is NOT so intelligent yet (might become some day but not now).

Ghost Mjrm
Explorer | Level 4
Ok bro thanks a lot

Ghost Mjrm
Explorer | Level 4

there is my main code

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

private static final int CAMERA_PERMISSION_REQUEST = 100;
private static final String[] REQUIRED_CAMERA_PERMISSIONS = new String[]{Manifest.permission.CAMERA};

private static final String DROPBOX_APP_KEY = "hc2p6uj44p9pyoc";
private static final String DROPBOX_APP_SECRET = "i cannot show this";
private static final String DROPBOX_REDIRECT_URI = "https://auth-finish";

private String DROPBOX_ACCESS_TOKEN = null;
private PreviewView previewView;
private ImageCapture imageCapture;
private TextView addressTextView;

private ExecutorService cameraExecutor = Executors.newSingleThreadExecutor();
private FusedLocationProviderClient fusedLocationProviderClient;
private Geocoder geocoder;

// Add latitude and longitude variables
private double latitudeValue;
private double longitudeValue;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

previewView = findViewById(R.id.previewView);
ImageButton captureButton = findViewById(R.id.captureButton);
ImageButton leftCornerButton = findViewById(R.id.leftCornerButton);
addressTextView = findViewById(R.id.addressTextView);

fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
geocoder = new Geocoder(this, Locale.getDefault());

captureButton.setOnClickListener(this);

leftCornerButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
initiateDropboxAuthorization();
}
});

addressTextView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showEditAddressDialog();
}
});

if (allPermissionsGranted()) {
startCamera();
getLastLocation();
} else {
ActivityCompat.requestPermissions(this, REQUIRED_CAMERA_PERMISSIONS, CAMERA_PERMISSION_REQUEST);
}

// Initialize Dropbox access token if available
SharedPreferences prefs = getPreferences(Context.MODE_PRIVATE);
DROPBOX_ACCESS_TOKEN = prefs.getString("dropboxAccessToken", null);

// Check if the app was opened with a Dropbox authorization callback
handleDropboxAuthorizationCallback(getIntent());
}

// Override onNewIntent to handle the Dropbox authorization callback
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);

// Log the received intent data for debugging
Log.d("Dropbox", "Received new intent: " + intent);

// Extract and log the data URI
Uri data = intent.getData();
Log.d("Dropbox", "Intent data URI: " + data);

if (data != null && data.toString().startsWith(DROPBOX_REDIRECT_URI)) {
// Authorization successful, extract the authorization code
String code = data.getQueryParameter("code");

// Log the authorization code for debugging
Log.d("Dropbox", "Authorization Code: " + code);

// Now, exchange the authorization code for an access token and refresh token
exchangeAuthorizationCodeForTokens(code);
}
}

private void initiateDropboxAuthorization() {
// Construct the Dropbox authorization URL
String authorizationUrl = "https://www.dropbox.com/oauth2/authorize" +
"?client_id=" + DROPBOX_APP_KEY +
"&response_type=code" +
"&token_access_type=offline" +
"&state=myState" + // Replace with your own state
"&redirect_uri=" + DROPBOX_REDIRECT_URI;

// Open the authorization URL in a web browser or WebView
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(authorizationUrl));
startActivity(browserIntent);
}
private String performPostRequest(String requestUrl, String urlParameters) {
try {
URL url = new URL(requestUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connection.setRequestProperty("Content-Length", Integer.toString(urlParameters.getBytes().length));
connection.setDoOutput(true);

// Log the request details
Log.d("Dropbox", "POST Request URL: " + requestUrl);
Log.d("Dropbox", "POST Request Body: " + urlParameters);

// Write the request body
try (DataOutputStream wr = new DataOutputStream(connection.getOutputStream())) {
wr.writeBytes(urlParameters);
wr.flush();
}

// Get the response
try (InputStream is = connection.getInputStream();
BufferedReader rd = new BufferedReader(new InputStreamReader(is))) {
StringBuilder response = new StringBuilder();
String line;
while ((line = rd.readLine()) != null) {
response.append(line);
response.append('\r');
}

// Log the response
Log.d("Dropbox", "POST Response: " + response.toString());

return response.toString();
}
} catch (Exception e) {
// Log any exceptions
Log.e("Dropbox", "Error in HTTP request: " + e.getMessage());
return null;
}
}
private void handleDropboxAuthorizationCallback(Intent intent) {
// Log the received intent for debugging
Log.d("Dropbox", "Handling Dropbox Authorization Callback Intent: " + intent);

Uri data = intent.getData();
if (data != null && data.toString().startsWith(DROPBOX_REDIRECT_URI)) {
// Authorization successful, extract the authorization code
String code = data.getQueryParameter("code");

// Log the authorization code for debugging
Log.d("Dropbox", "Authorization Code: " + code);

// Now, exchange the authorization code for an access token and refresh token
exchangeAuthorizationCodeForTokens(code);
} else {
// Log a message if the intent data is unexpected
Log.d("Dropbox", "Invalid Dropbox Authorization Callback Intent Data: " + data);
}
}

private void exchangeAuthorizationCodeForTokens(String code) {
new AsyncTask<String, Void, Void>() {
@Override
protected Void doInBackground(String... params) {
try {
String url = "https://api.dropbox.com/oauth2/token";
String requestBody = "code=" + params[0] +
"&grant_type=authorization_code" +
"&client_id=" + DROPBOX_APP_KEY +
"&client_secret=" + DROPBOX_APP_SECRET +
"&redirect_uri=" + DROPBOX_REDIRECT_URI;

// Log the request details
Log.d("Dropbox", "Token Exchange Request URL: " + url);
Log.d("Dropbox", "Token Exchange Request Body: " + requestBody);

// Perform the POST request and obtain the JSON response
String jsonResponse = performPostRequest(url, requestBody);

// Log the response
Log.d("Dropbox", "Token Exchange Response: " + jsonResponse);

// Parse the JSON response to extract access and refresh tokens
JSONObject jsonObject = new JSONObject(jsonResponse);
DROPBOX_ACCESS_TOKEN = jsonObject.getString("access_token");

// Log the obtained access token
Log.d("Dropbox", "Access Token Obtained: " + DROPBOX_ACCESS_TOKEN);

// Save the Dropbox access token
SharedPreferences prefs = getPreferences(Context.MODE_PRIVATE);
prefs.edit().putString("dropboxAccessToken", DROPBOX_ACCESS_TOKEN).apply();

} catch (Exception e) {
// Log any exceptions
Log.e("Dropbox", "Error in token exchange: " + e.getMessage());
}
return null;
}
}.execute(code);
}

private void uploadToDropbox(File photoFile) {
if (photoFile == null || !photoFile.exists()) {
runOnUiThread(() -> Toast.makeText(MainActivity.this, "Error: Photo file does not exist", Toast.LENGTH_SHORT).show());
return;
}

if (DROPBOX_ACCESS_TOKEN == null) {
runOnUiThread(() -> Toast.makeText(MainActivity.this, "Error: Dropbox access token is null", Toast.LENGTH_SHORT).show());
return;
}

DbxRequestConfig config = DbxRequestConfig.newBuilder("Decamera").build();
DbxClientV2 client = new DbxClientV2(config, DROPBOX_ACCESS_TOKEN);

try {
String remotePath = "/Decamera/" + photoFile.getName();

try (InputStream in = new FileInputStream(photoFile)) {
FileMetadata metadata = client.files().uploadBuilder(remotePath)
.withMode(WriteMode.ADD)
.uploadAndFinish(in);

runOnUiThread(() -> {
Toast.makeText(MainActivity.this, "Photo uploaded to Dropbox", Toast.LENGTH_SHORT).show();
// Log metadata information
Log.d("Dropbox", "File uploaded. Metadata: " + metadata.toString());
});
}

} catch (Exception e) {
e.printStackTrace();
runOnUiThread(() -> Toast.makeText(MainActivity.this, "Error uploading to Dropbox: " + e.getMessage(), Toast.LENGTH_SHORT).show());
}
}

Здравко
Legendary | Level 20

Hm..:thinking_face: Are you still trying some sort of AI? 🧐 @Ghost Mjrm, come on... :beaming_face_with_smiling_eyes: I believe you have your own; use it! :winking_face:

Ghost Mjrm
Explorer | Level 4

im not using ai just to copy paste its help to understand the main code to how to exchange authorized code with access token using the app key and app secret and teach me to constructor the link and make post and request method im not using it blindly and its help to create log statments to dedicate the error in the logcat its a powerful but at the end i got upload to dropbox success message but and im 100% sure that the Decamera folder name is correct and app key app secret correct so where is the problem i cannot find it

Здравко
Legendary | Level 20

@Ghost Mjrm wrote:

... so where is the problem i cannot find it


Ah..🙋 If that's fine for you, you can use it in such a way, of course. In such a case you can remove the "offline" declaration for the access type since you're not using it in fact. So big part of entire discussion seems meaningless - you don't need long term access since the posted cover your demands. :slightly_smiling_face: Ok, all done.

Ghost Mjrm
Explorer | Level 4
Thank you for your support
Need more support?
Who's talking

Top contributors to this post

  • User avatar
    Ghost Mjrm Explorer | Level 4
  • User avatar
    Здравко Legendary | Level 20
What do Dropbox user levels mean?