Authorized Orgs — Multi-Org Service Collaboration

What this covers

How to let devs from a second organization help build and release a service that a primary org owns — without moving them into the owning org.

The model

A service has exactly one primary owner org (spec.owner in catalog-info.yaml, stored as service.org). By default only members of that org can deploy it — the builder authorizes a deploy when user.org === service.org.

A service can additionally grant one or more authorized orgs (service.authorizedOrgs). Members of an authorized org get full parity with the owning org: deploy, config, secrets, and database access.

Primary org (owner)                Authorized org(s)
─────────────────────              ─────────────────────
• owns the service                 • deploy / release
• pays gas                         • config + secrets
• controls spec.owner              • database access
• admins grant/revoke              • CANNOT add further orgs
  authorized orgs

Billing never moves

The deploy gate keys off catalog.owner (= spec.owner = the primary org), so:

  • Gas is always billed to the primary org's wallet, no matter which org's dev deploys.
  • The owner-tamper guard still passes (authorized-org devs never change spec.owner).
  • The authorized org does not need to be in the platform approved_orgs allowlist.

Granting access

Only an admin of the owning org (or a platform super-admin) can add or remove authorized orgs. An authorized org cannot authorize further orgs.

CLI (requires tawa ≥ 0.18.0)

# List the owner + authorized orgs
tawa services authorized-orgs <service>

# Grant another org full-parity access.
# Also adds that org's members as collaborators on the service repo (default: write).
tawa services authorize-org <service> <org-slug>

# Control repo access: read | write | admin | none
tawa services authorize-org <service> <org-slug> --repo-role read
tawa services authorize-org <service> <org-slug> --repo-role none   # deploy/config/DB only, no repo grant

# Revoke
tawa services deauthorize-org <service> <org-slug>

authorize-org grants the org's current Forgejo members repo access immediately. Members who join the org later are granted access automatically the next time they authenticate to the builder (e.g. on tawa deploy) — see Self-healing provisioning below.

API

GET    /services/:name/authorized-orgs                 # owner + authorized orgs
POST   /services/:name/authorized-orgs   { orgSlug }   # add    (owning-org admin only)
DELETE /services/:name/authorized-orgs/:orgSlug        # remove (owning-org admin only)

End-to-end: onboarding a dev from another org

Say insureco owns the worldsweeper service (repo insureco/wsa) and you want a dev whose Bio-ID org is world-sweeper to help.

  1. Authorize their org on the service — this also grants their org's members repo access:
    tawa services authorize-org worldsweeper world-sweeper
    
  2. They deploy — after tawa login, their Bio-ID JWT carries org=world-sweeper. They run tawa deploy --prod; the builder authorizes it and bills gas to insureco. This same call self-heals their Forgejo org membership + repo access in the background.

No spec.owner change, no second wallet, no approved_orgs edit, and no manual repo-collaborator step.

Self-healing provisioning

Forgejo org provisioning historically only ran on tawa login, so a dev who only logged into Forgejo via web SSO — or whose org was created after their last CLI login — could be left without an org (and without repo access). The builder now self-heals on authenticated actions:

  • On tawa deploy, the builder reconciles the deployer's Forgejo state in the background: links their Bio-ID OIDC identity, ensures their org exists and they're a member, and grants collaborator access on every repo their org is authorized on.
  • This is idempotent and best-effort — it never blocks or fails the deploy.

So a newly-added authorized-org dev needs only to tawa login + tawa deploy — everything else provisions itself.

What each side can and can't do

CapabilityOwning orgAuthorized org
Deploy / release
Config vars + secrets (tawa config)✅ (full parity)
Database access (tawa db connect)✅ (full parity)
View build history✅ (shared view)
Add/remove authorized orgs✅ (admins)
Change spec.ownersuper-admin only
Pays gas❌ (owner always pays)

Security notes

  • Full parity includes secrets and DB. An authorized org can read/write this service's managed secrets and connect to its database. Only authorize orgs you trust with that data. Revoke with tawa services deauthorize-org at any time.
  • Build history is resolved through the service, not the raw build.org on each build — so the owning org and every authorized org see one shared history (a build triggered by an authorized-org dev is stamped with that dev's org, but remains visible to the owner).

Common mistakes

  • Creating a second org in approved_orgs to let another org's dev deploy your service — that only lets that org deploy its own services; it does not grant access to yours. Use authorize-org instead.
  • Expecting gas to bill the authorized org — it never does; the primary org (spec.owner) pays.
  • Running authorize-org as an authorized-org admin — only the owning org's admins can.
  • Forgetting the repo collaborator step — authorization lets them deploy; they still need Forgejo repo access to push code.

Last updated: July 15, 2026