wif.tax

DigitalOcean

D DigitalOcean API (Droplets and GPU Droplets, DOKS, Spaces, Container Registry, App Platform, Gradient AI)

Every automated path into DigitalOcean (API, doctl, Terraform, registry logins, DOKS kubeconfigs) starts from a personal access token made by hand in the Control Panel. Tokens can carry custom scopes, show last use and are covered by GitHub secret scanning, but nothing forces an expiry and there is no API to mint or rotate them. No federation from GitHub Actions or any other issuer. Spaces keys are static too. Paperspace has its own card.

Docs: docs.digitalocean.com · Checked 2026-10-22 · source YAML · dispute via PR

Inbound D

How a workload running anywhere authenticates to this product.

A static personal access token (PAT) created in the Control Panel, sent as a bearer token to api.digitalocean.com and used by doctl, Terraform, docker login to registry.digitalocean.com and DOKS kubeconfig generation. Spaces object storage uses separate static S3-style access keys. No documented OIDC or workload identity exchange into the API.

Graded on the weakest path a workload must use, which is the control-plane PAT: Spaces keys, registry credentials and DOKS OAuth tokens are all minted from it or beside it, and are static themselves. DOKS cluster SSO accepts an OIDC issuer, but it is a browser login for people and only covers kubectl against one cluster, so it does not lift the grade (rubric: federation must be documented for workloads). The OAuth API is an authorization-code flow for third-party apps (30-day access tokens, single-use refresh tokens, client secret for confidential clients); at best that is a static root (C), and it needs a person to authorize it. DigitalOcean's security team published a three-part blog series building workload identity federation for Droplets and GitHub Actions on top of that OAuth API, but it is an open-source proof of concept the customer deploys and runs, not a platform feature, so it is noted and not credited. What would move this to B or A: a token-exchange endpoint on cloud.digitalocean.com that trusts GitHub Actions (B) or any configured OIDC issuer (A) and returns a short-lived, scoped API token. Hygiene passes 3 of 5, so D.

Outbound B

How this product reaches into your cloud, repos, or other SaaS.

App Platform pulls source from GitHub, GitLab and Bitbucket after the user grants the repository service access, and Knowledge Bases connect Dropbox by OAuth; both keyless. Knowledge Bases index Amazon S3 only with a pasted IAM access key and secret, and App Platform pulls private Docker Hub and GHCR images with a pasted username:token.

Checked: App Platform Git sources (GitHub, GitLab, Bitbucket; consent, keyless) and container sources (DOCR native; Docker Hub and GHCR by pasted username:token, with DigitalOcean recommending a non-expiring token); Knowledge Bases data sources (Spaces native, web crawl of public URLs, Dropbox by OAuth consent, Amazon S3 by pasted IAM access key with no least-privilege or rotation guidance); custom image import (public URL download, no credential); Spaces migration (a third-party tool, Flexify.IO, not DigitalOcean reaching in). No integration uses an AWS role, GCP impersonation or Azure federated credential. B rests on the rubric's rule that consent apps count as keyless; the only cloud integration (S3) is a pasted static key, so a reviewer reading B as "keyless on a cloud" would put this at F. Gradient AI and GPU Droplet docs describe no other reach-in.

Hygiene for any static credential the product still issues

✗ Expiry enforceable
PATs take an expiration chosen by the creator. The public docs do not list the options or a default, and no team setting caps token lifetime (team settings cover contact emails, secure sign-in and SSO only). doctl documents minting API tokens that never expire, and Spaces access keys document no expiry at all. A changeable default is not an enforced expiry (precedent: temporal.yaml, coreweave-object-storage.yaml).
✗ Rotation via API
The API reference (and DigitalOcean's public OpenAPI spec) has no endpoint to create, list or revoke personal access tokens; regenerate and delete live in the Control Panel menu. The scopes page mentions "creating tokens through the API" but no such endpoint is published. Spaces keys do have create/delete endpoints (the Spaces how-to page still says they cannot be managed by API, which is out of date), and `doctl registries login` mints registry tokens, but both run on an existing PAT. Rotating the root credential needs a browser.
✓ Scoped keys
A PAT can be cut down to individual resource-type CRUD scopes, which meets the rubric's "subset of permissions". It is still a token belonging to a person (custom scopes are capped by that user's team role and the token dies with them); DigitalOcean has no service-account or API-only principal. Scopes are per resource type, not per resource, and the registry pull secret applies to every registry on the account. Spaces keys can be limited per bucket.
  • docs.digitalocean.com checked 2026-10-22
    “Custom scopes grant more specific permissions, like only creating Droplets or updating cloud firewalls, which lets you secure your workflows by granting only the permissions the token needs and restricting access to other resources and actions.”
  • docs.digitalocean.com checked 2026-10-22
    “View and download Kubernetes cluster credentials”
  • docs.digitalocean.com checked 2026-10-22
    “Limited access allows you to grant permissions for specific buckets.”
✓ Last-used visible
The token list shows last-used status; the quote is the documented description of the token table screenshot. Not documented for Spaces access keys.
  • docs.digitalocean.com checked 2026-10-22
    “Personal access tokens table showing token name, number of scopes, creation time, last used status, and expiration date.”
  • docs.digitalocean.com checked 2026-10-22
    “You can click the entry in the Scopes column to view details about the token’s usage and scopes.”
✓ Leak revocation
The first ✓ is GitHub's Partner column. Personal access, OAuth, refresh and system tokens are all partner patterns. Spaces access keys do not appear in the table.
  • docs.github.com checked 2026-10-22
    “| DigitalOcean | DigitalOcean Personal Access Token | digitalocean_personal_access_token | ✓ | ✓ | ✓ | ✓ | ✓ | ✗ |”
  • docs.github.com checked 2026-10-22
    “| DigitalOcean | DigitalOcean OAuth Token | digitalocean_oauth_token | ✓ | ✓ | ✓ | ✓ | ✓ | ✗ |”
  • docs.github.com checked 2026-10-22
    “| DigitalOcean | DigitalOcean Refresh Token | digitalocean_refresh_token | ✓ | ✓ | ✓ | ✗ | ✗ | ✗ |”

Notes

One card for the DigitalOcean control plane and the data planes reached with its credentials (Spaces, Container Registry, DOKS kubeconfigs), since all of them bootstrap from the same PAT; splitting Spaces would not change its grade (static keys, no expiry, per-bucket scoping, API create/delete). Paperspace (now part of DigitalOcean) still has its own console and team API keys and is graded on the paperspace card. The fix list: a federated token exchange for GitHub Actions and arbitrary OIDC issuers (DigitalOcean's own PoC shows the shape), an API to create and revoke PATs, a team policy that caps token lifetime, and a non-human principal to own tokens.

Badge

wif.tax grade D

[![wif.tax grade](https://wif.tax/badge/digitalocean-api.svg)](https://wif.tax/p/digitalocean-api/)