Skip to Content
Task guidesTechnical: Identity & Access

Identity & Access

Technical reference. This page is for integrations, advanced configuration, or platform operations. For portal tasks, start with the user guide.

Orqestra separates identity from authorization. Users, groups, and service accounts can come from enterprise identity systems, while scoped permissions are evaluated by Orqestra against organizations, namespaces, workspaces, workloads, and platform-level operations.

Use this guide when you need to configure login, map IdP groups to Orqestra roles, provision users, debug 403 responses, or decide which role should own an operation.

Identity Sources

SourcePurpose
OIDCAuthenticates users and service principals with bearer tokens and JWKS.
SCIMProvisions users and groups from the enterprise IdP.
IdP group mappingsMaps external groups to scoped Orqestra roles.
Service accountsRepresents runtime services, agents, and automation identities.
Workload principalsGrants invocation, management, observation, or admin access to workloads.
Platform admin groupsGrants deployment-wide administration through configured IdP groups.

OIDC Login

The control plane validates bearer tokens against the configured issuer and JWKS endpoint. Configure these environment variables on the control plane:

VariableDescription
ORQESTRA_OIDC_ISSUER_URLIssuer URL used to validate token issuer claims.
ORQESTRA_OIDC_JWKS_URLOptional JWKS endpoint override when services must fetch keys through an internal address.
ORQESTRA_OIDC_AUDIENCEExpected token audience.
ORQESTRA_OIDC_CLIENT_IDRegistered client ID.
ORQESTRA_OIDC_ACTOR_REF_CLAIMStable claim used for the persisted Orqestra actor reference. Defaults to sub; use the SCIM subject.
ORQESTRA_OIDC_CLOCK_SKEW_LEEWAY_SECONDSBounded allowance for IdP/control-plane clock skew when validating iat, nbf, and exp. Defaults to 30; maximum 300.

Example:

export ORQESTRA_OIDC_ISSUER_URL="https://auth.example.com/realms/orqestra" export ORQESTRA_OIDC_JWKS_URL="https://auth.example.com/realms/orqestra/.well-known/jwks.json" export ORQESTRA_OIDC_AUDIENCE="orqestra-control-plane" export ORQESTRA_OIDC_CLIENT_ID="orqestra-cp" export ORQESTRA_OIDC_ACTOR_REF_CLAIM="email" export ORQESTRA_OIDC_CLOCK_SKEW_LEEWAY_SECONDS="30"

Local Keycloak deployments commonly use email because development user IDs can change after a restart. Production deployments should use a claim that is stable across IdP migrations and SCIM provisioning events.

Expired Portal sessions

When a Portal session expires, API reads and mutations return a structured 401 instead of redirecting the request to the login page. The Portal blocks the stale shell with a Your session expired dialog and offers an explicit sign-in action. After OIDC login, the browser returns only to a validated Portal page path. Orqestra never automatically replays the failed request: review the page and explicitly retry the action. Workload-profile sandbox discovery reconciles its draft profile asset and version before requesting recommendations, so explicitly retrying that step does not duplicate a profile write that committed before session loss. Other multi-write workflows do not currently provide this reconciliation guarantee. A 403 remains an authorization denial and does not start the session-expired flow. A separate endpoint-owned 401 (for example, an expired share-link ticket) also remains an endpoint error and does not sign the user out.

Signing out of the Portal

Signing out takes two deliberate steps. The sign-out control in the user menu is an ordinary link to /logout, which opens a confirmation page; the session ends only when you submit the confirmation on that page. Simply loading /logout changes nothing, and GET or HEAD /api/auth/logout answers 405 with Allow: POST — so a link prefetch, a mail scanner, or a page that embeds the URL as an image cannot sign you out.

The confirmation page carries a one-use token bound to your current session. It expires at the sooner of ten minutes and your session’s own idle and absolute deadlines, and confirming consumes it. So a confirmation page you left open, a second tab holding an older confirmation, or a resubmitted browser history entry is refused. Nothing about your session changes when that happens, and the retry is always the same: reload /logout and confirm again — never resubmit the old page. A /logout page that offers no confirmation control means there is no live session left to end; go to /login instead.

If the session store is unavailable while the confirmation page is being prepared, /logout answers 503 and leaves your cookies untouched. Retry once the deployment’s session Redis is healthy.

Bounded sign-out failures

The sign-out submission accepts one small, strictly shaped form and refuses everything else with a fixed status and no detail beyond it:

ResponseCause
403Missing, foreign, or malformed request provenance, or a stale, replayed, or mismatched one-use token.
401No live Portal session to end.
415A body that is not application/x-www-form-urlencoded.
413A body over 1024 bytes.
408A body that takes longer than five seconds to arrive.
400A body that is not exactly one canonical token field.
503The session store failed while ending an already-authorized session.

Every one of these except the 503 is refused before anything is changed: your session, your cookies, and the one-use token are exactly as they were. The 503 is the only case that happens after authorization — the sign-out was accepted but the stored session could not be deleted — so the Portal clears the four browser auth cookies (orq_access_token, orq_pkce_verifier, orq_oauth_state, orq_auth_return_to) anyway and does not call the identity provider. A successful sign-out clears those same four cookies and returns you to /login.

Sign-out from an embedded Portal page

The sign-out submission requires strict same-origin provenance. A present Origin header must be exactly one valid, trusted HTTP(S) origin — the Portal’s own origin or a configured browser-facing base URL. An empty, multi-valued, non-HTTP(S), or opaque null Origin is rejected outright and never falls back to Referer; only a genuinely absent Origin may fall back, and the Referer must then itself be a trusted origin.

That rule denies mutations from an opaque origin, which is exactly what a sandboxed <iframe> produces. A frame sandboxed without allow-same-origin sends Origin: null, and that value is indistinguishable from every other opaque origin — a data: document, an unrelated sandboxed frame, a redirected cross-origin frame. Accepting null would accept all of them, so any site could host an invisible sandboxed frame that signs your users out. Orqestra denies it rather than weakening the check for Origin: null.

A cookie-authenticated embed that needs to make mutations therefore needs a same-origin-capable context: a frame served from the Portal’s own origin and, if sandboxed at all, sandboxed with allow-same-origin so it keeps that origin instead of collapsing to null. A frame hosted on a third-party origin sends its own Origin, which is not trusted, so it is refused for the same reason. An embed that must stay opaquely sandboxed, or that lives on another host, can still render Portal pages through ORQESTRA_EMBED_FRAME_ANCESTORS; signing out has to happen in a top-level Portal tab.

Scope Chain

Authorization walks the typed scope chain from narrowest to broadest:

WORKSPACE -> NAMESPACE -> ORG -> PLATFORM

The first scope at which the actor has a role that grants the permission returns ALLOW. A lower scope that lacks a permission does not deny the check; it continues walking upward. This is the affirmative-grant rule.

Example: a user can be a Developer in one workspace and an Organization Admin on the parent organization. A workspace member-management check can pass through the organization grant even though the workspace Developer role does not include that permission.

Built-In Roles

RoleScopeCommon use
Platform AdminPlatformDeployment-wide administration, retention purge, platform-level settings.
Organization AdminOrganizationNamespace management and organization-level grants.
Namespace AdminNamespaceWorkspace creation and operations inside a namespace.
Workspace AdminWorkspaceWorkspace membership, assets, releases, secrets, and connections.
DeveloperWorkspaceAuthor assets, create draft releases, execute flows.
OperatorWorkspaceApprove, activate, rollback, observe, and respond to incidents.
ViewerWorkspaceRead-only access to workspace resources.

Permission Boundaries

The most important boundaries are:

  • Developers can create assets and draft releases, but cannot approve or activate releases.
  • Operators can approve, activate, and rollback releases, but cannot create or edit assets.
  • Workspace Admins manage workspace members, secrets, connections, assets, and releases in their workspace.
  • Namespace Admins can create and manage workspaces, but cannot make themselves platform or organization administrators.
  • Organization Admins can manage namespaces and organization-level grants.
  • Only Platform Admins can purge retention or audit data.

Use the repository reference at docs/reference/iam-permissions.md when you need the complete permission matrix.

IdP Group Mapping

IdP group mappings bind enterprise groups to scoped Orqestra roles. Workspace role mappings include a workspace. Namespace role mappings omit the workspace. Platform admin access is configured separately through ORQESTRA_PLATFORM_ADMIN_GROUPS.

A mapping references the IdP group directory — an issuer-scoped table of group claims either observed at a real login (verified) or explicitly pre-provisioned by a Platform Admin (pending_unverified) ahead of a group’s first login. A mapping cannot be created against a group that isn’t in the directory: a typo or guessed group name is rejected outright rather than silently creating a mapping that never matches a login claim.

Platform Admins can manage these mappings in the portal from Administration → IdP group mappings. The IdP group field is a searchable combobox over the directory, with an explicit pre-provisioning option for a group that hasn’t logged in yet. The page lists existing mappings, creates namespace-scoped or workspace-scoped mappings, prevents invalid role/scope combinations before submit, and surfaces duplicate mapping conflicts from the API.

# Find (or pre-provision) the directory candidate first curl "http://localhost:8000/v1/idp-group-directory/candidates?q=azure-ad" curl -X POST http://localhost:8000/v1/idp-group-directory \ -H "Content-Type: application/json" \ -d '{"claim_ref": "azure-ad-group-object-id"}' # Then create the mapping against its directory_group_id curl -X POST http://localhost:8000/v1/idp-mappings \ -H "Content-Type: application/json" \ -d '{ "directory_group_id": "<uuid from the directory candidate>", "namespace_id": "namespace-123", "workspace_id": "workspace-456", "default_role": "developer" }'

When a user logs in, Orqestra reads group claims from the token, upserts each one into the directory, and matches them against configured mappings to provision the matching workspace or namespace membership. A mapping bound to a still-pending_unverified directory group grants nothing until that happens.

SCIM Provisioning

SCIM keeps users and groups aligned with the enterprise IdP. The OIDC actor reference claim should match the stable subject SCIM uses for the same human or service identity. If those identifiers drift, the same person can appear as two different actors and permissions will not resolve as expected.

SCIM is off by default and is enabled per tenant in Administer › Access & org › Tenant settings (or orqestractl namespace settings set <namespace_id> --scim on), an audited change that applies to the next request. While it is off, /scim/v2 answers 403 enterprise_capability_required (in the SCIM error format) to an authenticated provisioning client; an unauthenticated caller still gets 401. In a single-issuer deployment SCIM is platform-wide, so enabling it needs platform administration; with Entra tenants it is keyed on the credential’s own organization.

Microsoft Entra ID

Orqestra trusts Entra tenants one at a time, per organization. Nothing is trusted implicitly: a tenant is inert until an operator registers it, and a registered tenant only provisions once it holds a SCIM credential.

For a full step-by-step runbook covering both the platform and customer sides of bringing a new customer onto this profile, see Customer Tenant Onboarding.

The customer’s Entra administrator grants admin consent for the Orqestra application in their own tenant. Consent alone does not grant access to Orqestra — it only allows the tenant’s users to present tokens. Until the tenant is registered (below), those tokens are rejected.

Registering a trusted tenant

Register from Administer → Access & org → Organizations → (organization) → Trusted tenants, or with orqestractl identity-tenant. You supply the tenant’s directory ID; Orqestra derives and stores the exact issuer it will accept and shows it back to you.

The binding is permanent. A tenant can be renamed, disabled and re-enabled, but never deleted and never re-pointed at a different issuer. Historical actors, audit records and group mappings reference it, so detaching it would strand that evidence. If you registered the wrong tenant, disable it and register the correct one.

A disabled tenant stops authenticating immediately and cannot be issued new SCIM credentials.

Qualifying client IDs

ORQESTRA_ENTRA_QUALIFIED_CLIENT_IDS lists the application (client) IDs eligible for issuer qualification — between 1 and 10 comma-separated GUIDs. Ordinary sign-in admission checks tenant registration, token signature, issuer, audience, and expiry. The azp allowlist is a separate, additional check enforced by the issuer-qualification authority (POST /v1/issuer-qualifications and friends — see docs/reference/qualified-issuer-authority.md), which the owner-continuity and external-AI-ownership workflows require before trusting an actor with those specific, more sensitive operations. Qualification requires idtyp == "user", a non-empty scp, and azp in this allowlist.

The allowlist remains the authority for operator-tenant clients and configured first-party clients. Customer applications can instead be registered by an organization administrator under Administer → Client applications or with orqestractl client-application register. Registration is scoped to an active organization and its registered Entra tenant; Orqestra checks the live client registration on each request. Registration grants admission only. Workspace membership, permissions, and human-session qualification still apply.

Disable takes effect on the next request across replicas. Re-enabling advances the authorization revision, so qualifications made under the previous revision remain invalid until a new qualification is approved. Rename does not change the authorization revision.

Use orqestractl client-application scopes to list organizations and tenants the current caller may administer, then orqestractl client-application list --org-id <id> --identity-tenant-id <id> to inspect registrations. Enable and disable operations require the current revision with --expected-revision.

Changing this value does not retroactively qualify identities under a new configuration. After changing it, re-qualify affected first-party identities so their qualifications are re-evaluated against the new set. Customer-registered applications are separately bound to the registration’s organization, tenant, client ID, and authorization revision.

SCIM credentials: issuing, rotation, revocation

SCIM credentials are scoped to one organization and one registered tenant, and are confined to /scim/v2 — a SCIM credential cannot read any other API.

  • The secret is displayed once, at issue time. It is never retrievable afterwards. Orqestra stores only a hash and a short non-secret prefix (orqscim_…) used to identify the credential in listings and logs.
  • Rotate by issuing a second credential, moving the Entra provisioning job onto it, then revoking the first. Two active credentials per tenant is the maximum, and that ceiling exists to make this overlap possible — it is not a quota to sit at. Issuing is refused at two active credentials.
  • Revocation takes effect immediately.

Provisioning contract

Configure the Entra enterprise application’s provisioning to Orqestra’s SCIM endpoint using the issued credential as the bearer token.

externalId must be the Entra objectId, and it is required on create. It is immutable: once a user is provisioned, a later request carrying a different externalId is rejected rather than silently re-keying the identity.

Orqestra applies the core SCIM attributes it governs. Attributes outside that set are accepted and ignored rather than rejected, because Entra sends them routinely and rejecting one would take the whole request with it:

  • core: title, nickname, userType, preferredLanguage, locale, timezone, profileUrl, phoneNumbers, addresses, ims, photos
  • name.*: formatted, honorificPrefix, honorificSuffix, middleName
  • enterprise extension: employeeNumber, costCenter, organization, division, department, manager

Any attribute outside the governed and accepted sets fails the PATCH with 400. This matters more than it looks: Entra batches attribute updates with lifecycle changes, so a PATCH carrying an unsupported attribute and active: false fails as a unit and the user is not disabled. If deprovisioning appears not to take effect, look for a 400 on the batched PATCH before looking at the lifecycle logic.

Errors are returned as RFC 7644 Error objects (application/scim+json); a duplicate userName returns 409 with scimType: "uniqueness".

Group mapping is issuer-scoped

Directory search and pre-provision run against a specific registered tenant, so group mapping is organization-first: choose the organization, then one of its active tenants, then the group. The chosen tenant’s issuer is sent with the lookup — which is why group search does nothing useful until at least one tenant is registered.

For an organization-wide administrator, map a single Entra group GUID to organization-admin at organization scope. A mapping targets an organization or a namespace, never both.

Entra licensing and group shape

Group-based assignment to an enterprise application requires Entra ID P1 or P2. On the free tier, assign users to the application directly.

Only direct group membership is provisioned. Nested groups are not expanded — a user who belongs to a mapped group only through a child group will not be provisioned. Flatten the membership, or map the child group too.

Service Accounts

Service accounts represent runtime services, AI agents, automation clients, and other non-human principals. They are tracked with the same membership model as users but are marked as service accounts.

Use service accounts when:

  • a runtime gateway needs to execute on behalf of a workspace,
  • an agent needs stable access to scoped workloads,
  • CI/CD needs to create releases or synchronize GitOps state,
  • automation needs audit attribution separate from a human user.

Do not reuse personal user tokens for automation. Service account activity should have its own actor reference in audit logs.

Workload Principal Bindings

Workload access uses principal bindings for invocation and operational access.

Access modeMeaning
interactiveA human-driven session (for example, a console seat).
programmaticAn automated or service-to-service caller.

actor_type is one of user, workload, service, or system.

Example:

curl -X POST http://localhost:8000/v1/workloads/{workload_id}/principal-bindings \ -H "Content-Type: application/json" \ -d '{ "actor_type": "service", "actor_ref": "service:release-bot", "access_mode": "programmatic", "scope_ref": "workspace:payments-prod" }'

Debugging Access Failures

Use this checklist for 401 and 403 failures:

  1. Confirm the request has a bearer token or an authenticated portal session.
  2. Verify the token issuer, audience, expiry, and JWKS configuration.
  3. Check the actor reference claim and make sure it matches the stored member or SCIM subject.
  4. Confirm the actor is mapped into the expected organization, namespace, or workspace.
  5. Check whether the permission is evaluated at workspace, namespace, organization, or platform scope.
  6. For workload operations, inspect workload principal bindings and access modes.
  7. For gated features, inspect /v1/capabilities and verify the capability is enabled in the deployment.

If a permission should be granted by a broader scope, verify that the broader role is on the same parent chain as the target workspace or workload.

Workspace role permission overrides

An administrator with members.manage on a workspace can set or reset per-role overrides there. These are workspace-role settings, not per-user override lists. Use authenticated API paths relative to your deployment’s control-plane address:

PUT /v1/workspaces/{workspace_id}/permissions/overrides/{role} DELETE /v1/workspaces/{workspace_id}/permissions/overrides/{role}

For example, removing execution permission from the developer role uses this PUT body:

{ "added": [], "removed": ["execution.run"] }

The wire fields are added and removed. Deleting that role’s override restores its defaults; it does not remove workspace membership. The API validates roles and permission names and rejects platform-admin overrides. Confirm the member’s effective permissions after changing an override; a user’s combined roles and grants can affect the result.