Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Correct method of authenticating with refresh token only #769

Closed
mtrlar opened this issue Aug 11, 2021 · 4 comments
Closed

Correct method of authenticating with refresh token only #769

mtrlar opened this issue Aug 11, 2021 · 4 comments
Labels

Comments

@mtrlar
Copy link

mtrlar commented Aug 11, 2021

I'm using v10.5.0 with Javascript.

I have a manual user workflow to generate and store a refresh token. I now want my JS client to use that same refresh token across all my users so they can all upload to the same dropbox account without any manual OAuth flow for them.

I checked the code and it seems that if I do pass a refresh token and I don't pass an access token then checkAndRefreshAccessToken will determine that a refresh is required and call refreshAccessToken. I believe this is being called because I see this POST request in my network:

https://api.dropboxapi.com/oauth2/token?grant_type=refresh_token&refresh_token={myRefreshToken}&client_id={myClientId}

The result of this call is;

{"error_description": "No auth function available for given request", "error": "invalid_request"}

I did some testing with the HTTP call, and I found that I had to pass an Authorization header client_id/client_secret and I had to remove 'client_id' from the parameters. If I do this, then a new access token is returned.

Can you let me know what I am doing wrong? I have a refresh token, it should be enough to generate a short-lived access token, but I just can't work out how to get this library to do it.

Current constructor:

        let dbx = new Dropbox({
            clientId: data.dropbox.client_id,
            refreshToken: data.dropbox.refresh_token,
            fetch: isoFetch,
        });

Thanks in advance.

@greg-db
Copy link
Contributor

greg-db commented Aug 11, 2021

[Cross-linking for reference: https://www.dropboxforum.com/t5/Discuss-Dropbox-Developer-API/Refresh-token-using-dropbox-sdk-js-returns-400-error/td-p/538793 ]

This will actually depend on whether or not you used "PKCE" (set by the usePKCE option on , e.g., as shown in this example) when retrieving that refresh token.

If you used PKCE, you can supply just the client ID and refresh token like you're doing here.

If you didn't use PKCE, you would need to supply both the client ID and secret as well as the refresh token. Otherwise, you'll get an error like this.

I see you're not supplying the client secret, so it appears you did not use PKCE to get this refresh token. That being the case, you would need to either add the clientSecret parameter to your Dropbox constructor when using this refresh token, or get a new refresh token using PKCE.

@greg-db greg-db closed this as completed Aug 11, 2021
@mtrlar
Copy link
Author

mtrlar commented Aug 12, 2021

Thanks for such a quick response Greg.

I've switched over to PKCE as recommended and I have the flow working successfully. I did have a couple of issues that maybe you can help with:

Example: PKCE code flow token request

curl https://api.dropbox.com/oauth2/token \
    -d code=<AUTHORIZATION_CODE> \
    -d grant_type=authorization_code \
    -d redirect_uri=<REDIRECT_URI> \
    -d code_verifier=<VERIFICATION_CODE> \
    -d client_id=<APP_KEY>
  • I was unable to get the sha256 to work. I passed the hashed code in the initial request and the unhashed code in the token request and received an invalid code verifier error. I independently verified that my PHP hashing algorithm was working. I noticed that the hashed string you generate in your JS client is different to the string I would generate as a result of a PHP hash. Here was how I generated my query param:
$queryString = $foo .

// Returns "invalid code verifier" error
// 'code_challenge=' . hash( 'sha256', self::CODE_VERIFIER ) . '&' .
// 'code_challenge_method=S256&' .

// Successful
'code_challenge=' . self::CODE_VERIFIER . '&' .
'code_challenge_method=plain';

@greg-db
Copy link
Contributor

greg-db commented Aug 12, 2021

  • When exchanging an authorization code, the /oauth2/token endpoint actually accepts the app key and secret as either as URL parameters client_id and client_secret (using the -d option in curl) or as the Authorization header (using the -u parameter in curl, which automatically encodes them like a Basic username/password combination in the Authorization header). Either is fine. When using PKCE though, where only the app key is needed, apps should just use the client_id parameter to send just the app key.

  • It sounds like the PHP hash function doesn't produce the value in exactly the right required format. You can see how it's generated in the SDK here, for example.

@mtrlar
Copy link
Author

mtrlar commented Aug 12, 2021

Thanks Greg. It was only the initial /oauth2/token call (made in my php) to obtain the refresh token where I needed the client secret so maybe I was misinterpreting the docs.

I did take a look at your code for generating the hash and tried to port to PHP, but since everything is working now I have other demands on my time. I might come back to it at a later date.

Thanks again for your help. It's much appreciated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants