Secrets
The Secrets API provides encrypted key-value storage for sensitive configuration values such as API keys, tokens, and credentials. Secrets are scoped to organizations and encrypted at rest using AES-256.
Overview
- Encryption: AES-256 with per-value random IV, stored as base64 in PostgreSQL
- Scoping: Secrets are automatically scoped to the organization via qualified naming (
org/{organizationId}/{secretName}) - Authorization: Users must be a member of the target organization
- Integration: Secrets can be referenced from Organization Configuration values for automatic resolution
GraphQL Schema
Mutations
setSecret
Creates or updates an encrypted secret for an organization.
mutation SetSecret($input: SetSecretInput!) {
setSecret(input: $input) {
setSecretResult {
secretName
}
}
}
input SetSecretInput {
organizationId: Int!
secretName: String!
secretValue: String!
}
Response Type:
type SetSecretPayload {
setSecretResult: SetSecretResult
}
type SetSecretResult {
secretName: String! # Qualified name: "org/{organizationId}/{secretName}"
}
Example:
mutation {
setSecret(
input: {
organizationId: 42
secretName: "CARRIER_API_KEY"
secretValue: "sk-abc123..."
}
) {
setSecretResult {
secretName
}
}
}
Response:
{
"data": {
"setSecret": {
"setSecretResult": {
"secretName": "org/42/CARRIER_API_KEY"
}
}
}
}
deleteSecret
Deletes a secret from the organization's secret store.
mutation DeleteSecret($input: DeleteSecretInput!) {
deleteSecret(input: $input) {
boolean
}
}
input DeleteSecretInput {
organizationId: Int!
secretName: String!
}
Example:
mutation {
deleteSecret(
input: {
organizationId: 42
secretName: "CARRIER_API_KEY"
}
) {
boolean
}
}
Response:
{
"data": {
"deleteSecret": {
"boolean": true
}
}
}
User-Scoped Secrets
In addition to organization-scoped secrets, each user can store personal secrets that are invisible to other users. User secrets are keyed as user/{currentUserId}/{secretName} and are derived entirely from the JWT — no organizationId argument is required or accepted.
The primary use case is storing a personal GitHub Personal Access Token (PAT) for the publish flow. When a user PAT is present, the GitHub client uses it in preference to the organization-level token or the global GITHUB_TOKEN.
Mutations
setUserSecret
Creates or updates a secret scoped to the currently authenticated user.
mutation {
setUserSecret(
secretName: String!
secretValue: String!
): SetUserSecretResult!
}
Response Type:
type SetUserSecretResult {
secretName: String! # Qualified name: "user/{currentUserId}/{secretName}"
}
Example:
mutation {
setUserSecret(
secretName: "github-pat"
secretValue: "ghp_abc123..."
) {
secretName
}
}
Response:
{
"data": {
"setUserSecret": {
"secretName": "user/7/github-pat"
}
}
}
deleteUserSecret
Deletes a secret scoped to the currently authenticated user.
mutation {
deleteUserSecret(
secretName: String!
): Boolean!
}
Example:
mutation {
deleteUserSecret(secretName: "github-pat")
}
Queries
hasUserSecret
Returns true if the currently authenticated user has stored a secret with the given name.
query {
hasUserSecret(secretName: String!): Boolean!
}
Example:
query {
hasUserSecret(secretName: "github-pat")
}
Response:
{
"data": {
"hasUserSecret": true
}
}
Validation Rules
| Field | Rule |
|---|---|
organizationId (org operations) | Must be greater than 0 |
secretName | Must not be empty |
secretValue (set operations) | Must not be empty |
Authorization
- Organization secrets: The authenticated user must have access to the specified
organizationId. Returns401 Unauthorizedif the user does not belong to the target organization. - User secrets: No organization membership check is required. The user ID is derived from the JWT; a user can only read or write their own secrets.
Usage with Organization Config
Secrets can be referenced in organization configuration values using secret reference syntax. The OrganizationConfigService automatically resolves these references at runtime, enabling secure storage of sensitive configuration without exposing plaintext values in the configuration store.
GitHub PAT Resolution Order
When the system builds a GitHub client, it resolves a token using the following priority:
- User PAT —
user/{currentUserId}/github-pat(set viasetUserSecret) - Organization token —
apps.github.tokenfrom the organization's configuration - Global environment variable —
GITHUB_TOKEN
This allows individual users to authenticate GitHub operations with their own PAT without changing organization-level settings.