Skip to Content
We are live but in Staging 🎉

Credentials — API Reference

Package: dodil.k3.source.v1 · Service: SourceService

Credentials are org-scoped (not bucket-scoped) and may optionally link to a source_id. Five credential types, discriminated by CredentialType and a oneof credential_data payload — see Core Concepts → Credential.

Preview — the entire Credentials API surface, including the OAuth flow, is paired with external sources, which are Preview. The production internal-S3 path requires no credential. Shapes below reflect today’s API; expect refinements.

RPCHTTP
StoreCredentialPOST /admin/credentials
GetCredentialGET /admin/credentials/:credential_id
ListCredentialsGET /admin/credentials
DeleteCredentialDELETE /admin/credentials/:credential_id
ValidateCredentialPOST /admin/credentials/:credential_id/validate
GetOAuthUrlPOST /admin/oauth/authorize
ExchangeOAuthCodePOST /admin/oauth/token
RefreshOAuthTokenPOST /admin/credentials/:credential_id/refresh

Secrets are stored in HashiCorp Vault behind K3. ListCredentials only returns CredentialInfo (no secret payload); GetCredential returns the full payload for the credential you own.

gRPC setup — grpcurl, endpoints, reflection, and field-name casing — is covered once in Conventions → Using gRPC.

StoreCredential

Stores a credential directly. For OAuth providers, prefer the OAuth flow below — it handles redirect + code exchange end-to-end. Use this for API keys, PATs, service-account JSON keys, and access keys.

Request

GitHub PAT variant:

curl -sS -X POST "https://k3.dev.dodil.io/admin/credentials" \ -H "Authorization: Bearer $DODIL_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "provider": "SOURCE_PROVIDER_GITHUB", "credentialType": "CREDENTIAL_TYPE_PAT", "displayName": "github-readonly", "isPrimary": true, "pat": { "token": "ghp_...", "username": "dodil-bot" } }'

External S3 access-key variant:

curl -sS -X POST "https://k3.dev.dodil.io/admin/credentials" \ -H "Authorization: Bearer $DODIL_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "provider": "SOURCE_PROVIDER_INTERNAL_S3", "credentialType": "CREDENTIAL_TYPE_ACCESS_KEY", "displayName": "external-s3", "accessKey": { "accessKeyId": "AKIA...", "secretAccessKey": "wJalrXUt...", "region": "us-east-1", "endpoint": "https://s3.example.com" } }'

Response

{ "credentialId": "cred_a1b2..." }

GetCredential

Returns the credential’s CredentialInfo and (subject to authorization) its secret payload. Pass auto_refresh = true to refresh expired OAuth tokens before returning.

Request

curl -sS "https://k3.dev.dodil.io/admin/credentials/cred_a1b2...?auto_refresh=true" \ -H "Authorization: Bearer $DODIL_TOKEN"

Response

{ "info": { "credentialId": "cred_a1b2...", "sourceId": "src_a1b2...", "provider": "SOURCE_PROVIDER_GOOGLE_DRIVE", "credentialType": "CREDENTIAL_TYPE_OAUTH2", "displayName": "gdrive-main", "isPrimary": true, "isValid": true, "createdAt": "1716840000000", "updatedAt": "1716843600000", "expiresAt": "1716847200000" }, "oauth2": { "accessToken": "ya29....", "refreshToken": "1//...", "expiresAt": "1716847200000", "tokenType": "Bearer", "scopes": ["https://www.googleapis.com/auth/drive.readonly"] } }

ListCredentials

Returns CredentialInfo rows only — no secret payloads. Filter by source_id or provider.

Request

All credentials for Google Drive:

curl -sS "https://k3.dev.dodil.io/admin/credentials?provider=SOURCE_PROVIDER_GOOGLE_DRIVE" \ -H "Authorization: Bearer $DODIL_TOKEN"

All credentials linked to a specific source:

curl -sS "https://k3.dev.dodil.io/admin/credentials?source_id=src_a1b2..." \ -H "Authorization: Bearer $DODIL_TOKEN"

Response

{ "credentials": [ { "credentialId": "cred_a1b2...", "sourceId": "src_a1b2...", "provider": "SOURCE_PROVIDER_GOOGLE_DRIVE", "credentialType": "CREDENTIAL_TYPE_OAUTH2", "displayName": "gdrive-main", "isPrimary": true, "isValid": true, "createdAt": "1716840000000", "updatedAt": "1716843600000", "expiresAt": "1716847200000" } ] }

DeleteCredential

Request

curl -sS -X DELETE "https://k3.dev.dodil.io/admin/credentials/cred_a1b2..." \ -H "Authorization: Bearer $DODIL_TOKEN"

Response

Empty (DeleteCredentialResponse {}).

ValidateCredential

Live-checks the credential against the provider. For OAuth, this typically calls a low-cost provider endpoint to verify the token is still good; for API keys / PATs, it makes a token-info or ping call.

Request

curl -sS -X POST "https://k3.dev.dodil.io/admin/credentials/cred_a1b2.../validate" \ -H "Authorization: Bearer $DODIL_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "credentialId": "cred_a1b2..." }'

Response

{ "isValid": true, "errorMessage": "", "validatedAt": "1716843600000" }

OAuth flow

Three RPCs, one per stage of the standard OAuth authorization-code flow:

  1. GetOAuthUrl — your backend asks K3 for an authorization URL; K3 returns the URL with the right scopes + client ID for the provider.
  2. User redirect — your frontend redirects the user to that URL; the user authorizes; the provider redirects back to your redirect_uri with ?code=...&state=....
  3. ExchangeOAuthCode — your backend hands the code back to K3, which exchanges it for tokens and stores them as a credential. Returns the credential_id.

Later, RefreshOAuthToken refreshes expiring tokens — or use auto_refresh = true on GetCredential to do it implicitly.

GetOAuthUrl

Request

curl -sS -X POST "https://k3.dev.dodil.io/admin/oauth/authorize" \ -H "Authorization: Bearer $DODIL_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "provider": "SOURCE_PROVIDER_GOOGLE_DRIVE", "redirectUri": "https://app.example.com/k3/oauth/callback", "scopes": ["https://www.googleapis.com/auth/drive.readonly"], "state": "req-123" }'

Response

{ "authUrl": "https://accounts.google.com/o/oauth2/v2/auth?client_id=...", "state": "req-123" }

ExchangeOAuthCode

Request

curl -sS -X POST "https://k3.dev.dodil.io/admin/oauth/token" \ -H "Authorization: Bearer $DODIL_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "provider": "SOURCE_PROVIDER_GOOGLE_DRIVE", "code": "<oauth_code>", "redirectUri": "https://app.example.com/k3/oauth/callback", "state": "req-123", "displayName": "gdrive-main" }'

Response

{ "credentialId": "cred_a1b2..." }

RefreshOAuthToken

Request

curl -sS -X POST "https://k3.dev.dodil.io/admin/credentials/cred_a1b2.../refresh" \ -H "Authorization: Bearer $DODIL_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "credentialId": "cred_a1b2..." }'

Response

{ "success": true, "expiresAt": "1716847200000" }

See also