Skip to content

Identity & SSO

Who can sign in, what each role may do, how people are invited, and how an organisation brings its own identity provider.

Who may do whataccess rules
Signed in as
An owner · open a colleague's workspace · refused: not-owner

Opening a workspace is ownership and nothing else: administering the organisation is not access to its people's work. Owners and admins may start, stop, create and remove workspaces, but not open a colleague's shell. Reassigning a workspace is the recorded way to hand it over.

What each role may do, and the reason code when it is refused
ActionoperatorowneradminmemberauditorShared password
Open your own workspace
Open a colleague's workspace
Read the organisation's pages
Open the Audit and AI usage tabs
Start, stop, create or remove its workspaces
Change organisation settings, SSO included
Invite as member, admin or auditor
Make someone an owner
Remove or demote the last owner
Platform settings, mail, new organisations

Press a cell for the rule behind it. Refused cells show the reason code the console gives, where it has one. “Their agent” is an agent session started by that person; “shared password” is a session opened with the front-door password.

Two kinds of account

Operators run the host. They sign in at /admin/ with a password, create organisations, grant owners, and hold the platform settings: outbound mail, the AI agents, egress policy, the cluster. The first one is created when you install.

Everyone else belongs to organisations and signs in at /portal/. Inside an organisation each person holds one of four roles. There is no self-service signup: accounts arrive by invitation.

It is not a directory. There is no SAML, no SCIM provisioning, no native MFA and no passkeys.

The four organisation roles

RoleMayMay not
ownereverything an admin may; is the organisation's accountable holdercreate another owner; leave the organisation without an owner
admininvite and re-role members, admins and auditors; change settings and SSO; start, stop, create and remove workspaces; read the Audit and AI usage tabsopen a colleague's workspace; grant owner
memberuse the workspaces they own; read the organisation's pages; ask for an egress hostadminister anything
auditorread the organisation's pages, its Audit tab (a dashboard) and its AI usage tabchange anything, or open a terminal, IDE or preview, even in a workspace they own

An organisation cannot be deleted yet. Members can be disabled, offboarded and removed; the organisation stays. A plain member is not offered the Audit tab (since orxy V1.7.2.2).

Defaults

SettingScopeDefaultAllowed values
Require per-developer identityplatformoff, until an operator turns it onon, off
Invitation lifetimeplatform7 daysfixed
Session lifetimeplatform24 hoursfixed; revocable on the server
Outbound mail driverplatformnone: refuses every sendnone, smtp, console (development only)
SMTP port and TLSplatform587, autoauto, starttls, implicit, none
SSO providerorganisationnone configuredMicrosoft Entra ID, Google Workspace, generic OIDC
Require SSOorganisationoffon only with a complete provider and one break-glass member
Password sign-in alongside SSOorganisationonon, off
Require MFAorganisationoffon: the identity provider must assert it

Invitations

  1. Open the organisation's members. OrganisationsacmeMembersInvite

  2. Enter an email and pick a role. Admins can invite members, admins and auditors. Only an operator can invite an owner: that is how a new organisation gets its first one.

  3. Deliver the link. With mail configured, it is emailed. Without it, the console shows the accept link once, for you to send by another channel. It lasts 7 days.

  4. The person accepts and sets a password at /portal/, or signs in with the organisation's SSO. The membership becomes active with the role you picked.

An invitation is itself the approval, so there is no second step. It cannot quietly lower someone who already holds a higher role, and it does not undo a suspension unless an admin re-invites that member on purpose.

Outbound mail

Mail is off until an operator configures it: the default driver refuses every send and says so, rather than dropping messages. Until then there are no emailed invitations, no email verification and no password reset. Configure SMTP in the console, where the password is write-only, or through the serving tier's environment, which overrides it.

ConsoleSettingsOutbound mail

an env file the serving-tier unit reads
AGENT_STACK_MAIL_DRIVER=smtp
AGENT_STACK_SMTP_HOST=smtp.example.com
AGENT_STACK_SMTP_PORT=587
AGENT_STACK_SMTP_USER=kodela@example.com
AGENT_STACK_SMTP_FROM=kodela@example.com
AGENT_STACK_SMTP_TLS=auto
AGENT_STACK_BASE_URL=https://kodela.example.com

Keep AGENT_STACK_SMTP_PASSWORD in the host's secret store, not in a file you commit. AGENT_STACK_BASE_URL must be the exact origin people open: links are never built from the request's Host header, so without it every identity email refuses with no-base-url. Then use Send a test message on the same page; it tells missing settings, connection failure, authentication failure and relay rejection apart. From the host, python3 bin/_mail.py status gives the same check without sending.

No delivery is on record yet. The SMTP driver exists and is tested; a real relay has not yet delivered an invitation on record.

Single sign-on per organisation

Each organisation can bring its own identity provider over OpenID Connect: authorization code with PKCE, a nonce bound to the request, and issuer, audience and age checks on the ID token. It is configured by the organisation's owner or admin, not by the operator.

ProviderYou enterChecked
Microsoft Entra IDdirectory (tenant) ID, application (client) ID, client secretthe directory is pinned: not common, and the token's tenant must match
Google Workspaceclient ID, client secret, allowed domains (required)the hosted-domain claim against the organisation's verified domains
Generic OIDCclient ID, client secret, the endpoints by handdiscovery is not fetched; Okta and others work through this path, untested
  1. Register an application with your provider (Entra admin centre, App registrations; or Google Cloud, Credentials, OAuth client ID) with this redirect URI:

    redirect URI
    https://kodela.example.com/portal/sso/callback

    The base URL must be your https origin first; providers will not register a plain-http redirect.

  2. Enter it in the organisation's settings. OrganisationsacmeSettingsSingle sign-on The secret is write-only; the page shows whether one is installed, never its value. A provider that is on but has no secret is marked incomplete, and no sign-in button appears.

  3. Verify your email domains. An SSO identity links to an existing account only when the provider marks the email verified and the domain is verified for this organisation. It is never linked by a plain email match, and never to an operator. Otherwise a new identity is created for this organisation, with no role until an owner or admin assigns one.

  4. Test with one person, then decide on Require SSO. Require SSO binds members, not addresses, and needs at least one break-glass member who can still sign in with a password, so a lapsed provider cannot lock the owner out. Require MFA refuses sign-ins whose token does not assert MFA.

Tested only against a stub identity provider. No sign-in against a real Entra ID, Google or Okta tenant is on record. There is no SAML and no SCIM.

Sign-in and sessions

Passwords are stored with PBKDF2-SHA256 at 200,000 iterations, and an unknown account costs the same work as a known one. Repeated failures lock out the source; that lockout is held in memory and clears on restart. A session is an HMAC-signed, HttpOnly, SameSite=Lax cookie that lasts 24 hours, marked Secure on an https origin, and revocable on the server.

Disabling an account does not end its live sessions. Offboarding does: Membersdev@example.testOffboard disables the account, removes its ownership and signs it out.

Require per-developer identity

Out of the box, the shared front-door password is still accepted at the portal. A session opened with it is authenticated but names nobody, and it can reach any workspace. Close it once every developer has their own account, or they will be locked out.

ConsoleGovernanceControlsRequire per-developer identity

After this, the shared password is refused at the portal sign-in. Keep it in door.env: it is still used between the console process and the door.

Verify it works

  1. Sign in as a member and open a colleague's workspace URL. Good: {"error": "not your workspace"} with a 403.

  2. Sign in as an auditor and open their own workspace. Good: refused with org-read-only.

  3. Check mail. python3 bin/_mail.py status, then Send a test message.

  4. Read the posture. The console's Governance page reports whether identity is required, and the compliance report marks identity partial until it is.

    on the host
    $ bin/compliance-report

Troubleshooting

409 an organisation must keep one owner

You are removing or demoting the only owner. Make someone else owner first; that needs an operator.

409 last-break-glass

The organisation requires SSO and this is the last member who can sign in with a password. Exempt someone else first, or turn off Require SSO.

403 organisation admins only

A member tried an admin action. Ask an owner or admin, or have your role changed.

403 an identified session is required

You are signed in with the shared front-door password. Sign in with your own account.

403 not your workspace

Workspaces open only for their owner. An admin can reassign it to you.

Invitation email never arrives

Mail is off by default (not-configured), or the base URL is unset (no-base-url). Copy the accept link from the console, then configure mail.

Test message fails with auth-failed or connect-failed

Wrong relay credentials, or the relay host and port are unreachable from the host. Check the TLS mode against the port.

No SSO button on the sign-in page

The provider is off, or on without a client secret (shown as incomplete).

Sign-in fails over plain http

On an https origin the session cookie is Secure, so a browser will not send it over http. Use the https address.

What it does not do yet

  • No SAML, no SCIM. OIDC only, and provisioning is by invitation.
  • SSO is unproven against a real provider. Tested against a stub identity provider only.
  • No native MFA or passkeys. MFA only as a requirement the identity provider asserts.
  • Mail refuses until configured. No delivery through a real relay is on record.
  • Shared password on by default. Unattributable until “require identity” is on.
  • No organisation deletion. Organisations cannot be removed yet.
  • No rate limit on invitations. Nor on workspace creation.

Verified against the main branch, 4 Oct 2026.