The Credentials API returns a connected service's credential to an authorized backend. STACK stores customer credentials with AWS KMS envelope encryption and decrypts them in memory when an authorized retrieval or proxy request needs them. A direct retrieval writes a credential.retrieve entry to the operator's audit chain.
Credentials are sensitive secrets (API keys, OAuth tokens, passwords). They are returned in plaintext over TLS. Ensure your application handles them securely - do not log them, store them in plaintext, or expose them to untrusted contexts.
These endpoints accept an operator API key or a user OAuth access token. Operator keys are account-wide. A member's OAuth token remains subject to that member's allowed_connections restrictions.
Retrieve the decrypted credential for a connected service, identified by its provider key (e.g., slack, openai,custom_internal_crm). If you have multiple connections to the same provider, use the /by-connection/:connectionId endpoint instead.
curl https://api.getstack.run/v1/credentials/openai \
-H "Authorization: Bearer sk_live_op_abc123"For services connected with a single API key or token, the response includes a credential string field:
{
"provider": "openai",
"credential": "YOUR_PROVIDER_API_KEY"
}For services connected with multiple credential fields (e.g., custom services with username + password, or host + port + key), the response includes a credentials object:
{
"provider": "custom_sftp_server",
"credentials": {
"host": "sftp.example.com",
"username": "stack-agent",
"password": "s3cur3p4ss",
"port": "22"
}
}For OAuth-connected services, the credential is the access token granted during the OAuth flow:
{
"provider": "slack",
"credential": "xoxb-1234567890-1234567890123-abc123def456ghi789jkl012"
}Retrieve a decrypted credential by connection ID. This is the recommended approach when an operator has multiple connections to the same provider (e.g., two separate Slack workspaces or multiple AWS accounts).
curl https://api.getstack.run/v1/credentials/by-connection/conn_8mR4xK9wN2 \
-H "Authorization: Bearer sk_live_op_abc123"{
"provider": "slack",
"connection_id": "conn_8mR4xK9wN2",
"credential": "xoxb-1234567890-1234567890123-abc123def456ghi789jkl012"
}A member can have an allowed_connections list that restricts which service credentials their session can access. Requests outside that list return403 Forbidden.
# The signed-in member is limited to two connection IDs
curl https://api.getstack.run/v1/credentials/openai \
-H "Authorization: Bearer $STACK_OAUTH_TOKEN"{
"error": {
"code": "FORBIDDEN",
"message": "You do not have access to this service connection"
}
}Operators and admins can manage member access restrictions via the PATCH /v1/team/members/:id endpoint or through the dashboard team settings.
The Credentials API implements multiple layers of security to protect stored secrets:
Every successful direct retrieval records the action, outcome, operator, request trace, duration and hash-chain links. When the request carries an agent or Passport context, the same row includes those identifiers.
{
"entry_id": "aud_abc123",
"operator_id": "op_abc123",
"agent_id": "system",
"passport_jti": "none",
"layer": "vault",
"action": "credential.retrieve",
"outcome": "success",
"prev_entry_hash": "...",
"entry_hash": "..."
}The audit log is hash-chained - each entry includes a hash of the previous entry, making tampering detectable. Audit entries cannot be updated or deleted.
Use direct retrieval only in a trusted backend that is allowed to handle the upstream secret. An agent that should not see the credential must use the proxy instead.
// Trusted backend retrieves the credential on demand
const response = await fetch('https://api.getstack.run/v1/credentials/openai', {
headers: { 'Authorization': 'Bearer ' + process.env.STACK_API_KEY }
});
const { credential } = await response.json();
// Use it immediately
const completion = await fetch('https://api.openai.com/v1/chat/completions', {
method: 'POST',
headers: {
'Authorization': `Bearer ${credential}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: 'gpt-4',
messages: [{ role: 'user', content: 'Hello' }]
})
});
// Do not log or persist the credential.The public MCP surface does not return decrypted credentials or accept custom secrets. Connect providers in the Console or provider browser flow. Use the STACK proxy when an MCP client needs to call a connected service.
Direct credential retrieval remains an API capability for explicitly configured runtimes. Proxy-only agents cannot use it.