Syndroodocsv0.7.2
WebsiteGitHubOverview
Syndroo is under active development. Documentation and CLI behavior may change, and features are not guaranteed to work reliably.

Credentials

For the local workflow, a credential is read once, validated against the provider's schema and stored by Core. Later publishing never re-reads the environment variable or file you imported. The optional self-hosted Server keeps deployment secrets in separate private state.

Two explicit sources

  • --from-env reads exactly SYNDROO_CREDENTIALS: one JSON object, at most 64 KiB.
  • --credential-file reads one private JSON file with the same object shape.

Passing both, or passing neither when the provider needs credentials, is refused. An interactive run at a terminal offers the same two sources plus field-by-field entry, where a field the provider marks as secret is read with echo disabled. A non-interactive run never guesses and never blocks.

Field names by provider

ProviderCredential objectSecret fields
Blueskyidentifier, password (both required)password
Threadsclient_id, client_secret (both required)client_secret
LinkedInclient_id, client_secret (both required)client_secret
Mastodon{}: the accepted object is emptyNone: browser authorization
DEV.toapiKey (required)apiKey

Unknown keys in the credential object are refused, because every provider's credential schema sets additionalProperties to false.

# Bluesky
export SYNDROO_CREDENTIALS='{"identifier":"you.bsky.social","password":"APP_PASSWORD_PLACEHOLDER"}'

# DEV.to
export SYNDROO_CREDENTIALS='{"apiKey":"DEV_TO_API_KEY_PLACEHOLDER"}'

App clients are connect options, not credentials

LinkedIn, Threads and Mastodon accept their app client through the connect options of the request document, which is how a machine caller skips an interactive prompt:

ProviderRequired connect optionsOptional connect options
BlueskyNoneNone
DEV.toNoneNone
LinkedInredirectUriclientId, clientSecret, scopes
ThreadsredirectUriclientId, clientSecret, apiHost, authorizationHost, scopes
Mastodoninstance, redirectUri, scopesclientId, clientSecret

Server credentials

Self-hosted Server. Server setup uses @syndroo/cli and @syndroo/cloudflare. The Server flow does not use the local SYNDROO_CREDENTIALS import described above.

server connect threads reads the App Secret through hidden terminal input, THREADS_APP_SECRET or --app-secret-stdin. Cloudflare authentication comes from the existing Wrangler login. The scoped CI bearer is stored privately or can be supplied through --ci-token-stdin when setup requests recovery.

Never put the App Secret, CI bearer, Cloudflare admin bearer, SECRET_KEY or RUNTIME_KEY in a command argument, log, chat message or repository file. Deployment credentials can be imported together with server deploy --yes --credentials-stdin using protected input. See Deploy a server and the Server command reference.

After a credential is stored

Core keeps the credential in the local credential store and records a reference on the connection; a plugin receives only what its own operation needs. Publishing does not depend on the environment variable or the import file still existing, so the file can be deleted once the connection works.

A stored credential is released when the connection is disconnected. Disconnecting removes the local record only: Syndroo never revokes a platform credential, so revoke it at the platform as well. Each platform guide says what is documented for its revocation.

Local browser authorization

LinkedIn, Threads and Mastodon connect with an authorization action that a browser completes. The local CLI finishes that OAuth callback itself for all three. With --redirect-uri it binds exactly that loopback host, port and path in-process and consumes one redirect; the default is a pre-registerable loopback URI, and the bind needs a controlling terminal, so without one the run reports the pending action and exits 0. With --callback-url - it reads the redirected URL from standard input instead. A callback URL that carries code or state is refused on the command line as CALLBACK_URL_INVALID, because a secret must not reach the argument vector. This local callback path is verified by fixture tests against local HTTP servers only; no live LinkedIn, Threads or Mastodon account was connected.