Skip to main content

Mobile Credentials & Vault

Vendor device farms (BrowserStack, Sauce Labs) require API credentials. The platform stores these once in the environment credential vault — encrypted at rest with AES-GCM — and references them from mobile apps by tag. No secrets in JSON.

This page covers the vendor-credential side. For app-login credentials (the usernames + passwords your test types into the app), see the test data section in YAML format.

The model

Environment

└─ auth_config (jsonb, AES-GCM encrypted)

├─ defaultCredentialTag: "prod-browserstack" ← env-level default

└─ credentials: [
{
tag: "prod-browserstack",
username: "alice@company.com",
password: "ABCDEF...", ← BrowserStack access key
isDefault: true
},
{
tag: "dev-saucelabs",
username: "company-dev",
password: "12345...",
isDefault: false
}
]

Mobile App

├─ cloud_provider: "BROWSERSTACK"
└─ cloud_config: { "credentialTag": "prod-browserstack", "deviceName": "Pixel 7" }

At job time the agent calls a vault-resolution endpoint with the mobile app id, the backend walks MobileApp → EnvironmentTarget → Environment → vault, finds the credential by tag, and returns the inline userName + accessKey to the agent.

Adding a vendor credential

In the environment's auth config, add a credential set:

{
"defaultCredentialTag": "prod-browserstack",
"credentials": [
{
"tag": "prod-browserstack",
"username": "your-bs-username",
"password": "your-bs-access-key",
"isDefault": true
}
]
}

Fields:

  • tag — referenced from cloud_config.credentialTag. Pick anything memorable (prod-bs, qa-saucelabs, team-a-bs).
  • username — BrowserStack/Sauce Labs username (typically your dashboard login email).
  • password — the vendor access key. Field is named password for compatibility with the rest of the vault, but for vendor APIs it's the access key.
  • isDefault — optional. When true, any app that doesn't specify credentialTag uses this one.

The password is AES-GCM encrypted before being written to the DB via the AuthConfigEntityListener.

Three reference patterns

1. Explicit tag (most explicit)

{
"credentialTag": "prod-browserstack",
"deviceName": "Google Pixel 7"
}

Wins over any default. Use when an app needs different credentials from the env default (e.g., a customer account vs. an internal account).

2. Default credential (implicit)

{
"deviceName": "Google Pixel 7"
}

No credentialTag, no inline creds. Agent uses the env's default credential — either:

  • The credential matching environment.defaultCredentialTag, OR
  • Any credential with isDefault: true

Most teams set one default per env so 90% of mobile apps don't need credential boilerplate.

3. Inline (legacy, back-compat)

{
"userName": "your-bs-username",
"accessKey": "your-bs-access-key",
"deviceName": "Google Pixel 7"
}

Passes through unchanged. The vault is bypassed. Avoid for new apps — secrets in JSON are harder to rotate and surface in any UI roundtrip that re-fetches the mobile app.

Precedence

What you setWhat the agent receives
Inline userName + accessKeyInline (no vault lookup)
credentialTag + matching vault entryResolved from vault
credentialTag + missing vault entryHard error — names the missing tag, lists available ones
No tag, no inline, but env has a defaultResolved from env default
No tag, no inline, no env defaultPass through; vendor validation surfaces "missing userName"

Rotating a credential

Update the vault entry's password field. Every mobile app pointing at that tag picks up the change on the next job — no app-level edit needed. Old in-flight tests continue with the old credential since the agent caches it for the duration of the test.

To force immediate rotation across all running tests: remove the old credential set, the next vault-resolution call fails fast, the agent surfaces an error in Job History, operator fixes.

Multiple environments

The vault is per-environment, so:

EnvironmentCredential tagUse case
Developmentdev-browserstackshared low-volume tier
Stagingstaging-browserstackmid-volume parallel tests
Productionprod-browserstackrelease-day matrix

Same mobile app can reference different tags depending on which environment it's targeting. The agent resolves against the environment that owns the EnvironmentTarget linked to the test job.

Secrets at runtime

After resolution, the inline creds exist only:

  • In-memory on the backend (during the single resolve call)
  • Over the wire from backend → agent (HTTPS in production)
  • In-memory on the agent (during driver creation)

They are not stored on disk, not in the agent's job-claim cache, not in MinIO. Each job re-resolves from the vault.

Audit trail

The vault already audits reads via CredentialAuditService. Every time a job resolves a tag, an audit entry is written: who (agent id) + when + which tag + which environment. View via the existing audit log endpoint or the Audit Logs UI page.

What's NOT in the vault yet

  • Per-app credential overrides — today's pattern is env-scoped. Some teams might want per-app credentials (e.g., team-A uses tag X, team-B uses tag Y in the same env). Today the workaround is multiple environments. Per-app tags are on the roadmap.
  • Credential rotation hooks — no UI for time-bound rotation policies. Manual rotation only.