Connector manifest
manifest.json declares everything about a connector. HTTP connectors write it by hand; LDAP, SCIM,
SQL and flat-file connectors have it derived from their definition.json. This page lists every field.
The JSON Schema is the machine-readable
form, and Validation issues lists the rules that tie the manifest to your
handlers.
Top level
| Field | Type | Required | Meaning |
|---|---|---|---|
key | string | yes | The connector's key: lowercase letters, digits, _ and -, starting with a letter or digit. Cannot change. |
version | integer | yes | The major version, from 1. |
name | string | yes | Display name. |
kind | string | no | http, ldap, scim, sql or flat-file. Absent means http. |
description | string | no | One or two sentences for the catalog. |
icon | string | no | @ followed by the vendor's domain (Owlie shows that brand's logo), or an https:// image URL. |
provides | array | yes | Capabilities: sync, provision, notification. (login is accepted but not used by current connectors.) |
protocols | array | no | Host capabilities the connector needs: http (the default), ldap, sql, s3, powershell. ldap, sql and powershell require a private-network gateway. |
execution_targets | array | no | Where it may run: cloud, gateway, or both (the default for HTTP). A connector whose protocols need a gateway may declare only gateway. |
pagination_type | string | no | Default ctx.paginate style: cursor, next-token, offset-limit, page-number, link-header. |
config | object | yes | The shared install configuration (below). |
auth | array | yes | Authentication options (below). |
entities | object | yes | Entities, keyed by entity key (below). |
grant_kinds | array | no | Grant kinds (below). |
custom_ops | array | no | Custom operations (below). |
egress | object | no | Hosts the connector may reach (below). |
http_rate_limits | object | no | Request pacing (below). |
Config
config is { title?, description?, schema, help_uri? }. schema is a JSON Schema object; Owlie
renders the install form from it. Useful property keywords:
| Keyword | Effect |
|---|---|
title, description, examples, default | Label, help text, sample values and a default in the install form. |
"format": "password", writeOnly, "x-sensitive": true | Marks a secret: masked, never shown again, never in logs. Any one of these marks it. |
"x-secret-ref": true | The value is the name of a secret held on a private-network gateway, which the gateway resolves itself. |
"x-suffix": ".example.com" | Shows a fixed suffix inside the input and stores only what the admin types. |
Add "additionalProperties": false so an install cannot store settings the connector does not declare.
Auth
Each entry of auth is one authentication option:
| Field | Meaning |
|---|---|
key | Stable id of the option, such as api-token. |
title, description, help_uri | What the admin sees when choosing, and a link to the vendor's setup guide. |
enabled | Set to false to hide the option. |
availability | Set to "disabled" to take the option out of service without deleting it (see below). The only accepted value. |
config | { title?, description?, schema }: the credentials and settings this option needs. |
connect | A browser consent step: oauth2_authorization_code, or { "custom": true }. |
acquire | Getting a token: oauth2_client_credentials, oauth2_jwt_bearer, oauth2_private_key_jwt, oauth2_password, or { "custom": true }. |
credentials | Building credentials: static or oauth2_token_response, or { "custom": true }. Required on every option that gets a token. |
refresh | Renewing a token: oauth2_refresh_token or any acquire form, or { "custom": true }. |
apply | Putting credentials on requests, or { "custom": true }. |
reject | { statuses?, error }: a response that means the vendor refused the credential, see Credential rejection. |
Values inside stages are nodes: { "literal": value }, or { "expr": "expression" } over config (the
shared and option configuration merged), credentials, token_response and auth (auth.key); the
connect stage sees only config and auth (Expressions).
A secret-bearing field must read a property marked secret; a literal secret is refused. The shared
configuration and an option's configuration must not share a property name.
Stage fields
| Stage form | Fields |
|---|---|
oauth2_client_credentials | token_url, client_id, client_secret, scope, audience, client_auth (body or basic), grant_type (a literal; default client_credentials), extra_params |
oauth2_jwt_bearer | token_url, service_account_email, private_key, delegated_admin_email, scopes, grant_type, issuer, subject, audience |
oauth2_private_key_jwt | token_url, client_id, private_key (PKCS#8 PEM or JWK), key_id, algorithm (RS256, PS256 or ES256), scope, audience, claims, extra_params |
oauth2_password | token_url, username, password, client_id, client_secret, client_auth, scope, extra_params |
oauth2_refresh_token | token_url, refresh_token, client_id, client_secret, scope, client_auth, extra_params |
oauth2_authorization_code | authorize_url, token_url, issuer, client_id, client_secret, client_auth, scopes, response_type, response_mode, redirect_uri, pkce, audience, token_request_body (form or json), token_response_format, extra_authorize_params, extra_token_params, callback_validation |
static | A record of named values, each a node. |
oauth2_token_response | access_token, refresh_token, expires_in, extra: where each comes from in the token response. |
apply | header (a record of header names to nodes), query (a record of parameters to nodes), basic (username, password), base_url (a node), tls (cert, key) |
client_auth: "basic" sends the client id and secret as an HTTP Basic header instead of form fields.
extra_params adds vendor-specific form fields; it cannot override a field the stage sets.
callback_validation selects one of Owlie's built-in callback checks for vendors that require one
(shopify_hmac, intuit_realm). github_app_installation under connect is reserved for Owlie's
GitHub connector.
A stage marked { "custom": true } needs a matching function in lib/auth-hooks.ts
(Handler API).
Disabling an option
"availability": "disabled" takes an option out of service while its declaration, handlers and tests
stay in place. Owlie leaves a disabled option out of the authentication options it offers an admin,
and refuses to save an install's configuration, or start or finish a browser consent, that selects it
(Integration auth option is disabled). Leave the field out to keep the option available. It is
separate from enabled, which hides a single option at runtime based on the install's configuration.
Credential rejection
Owlie already treats a 401 or 403 as a refused credential: it refreshes the credentials and
retries the request once. Some vendors refuse a credential with another status, or with a 200
whose body carries an error code. reject declares that shape:
statuses(optional): up to 8 distinct HTTP statuses, 100 to 599, that the rule applies to. Leave it out to check the response whatever its status.error.pointer: a JSON pointer into the JSON response body, beginning with/, at most 8 segments deep. It may contain at most one*segment, which stands for every element of an array.error.codes: 1 to 16 distinct strings. The rule matches when the value at the pointer equals one of them; a number in the body is compared as its text.error.match:"all"or"any". Required when the pointer contains a*:"all"needs every element of the array to match,"any"at least one. An empty array, or a value that is not an array, never matches.
When a response matches, Owlie refreshes the credentials and sends the request again once. If the
second response also matches, the request fails as an authentication error (AUTH_ERROR) that is not
retried, whatever the HTTP status was. A response that your http_rate_limits already read as a rate
limit is not treated as a credential rejection.
Declaring reject asserts that the vendor refused the request before running it, because Owlie sends
the request again even when it is a write. Declare it only when the vendor's documentation says so,
and cite that page in the connector's README.
Entities
entities is an object keyed by entity key (user, group, role). Keys are singular, start with
a letter, and are not grant, grants, connection or notification.
| Field | Meaning |
|---|---|
name | Display name. |
description | What the entity is in the system. |
is_account | true on exactly one entity: the account. |
schema | JSON Schema of the entity's record (below). |
identifier_paths | Identifier property names in order. Always declare it: without it Owlie falls back to the properties marked x-identifier, and the copy of the schema Owlie stores for each install does not keep property order. Owlie keys a record by the first identifier that has a value, so a record whose first identifier is empty is keyed by the next one; make sure the first is always present. |
display_paths | Properties used as the record's display name, in order. Defaults to properties marked x-display. |
sync_support | supports_incremental (the entity has fetchAllSince), supports_deleted, and fetch_options (filter with enabled, input_hint and help; fields), which let an install narrow what Sync reads. |
sync_profile | Defaults for the install's sync settings (below). |
provisioning_profile | The account entity's provisioning settings (below). |
create_semantics | Account only: direct (the default), invite (creating sends an invitation; the account is pending until accepted), or external (accounts are created outside Owlie; the connector writes Grants only and has no create handler). |
invite | Account only, with invite: expiry_attribute (the record property holding when the invitation expires) and reinvite_op (a custom operation that resends it). |
identifier_transition | Account only: true when the id a create returns changes once the account is accepted. |
Schema annotations
| Annotation | Meaning |
|---|---|
"x-identifier": true | An identifier. List the same properties, in order, in identifier_paths; the first is the external id. |
"x-provider-stable-id": true | The vendor keeps this identifier for the record's lifetime and never reuses it. Top-level identifier properties only, and not writeOnly or x-sensitive. |
"x-display": true | Use as the record's display name. |
readOnly: true | Set by the system; never written. |
writeOnly: true | Sent but never read back, such as a password. |
"x-sensitive": true | Masked in logs and audit. |
"x-provisioning" | requiredOn (actions that require it: PROVISION, UPDATE_ATTRIBUTES), writableOn (the only actions that may write it), immutable (set once), passwordHistory (true when the connector applies the target's own password history rules to a password written here). Top-level properties only. |
"x-reference" | { entity, attribute }: the property refers to another account of the same system (a manager). entity is the account entity; attribute is the referenced account's property that holds the value, or externalId. |
"x-scope" | { entity }: on a Grant target, the property holding the external id of the entity that scopes the target, such as the organization that owns a role. Empty or null means unscoped. One readable, top-level string property per entity, fetched by Sync. |
Sync profile
On the account entity, sync_profile can set: target (IDENTITY, RESOURCE or HYBRID),
resourceId, matchingRules, onMatchAction, onNoMatchAction,
onIdentityMatchWithoutAssignedResourceAction, attributeMappings, fetchOptions,
assignmentPolicy, and three expressions over the synced record: is_active, is_deleted and
is_person (Expressions).
target decides what Sync does with accounts. RESOURCE is for a system people are given access
to: each account is linked to an existing identity by matchingRules, each
{ identityField, externalExpression } (such as { "identityField": "email", "externalExpression": "email" }),
an account that matches nobody is flagged, and the install's resource is bound to the job. IDENTITY
is for a source of people: Sync updates matched identities and creates one for every unmatched
account. HYBRID does both. Without a target, the default is IDENTITY with onMatchAction
update and onNoMatchAction create, so a connector for a system people get access to must declare
RESOURCE. An account whose target is RESOURCE or HYBRID needs is_active; without it, Sync
cannot tell an active account from an inactive one. On other
entities, sync_profile can set attrMappings, fetchOptions and assignmentPolicy. These are
defaults; each install can change them.
Provisioning profile
provisioning_profile is { version, operations }. operations may contain PROVISION, REVOKE,
DISABLE, ENABLE, UPDATE_ATTRIBUTES, ADD_GRANTS, REMOVE_GRANTS and SET_GRANTS; Owlie plans
only the operations listed. Each may carry before and after hook steps, each
{ type, op, params?, when? } with type InvokeConnectorOp (a custom operation) or OwlieFunction.
| Operation | Extra fields |
|---|---|
PROVISION | provision_mode (direct, invite or external, matching create_semantics), baseline |
REVOKE | remove_managed_grants, lifecycle_state_on_revoke (DISABLED or DELETED) |
baseline.attributes maps each attribute to a leaf evaluated per identity:
{ "type": "expression", "value": "identity.email" }, or
{ "type": "usernameGenerator", "config": { "steps": [...], "maxAttempts": 50 } }. baseline.grants
lists Grants every new account gets, each { kind, target: { entity, external_id }, qualifiers? }.
On the account, provisioning_profile can also hold a password block. When Owlie creates the account
it generates a random password of initial_length characters (24 unless set, 12 to 128) and sends it
to every path in paths (one to four credential properties, both writeOnly and x-sensitive); it
keeps no copy. policy (min_length, classes) states the target's own password rules.
link: "identity" makes the account follow the person's password changes, self_service lets the
person set this account's password themselves, on_change holds plain values written with every password
change, and history_check (person_changes, the default, always or never) says which changes
must meet the target's password history rules. Accounts created outside Owlie take no password
block.
Grant kinds
| Field | Default | Meaning |
|---|---|---|
key | required | Stable name; also the Grant handlers' folder. Starts with a letter; letters, digits, _, -. |
source | required | The entity that normally holds the Grant. |
principal_types | [source] | Every entity that can hold it; must include source. |
target | required | The entity the Grant is on. |
discovered_via | required | The entity whose sync returns these relationships. |
fetch_mode | per-entity | per-entity (fetchRelationships on discovered_via) or embedded (in fetchAll pages). |
qualifiers | [] | The assignment's details (below). |
validators | [] | Rules across qualifiers (below). |
writable | false | Owlie may add and remove it. Needs provision in provides and both Grant handlers. |
membership | false | The principal holds every Grant the target holds. |
membership_context | [] | Required single-valued qualifiers carried along membership as scope. Needs membership. |
prerequisite | none | { kind, target_from_qualifier }: a Grant of this kind needs a Grant of kind, held by the same principal on the target its target_from_qualifier qualifier names, such as an organization role needing membership of that organization. Owlie adds it with the Grant unless the resource turns that off. kind must be writable; the qualifier must be a required, single-valued entity_ref. |
hierarchy | false | The principal is a child of the target; propagating Grants on the target cover it. |
propagates | false | Grants of this kind cover the target's descendants. |
derived | false | Computed by the connector; never writable. |
via_membership | transitive | How far membership reaches: transitive, direct or none. |
effective_access | true | Whether effective-access answers read this kind. |
Qualifiers
| Field | Meaning |
|---|---|
name | Unique within the Grant kind. |
schema | string, enum, boolean, number, instant, duration, entity_ref, set or record. |
required | Every Grant must carry it. |
slot_key | The value distinguishes assignments that can exist side by side. |
multi_valued | The qualifier holds several values. Cannot be combined with slot_key. |
values, order, default | For enum: the allowed values, their ranking from lowest to highest, and a default. |
unit | For number: its unit. |
entity | For entity_ref: the entity the value refers to. The value is that entity's external id. |
pattern | For string and entity_ref: a regular expression new Grants must match. Anchor it with ^ and $ when it guards a URL segment. Nested quantifiers ((a+)+), repeated groups with alternatives ((a|b)+) and backreferences are refused. |
examples | Realistic values; each must match pattern or be one of values. |
source | Where Sync reads the value in a relationship record. Default attrs.<name>; must start with attrs.. |
Validators
Each validator is an object whose kind names the rule, plus that rule's fields, such as
{ "kind": "cardinality", "per": "principal", "max": 1 }.
kind | Fields | Rule |
|---|---|---|
cardinality | per (principal or principal_target), max | At most max Grants of this kind per principal, or per principal and target. |
subset | a, b | Qualifier a's values are a subset of qualifier b's. Both multi-valued. |
numeric_relation | a, op (lt, lte, eq, gte, gt), b | A numeric relation between two number qualifiers. |
Custom operations
Each entry of custom_ops is { key, title?, description?, params_schema? }. params_schema is a JSON
Schema for the parameters; Owlie checks them before the handler <account entity>.op.<key> runs. Custom
operations run on the account entity only.
Egress
egress is { auto?, manual? }. manual lists the domains the connector reaches. auto lists
{ domain, source } pairs that Owlie derives itself from literal URLs in the authentication stages
(apply.base_url and the token stages' token_url), recording in source where each came from; it
replaces any auto you write whenever it builds the connector. A host built by an expression, such
as 'https://' + config.subdomain + '.example.com', yields no auto entry, so list its parent domain
under manual.
In Owlie's cloud, a connector may reach only HTTPS hosts that equal or are subdomains of these
domains, plus any an install lists in egress_domains. Owlie adds that field to the configuration
schema of every connector that runs in its cloud, with your egress domains as its default, so a
connector must not declare a property of that name. Redirects are checked the same way.
Rate limits
http_rate_limits is { buckets, rules, quota? }.
- A bucket is either a fixed budget,
{ key, limit, window_ms, burst }, or limits the vendor reports,{ key, kind: "fixed_reset", feedback }.feedback.headersnames the response headers forlimit,remaining,resetandretry(time headers as{ name, unit }, withunitdelta_seconds,epoch_secondsorepoch_milliseconds).feedback.bodyreads error responses:statuses(200 to 599, up to 8),error({ pointer, match?, codes }, a JSON pointer and the vendor's rate-limit codes;matchas in Credential rejection), optionallimit,remaining,resetandretrypointers, and optionaldefault_retry_ms(1 to 900000): how long to wait before retrying when the response gives no retry time. - A rule is
{ methods, origin?, path, buckets }: uppercase HTTP methods, an optional HTTPS origin, a path where*matches one segment and a final**matches the rest, and the buckets a matching request consumes. quotagroups integrations that share one vendor quota:{ namespace, dimensions }, each dimension{ source, field, meaning }withsourceconfigorbinding.
Declare only limits the vendor documents. Fixed budgets are paced at 80% of the declared rate. Without a declaration, Owlie still backs off when the vendor answers 429.