Report this

What is the reason for this report?

Does DigitalOcean OAuth Authorization Code Flow Support Public Desktop Clients Using PKCE (Without client_secret)?

Posted on October 3, 2025

Hello all

I’m building a macOS desktop application (no backend) and attempted to use the OAuth 2.0 Authorization Code flow as a “public” client with PKCE (no client_secret distributed). I consistently receive a valid authorization code, but every token exchange without client_secret returns the same 401 invalid_request.

Once I include client_secret in the token POST body (with or without PKCE), the exchange succeeds immediately. This suggests DigitalOcean requires a client_secret for the Authorization Code flow, and does not accept a PKCE-only public/native pattern—unless I’m missing a required setting.

Environment / Context

  • Desktop app (Flutter/Dart), launching system browser.
  • Redirect URI registered exactly: [http://localhost:48815/callback]
  • Tested multiple scopes:
    • Fine-grained: account:read, account:read droplet:read
    • Legacy: read, read write
    • Empty (for test)
    • Mixed (account:read read)
  • All scope variants behave identically (no invalid_scope errors).

PKCE Attempt (Fails)

Authorize request (example):

GET https://cloud.digitalocean.com/v1/oauth/authorize
  ?response_type=code
  &client_id=<CLIENT_ID>
  &redirect_uri=http%3A%2F%2Flocalhost%3A48815%2Fcallback
  &scope=account%3Aread
  &state=<STATE>
  &code_challenge=<S256_CHALLENGE>
  &code_challenge_method=S256

Token POST (x-www-form-urlencoded), NO client_secret:

grant_type=authorization_code
code=<AUTH_CODE>
redirect_uri=http://localhost:48815/callback
client_id=<CLIENT_ID>
code_verifier=<ORIGINAL_CODE_VERIFIER>

Response (always):

{"error":"invalid_request","error_description":"The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed."}

Non-PKCE Attempt (Also Fails Without Secret)

Token POST (no challenge/verifier):

grant_type=authorization_code
code=<AUTH_CODE>
redirect_uri=http://localhost:48815/callback
client_id=<CLIENT_ID>

Same 401 invalid_request.

With client_secret (Success)

Token POST (PKCE on OR off both succeed) + I don’t think its relevant if we’re using client_secret then we wouldn’t need PKCE:

grant_type=authorization_code
code=<AUTH_CODE>
redirect_uri=http://localhost:48815/callback
client_id=<CLIENT_ID>
client_secret=<CLIENT_SECRET>
[optionally] code_verifier=<ORIGINAL_CODE_VERIFIER>

Response: 200 with access_token (length ~71 chars), token_type=bearer.

Observations

  1. The authorization step always succeeds (state matches, code returned).
  2. Only difference between failure and success is presence of client_secret.
  3. PKCE parameters appear ignored server-side when secret is omitted.
  4. Scopes don’t influence the behavior—no invalid_scope errors were seen.
  5. Redirect URI is clearly correct (else no code would be issued).

Questions

  1. Does DigitalOcean currently support Authorization Code + PKCE for public/native clients (no client_secret)?
  2. If yes, what registration flag or additional parameter is required to enable secret-less PKCE?
  3. If no, is there a recommended pattern for desktop apps to avoid embedding a client_secret (e.g. a documented token broker architecture)?
  4. Are there any enhanced diagnostics or error codes available beyond the generic 401 invalid_request for this scenario?

Naturally this has been frustrating to debug! But I’m not in a position to use easily use a client_secret and unfrotuantely the documentation is ambiguous / incomplete. The API reference says that an ‘implict flow’ is supported. But you have an article (linked below) saying that ‘implicit flow’ is not recommended and the future is PKCE… I’m a huge fan of DigitalOcean and hope I can get this cleared up and documented for the next dev!

API Ref: https://docs.digitalocean.com/reference/api/oauth/

Tutorial / Article: https://www.digitalocean.com/community/tutorials/an-introduction-to-oauth-2



This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

These answers are provided by our Community. If you find them useful, show some love by clicking the heart. If you run into issues leave a comment, or add your own answer to help others.
0

Accepted Answer

Hi there,

As far as I can tell based on what you’ve shared, it sounds like PKCE-only public clients might not be supported right now, as the token exchange requires a client_secret. Though I might be wrong.

It might be best to reach out to support and share your use case. The DigitalOcean product team would probably be interested in hearing about these scenarios, and they can give the most accurate guidance: https://www.digitalocean.com/support/

The developer cloud

Scale up as you grow — whether you're running one virtual machine or ten thousand.

Get started for free

Sign up and get $200 in credit for your first 60 days with DigitalOcean.*

*This promotional offer applies to new accounts only.