Appearance
Connections and Identity
This page covers two Explorer screens. Connections holds the named records of outside systems that flows, triggers, queues and synchronizations call. LDAP / SSO holds the sign-in providers that let people use an existing company account, plus SCIM provisioning. Both are administered by integration owners and tenant administrators. For the vocabulary used here (connection, connector, provider account) see Overview.
Connections
A connection records where an outside system lives, how the platform signs in to it, and the secret needed to do so. Flows refer to a connection by its code, so an address or credential changes in one place. One connection can also name a sandbox connection that is used when a flow is tested.
Where to find it
Studio Explorer > Workspace > Integrations > Connections. Page key integration-connections. The Integration Flows screen also has a simpler Connections tab that creates REST connections only; this screen is the complete one.
Key concepts
| Term | Meaning |
|---|---|
| Code | The identifier flows use. Lower-case letters, digits and dashes, derived from the name; fixed after creation. |
| Connection type | REST (default), DATABASE, SFTP, GRAPHQL, SOAP, KAFKA, RABBITMQ, SQS, AZURE_SERVICEBUS, GCP_PUBSUB. Stored in the connectionType field. |
| Sign-in (auth type) | How the platform authenticates. See the table below. |
| Sandbox connection | A second connection used instead of this one when a flow is tested from the designer. Live runs never use it. |
| Token state | For OAuth 2 connections, the condition of the access token. |
Add connection dialog
The dialog opens with a card per kind. Choosing a card sets the sign-in and the fields that follow. The kinds are:
| Card | Auth type saved | Connection type saved | Purpose |
|---|---|---|---|
| API key | API_KEY | REST | A key sent in a header. |
| Bearer token | BEARER | REST | Authorization: Bearer token. |
| Username and password | BASIC | REST | HTTP basic authentication. |
| OAuth 2 (client credentials) | OAUTH2_CLIENT_CREDENTIALS | REST | Server-to-server token from a token address. |
| OAuth 2 (a person signs in) | OAUTH2_AUTHORIZATION_CODE | REST | Acts on a person's account at a provider after one approval. |
| No authentication | NONE | REST | A public address. |
| SFTP with a password | PASSWORD | SFTP | Files on an SFTP server. |
| SFTP with an SSH key | SSH_KEY | SFTP | Files on an SFTP server, private key sign-in. |
| PostgreSQL database | PASSWORD | DATABASE | Database reads and writes from flows. |
| Kafka, RabbitMQ, Amazon SQS, Azure Service Bus, Google Cloud Pub/Sub | PASSWORD | KAFKA, RABBITMQ, SQS, AZURE_SERVICEBUS, GCP_PUBSUB | A broker a queue can be bridged to. |
Fields common to every kind
| Field | Type | Default | Required | Description |
|---|---|---|---|---|
| Name | text | empty | Yes | Display name. The code is generated from it while the connection is new. |
| Code | text | slug of the name | Yes | "Flows refer to the connection by this code." Disabled when editing. |
| When testing a flow, use | select | "This same connection" | No | Another connection to use for tests. Helper text: "Choose a sandbox connection so tests never touch the live system. Live runs always use this connection." A connection cannot be its own test connection. |
REST kinds (API key, Bearer, Basic, OAuth 2, None)
| Field | Applies to | Default | Required | Description |
|---|---|---|---|---|
| Address | all REST kinds | empty | Yes | Base address, for example https://api.example.com. Step paths are appended to it. |
| Header name | API key | X-Api-Key | Yes | Header that carries the key. Saved as authConfig.headerName. |
| Username | Basic | empty | Yes | Saved as authConfig.username. |
| API key / Token / Password | API key, Bearer, Basic | empty | Yes on create | Secret. "Stored on the server and never shown again." When editing: "Leave empty to keep the stored value." |
OAuth 2 kinds
| Field | Applies to | Default | Required | Description |
|---|---|---|---|---|
| Sign-in address | person signs in | empty | Yes | Where the provider asks the person to approve access. authConfig.authUrl. |
| Extra sign-in fields | person signs in | access_type=offline | No | One name=value per line, added to the sign-in request. A line without a key shows "Line N needs a key, then =, then the value." Many providers need access_type=offline (Google) or offline_access in the scope (Microsoft) to give a refresh token. |
| Revocation address | person signs in | empty | No | Called when the connection is disconnected. |
| Token address | both | empty | Yes | Must be https. "A token is fetched when needed, renewed before it expires, and shared by every server." |
| Client ID | both | empty | Yes | |
| Scope | both | empty | No | |
| Audience | both | empty | No | |
| Send the client secret | both | As a sign-in header | Yes | basic (header, most providers) or body (request body). Saved as clientAuth. |
| Request format | both | Form (standard) | Yes | form or json. Saved as requestFormat. |
| Client secret | both | empty | Required for client credentials; optional for a public client in the person-signs-in kind |
For the person-signs-in kind the dialog shows the return address to register with the provider: the Studio origin followed by /app/admin/studio/oauth-callback.
When an OAuth 2 connection is opened for editing the dialog shows the token state and a button: Connect or Reconnect and Disconnect (person signs in), or Get a new token now (client credentials).
| Token state | Colour | Text |
|---|---|---|
VALID | green | "Token valid until HH:MM", with "Connected by NAME" when known |
EXPIRING | amber | "Token ends at HH:MM, renewing" |
NOT_CONNECTED | amber | "Not connected yet. Press Connect to sign in." |
FAILED | red | "Could not get a token: REASON" |
NEEDS_RECONNECT | red | "The sign-in was withdrawn. Connect again." |
| other | grey | "No token yet. One is fetched on first use." |
SFTP kinds
| Field | Default | Required | Description |
|---|---|---|---|
| Server | empty | Yes | Host name. |
| Port | 22 | Yes | Digits only, up to five. The saved address is sftp://host:port/ (port omitted when 22). |
| Username | empty | Yes | Saved as authConfig.username. |
| Password / Private key | empty | Yes on create | The key field is a multi-line text box. |
| Passphrase of the key | empty | Only if the key has one | Kept encrypted together with the key. If a passphrase is entered the key must be pasted again ("Paste the private key again with its passphrase."). |
| Server identity | not trusted | n/a | Editing only. Show the server's fingerprint reads the host key; Trust this server pins it. "Nothing is sent to a server until you have confirmed who it is." If the key changed the page warns "This is not the key that was trusted (FINGERPRINT). Trust it only if the change is expected." |
PostgreSQL database
| Field | Default | Required | Description |
|---|---|---|---|
| Server | empty | Yes | |
| Port | 5432 | Yes | |
| Database | empty | Yes | |
| Secure connection | Encrypted (require) | Yes | require, verify-ca, verify-full or disable. Saved as authConfig.sslmode. Use verify-full when the server has a certificate you trust; disable only inside a network you control. |
| Username | empty | Yes | |
| Password | empty | Yes on create |
The saved address is postgresql://user@host[:port]/database. Flows use the connection through the db.query and db.write actions. See Integration Flows.
Message brokers
| Field | Applies to | Description |
|---|---|---|
| Servers | Kafka | Comma-separated host:port list. Required. |
| Security | Kafka | PLAINTEXT (default), SSL, SASL_PLAINTEXT, SASL_SSL. |
| Sign-in method | Kafka with SASL | PLAIN (default), SCRAM-SHA-256, SCRAM-SHA-512, OAUTHBEARER. With OAUTHBEARER the Token address (https), Client ID and optional Scope are required and the secret is the client secret. |
| Certificate authority | Kafka with SSL | Optional PEM, for a broker certificate issued by your own authority. |
| Client certificate | Kafka with SSL | Optional PEM chain; the secret is then its private key (PKCS#8 PEM). |
| Address | RabbitMQ | amqp:// or amqps://, host, port and virtual host. Required. |
| Namespace address | Azure Service Bus | The https namespace address. Required. |
| Shared-access policy name / key | Azure Service Bus | Name is required; the key is the secret. |
| Endpoint | Amazon SQS | Only for a compatible or private endpoint. |
| AWS region, Access key id, Secret access key | Amazon SQS | Region and access key id are required. |
| Google Cloud project id | Pub/Sub | Required. The secret is the service-account key file (JSON); empty only for the local emulator. |
| Username / Password | RabbitMQ, Kafka SASL | Password is required when a username is given (RabbitMQ) or when the security needs sign-in. |
Brokers carry messages for a queue only. Retries, dead messages and replay work as on any queue. See Queues. Kafka mutual TLS, OAUTHBEARER, Azure Service Bus and Pub/Sub were checked against local stand-ins only, not against the real services.
Save rules
The Save connection button is enabled when the name and code are present; a secret is present on create (except None, person-signs-in OAuth and brokers that sign in without one); the SFTP host, username and port are valid; the person-signs-in kind has a sign-in address and valid extra fields; and the broker-specific required fields above are filled.
Grid
| Column | Content |
|---|---|
| Connection | Name and code. |
| Address | Base address. |
| Sign-in | Auth type chip, with a "credentials set" chip when a secret is stored. |
| OAuth token | Token state for OAuth 2 connections, otherwise a dash. |
| Tests use | The sandbox connection code, or "Same connection". |
| Last test | The result of the last test in this session: message and latency in ms, or "Not tested". |
Chips above the grid: Connections, With credentials, Tested OK, Test failed.
Actions
| Action | Effect | API |
|---|---|---|
| Add connection | Opens the dialog. | |
| Save connection | Creates or updates by code. If the sandbox choice changed it also sets the test connection. A saved change to the address, client id or secret discards the cached OAuth token. | POST /api/v1/integration/connections, PUT /api/v1/integration/connections/{code}/test-connection |
| Test (row) | Chooses the test by type: broker connections call the broker test, SFTP calls the SFTP test, DATABASE calls the database test, everything else a REST test. | POST .../{code}/broker/test, .../sftp/test, .../database/test, .../test |
| Delete (row) | Removes the connection and its cached token. | DELETE /api/v1/integration/connections/{code} |
| Connect, Reconnect | Starts the OAuth sign-in and sends the browser to the provider. | POST .../{code}/oauth/authorize |
| Disconnect | Forgets the approval and asks the provider to revoke it when it can. | POST .../{code}/oauth/disconnect |
| Get a new token now | Discards the cached token and fetches a new one. A refusal returns 502 with the reason. | POST .../{code}/token/refresh |
| Show the server's fingerprint, Trust this server | Reads and pins the SFTP host key. | POST .../{code}/sftp/host-key, .../sftp/trust |
The REST test makes one bounded GET to the address with the credentials applied. Results: "Connected (HTTP N)."; "The address answered, but the credentials were rejected (HTTP 401 or 403)."; "The address answered with a server error (HTTP N)."; "Could not reach the address: ERROR"; "Testing is available for REST connections; this one is TYPE." is returned when the generic test endpoint is called for a connection that is not REST; Studio avoids this by choosing the matching test per type. Address problems return messages such as "The address must use https." and "The address points to a private or internal network, which is not allowed."
Procedure: add a client-credentials connection
- Select Add connection and the card OAuth 2 (client credentials).
- Enter Name
Acme CRM. The code becomesacme-crm. - Enter Address
https://api.acme.example, Token addresshttps://login.acme.example/oauth/token, Client IDspark-prod, Scopecontacts.read. - Leave Send the client secret on "As a sign-in header" and Request format on "Form (standard)". Enter the Client secret.
- Select Save connection. Reopen the row and select Get a new token now. The chip should read "Token valid until ...".
- Select Test on the row. The Last test column shows "Connected (HTTP 200)." with the latency.
Statuses
Connections have no lifecycle. Test results and token states above are the only states.
Permissions
integration.flow / view lists connections and reads token status. integration.flow / manage saves, deletes, tests, refreshes tokens, signs in and out, and pins SFTP host keys. Without them the call returns 403 and the screen shows the message.
API and CLI
http
POST /api/v1/integration/connections
X-Tenant-Id: 1
Content-Type: application/json
{
"connectionCode": "acme-crm",
"name": "Acme CRM",
"baseUrl": "https://api.acme.example",
"authType": "OAUTH2_CLIENT_CREDENTIALS",
"authConfig": {
"tokenUrl": "https://login.acme.example/oauth/token",
"clientId": "spark-prod",
"clientAuth": "basic",
"requestFormat": "form",
"scope": "contacts.read"
},
"secret": "client-secret-value",
"connectionType": "REST"
}The response is the connection without its secret: connectionCode, name, baseUrl, authType, authConfigJson, hasSecret, connectionType, testConnectionCode, createdAt, updatedAt. Other calls: GET /api/v1/integration/connections/{code}/token-status (OAuth only, otherwise 400 "this connection does not use OAuth 2"), POST /api/v1/integration/connections/import-openapi with openApiJson and optional baseUrlOverride (JSON OpenAPI only).
| Command | Purpose |
|---|---|
erp connection list | Type, code, secret presence and name for every connection. |
erp connection save <code> --name <name> --base-url <url> [--type REST|DATABASE|SFTP|KAFKA|RABBITMQ|SQS|AZURE_SERVICEBUS|GCP_PUBSUB] [--auth-type NONE|PASSWORD|BEARER|...] [--auth-config <json>] [--secret-from-file <path>] | Create or update. The secret is read from a file, never an argument. |
erp connection test <code> | REST test. |
erp connection broker-test <code> [--destination <topic-or-queue>] | Broker test, optionally against one destination. |
Limits and behaviour
- Tokens are fetched when needed, renewed before expiry and shared across server instances.
- The sandbox connection applies to designer tests only.
- Addresses on private networks are refused unless the operator allows them (see Overview).
- A passphrase left in an older connection's settings is never returned.
Errors and troubleshooting
| Message or symptom | Cause | Fix |
|---|---|---|
| "a connection cannot be its own test connection" | The sandbox choice equals the connection. | Choose another connection. |
| "the test connection "X" does not exist" | The sandbox code was deleted. | Choose an existing connection. |
| "this connection does not use OAuth 2" | Token status or refresh on another auth type. | Use an OAuth 2 connection. |
| Could not get a token: ... | The token address refused the client. | Check client id, secret, scope and request format; then Get a new token now. |
| The credentials were rejected (HTTP 401) | Secret expired or wrong. | Edit the connection and enter the new secret. |
| The address points to a private or internal network | Host resolves to a private range. | Use a public address, or ask the operator to allow private endpoints. |
LDAP / SSO
The screen is titled SSO Providers. It manages OpenID Connect sign-in providers, the role mapping from a provider's group values to platform roles, and SCIM provisioning for the tenant. LDAP directory accounts are configured on the External Connectors screen, tab LDAP: see External Connectors. Per the integration contract note, an LDAP account can test the service bind, find users and verify a password, but it is not wired into the login page in this release.
Where to find it
Studio Explorer > Workspace > Integrations > LDAP / SSO. Page key sso-providers.
Key concepts
| Term | Meaning |
|---|---|
| Provider | One configured OpenID Connect identity provider (Microsoft Entra ID, Google, Okta, Auth0, Keycloak, OneLogin, Ping Identity, Amazon Cognito, Oracle IAM, SAP Cloud Identity or any generic OIDC provider). |
| Issuer address | The provider's OpenID address. Find endpoints reads its discovery document and fills the sign-in, token and user-info endpoints. |
| Redirect address | The address the provider sends the browser back to, <origin>/api/v1/auth/sso/<id>/callback. Register it in the provider. |
| Role mapping | External group or claim value to platform role. With no mapping the claim value is used as the role name. |
| SCIM | A standard API at /scim/v2/Users and /scim/v2/Groups that lets an HR or identity system push user and group changes. |
Add a sign-in provider (three steps)
Step 1, choose the provider. Step 2, set it up. Step 3, a confirmation with the redirect address.
| Field | Type | Default | Required | Description |
|---|---|---|---|---|
| Name shown on the sign-in button | text | "Sign in with PROVIDER" | Yes | |
| Issuer address | text | empty | Yes for every provider except Microsoft and Google | Each provider shows an example, such as https://your-company.okta.com, https://keycloak.example.com/realms/your-realm or https://cognito-idp.REGION.amazonaws.com/POOL-ID. |
| Authorization endpoint, Token endpoint, User info endpoint | text | filled by Find endpoints | Only for "Other (OpenID Connect)" when the provider has no discovery document | Opened with "My provider has no discovery document: enter endpoints by hand". All three are then required. |
| Client ID | text | empty | Yes | |
| Client secret | password | empty | Yes | Has a show and hide toggle. Stored write-only. |
| Scopes | text | openid email profile | No | Under "Show optional settings". |
| Role or group claim | text | groups for Microsoft, Okta, Keycloak | No | The claim that carries the person's groups. |
| Email domains | text | empty | No | Comma-separated. People with these domains are sent to this provider automatically. |
Save provider is enabled when a provider is chosen, the name, client id and client secret are present, and endpoints are known (discovered or entered). The discovery failure message is shown as a warning. After saving, the dialog shows the redirect address with a copy button and the instruction "Turn the provider on" with the switch in the list.
Grid and row panel
Columns: Provider (name and client ID), Type, Email domains, Status (enabled or disabled). Each row has an enable switch and a delete button. Expanding a row shows the redirect address (read only, with copy), Preview sign-in address (the address the sign-in would redirect to, to check set-up), and the Role Mapping editor: two fields "External value (e.g. ERP-Managers)" and "SparkERP role (e.g. Manager)" and Add mapping. A disabled provider genuinely refuses sign-in.
SCIM Provisioning panel
A switch for Enabled or Disabled, a chip "Token issued" or "No token yet", and Generate bearer token or Regenerate bearer token. The token is shown once ("Copy this now - it will not be shown again"); regenerating invalidates the old one.
Procedure: add Okta
- Select Add provider and Okta.
- Keep the name "Sign in with Okta". Enter the issuer
https://acme.okta.com/oauth2/defaultand select Find endpoints. A green panel lists the sign-in, token and user-info endpoints. - Enter Client ID and Client secret. Open the optional settings and set Email domains to
acme.com. - Select Save provider. Copy the redirect address into the Okta application.
- Turn the provider on with the switch. Expand the row and add a mapping
ERP-ManagerstoManager.
Permissions
Creating, discovering, enabling, disabling and deleting providers, writing role mappings and changing SCIM settings require the authoring capability AUTHOR on the artifact type sso-provider. Listing providers, reading role mappings and previewing the sign-in address do not check a permission. Without the capability the call returns 403.
API and CLI
| Purpose | Request |
|---|---|
| Discover | POST /api/v1/sso-providers/discover with {"issuer":"..."} |
| List, get | GET /api/v1/sso-providers, GET /api/v1/sso-providers/{id} (secrets redacted) |
| Create | POST /api/v1/sso-providers with providerType, displayName, issuer, clientId, clientSecret, redirectBaseUrl, optional scopes, roleClaim, emailDomains, endpoints |
| Enable, disable | PUT /api/v1/sso-providers/{id}/enable, .../disable |
| Delete | DELETE /api/v1/sso-providers/{id} |
| Preview | GET /api/v1/sso-providers/{id}/preview-authorization-url |
| Role mappings | GET/POST /api/v1/sso-providers/{id}/role-mappings (externalValue, internalRole), DELETE /api/v1/sso-providers/role-mappings/{mappingId} |
| SCIM | GET /api/v1/scim-config, PUT .../enable, PUT .../disable, POST .../regenerate-token |
| Public | POST /api/v1/auth/sso/discover (email discovery), GET /api/v1/auth/sso/{id}/start, GET /api/v1/auth/sso/{id}/callback, GET /api/v1/auth/sso/providers (secret-free list) |
Provider types accepted by the API: MICROSOFT, GOOGLE, OKTA, AUTH0, KEYCLOAK, ONELOGIN, PING_IDENTITY, AMAZON_COGNITO, ORACLE_IAM, SAP_CLOUD_IDENTITY, GENERIC_OIDC (the default). There is no erp command for SSO providers.
json
{
"providerType": "OKTA",
"displayName": "Sign in with Okta",
"issuer": "https://acme.okta.com/oauth2/default",
"clientId": "0oa1b2c3d4",
"clientSecret": "replace-me",
"redirectBaseUrl": "https://erp.acme.example",
"scopes": "openid email profile groups",
"roleClaim": "groups",
"emailDomains": "acme.com"
}Errors and troubleshooting
| Message or symptom | Cause | Fix |
|---|---|---|
| "authorizationEndpoint is required for this provider type (no fixed default exists)" (also tokenEndpoint, userinfoEndpoint) | A generic provider saved without endpoints. | Use Find endpoints or enter all three by hand. |
| A discovery warning under the issuer field | The issuer address is wrong or publishes no discovery document. | Check the address (Okta custom servers need /oauth2/NAME); for a generic provider enter endpoints by hand. |
| Sign-in refused for a saved provider | The provider is disabled. | Turn on the switch. |
| The person signs in with no roles | No role mapping and the claim value is not a role name. | Add role mappings. |
