Dibbla Docs Get started Guides Workflows Changelog
Open Console
Guides

SSO & access control

Who may open your app, how the platform tells your code who they are, and why you should not implement login yourself.

Sign-in is Google or Microsoft, handled by the platform before your code runs. Your app never sees a password, never stores a session, and never implements a login screen. What it gets is a set of headers describing who is knocking.

The platform reserves some paths on your app's own hostname

These prefixes are routed by the platform before your app is consulted, on your app’s own domain:

/auth, /api/auth, /api/deploy, /api/wf, /api/feedback, /api/ai-usage, /git, /health, /__auth/, /_platform/

They are matched as prefixes, so this is wider than it looks: an app with a route at /authors or /authenticate silently loses it — the request never reaches your code, and nothing warns you at deploy time. Check your route table against this list before you turn the login gate on.

Deciding who gets in

Decide who can open it covers the console. Two other ways to set the same thing:

$dibbla deploy . --alias my-app -m "feat: launch" --require-login --access-policy invite_only
 
# on an app that already exists (note: takes a value here)
$dibbla apps update my-app --require-login true --access-policy all_members
# or per service, in dibbla.yaml
services:
  admin:
    build: ./admin
    port: 3000
    public: true
    auth:
      require_login: true
      access_policy: invite_only
PolicyWho gets in
all_membersanyone in your organisation
invite_onlyonly users you grant access to
email_domainanyone whose e-mail matches a listed domain — no membership required
email_domain is console-only

The CLI’s --access-policy accepts all_members and invite_only, and the domain policy needs its domain list alongside it — which no CLI flag supplies, and which the manifest’s auth: block has no field for either. Set it in the console’s Access & users dialog. It is the one access policy you cannot express in a deploy.

What your app receives

Once someone is through the gate, the proxy passes their identity as headers. The proxy strips any inbound X-User-* headers from the client first, so what arrives cannot be spoofed:

HeaderMeaning
X-User-IDstable identifier — use this as the key in your database
X-User-Emaile-mail address
X-User-Namedisplay name
X-User-Orgthe organisation they are acting as, as a UUID
X-User-Org-Slugthe same organisation, human-readable — use this if you are rendering it
X-User-Org-Roletheir role in it: owner, admin, developer or viewer
X-User-GlobalAdminthe literal string true, and sent only when they are one
X-Session-Idthe platform session this request belongs to
X-User-Deploymentset for a workload identity rather than a person
Every header is omitted when empty, not sent blank

In particular, a user with no organisation gets neither X-User-Org nor X-User-Org-Slug nor X-User-Org-Role. That is not an edge case: it is the normal state for anyone let in by an e-mail-domain policy, which is the policy this page recommends. Read them as optional, and decide what an org-less user is allowed to do.

app.use((req, res, next) => {
  req.user = req.header("x-user-id")
    ? {
        id: req.header("x-user-id"),
        email: req.header("x-user-email"),
        name: req.header("x-user-name"),
        org: req.header("x-user-org"),
        role: req.header("x-user-org-role"),
      }
    : null;
  next();
});
Key on the ID, not the e-mail

E-mail addresses change — people marry, companies rebrand, aliases get reassigned. X-User-ID is stable. Using the address as your primary key is the mistake that is expensive to undo a year later.

Do not decode a JWT from the client

Read the headers, not the cookie. There is an auth_token JWT cookie on your app’s domain — the proxy sets it and it reaches your backend — but it is the platform’s session, not a contract with your app. It can change shape without notice, and the headers are what the proxy guarantees. If you find yourself parsing that cookie, you have left the supported path.

Gate versus authorization

The platform answers may this person open the app. It does not answer may this person delete that record — that is your code’s job, using the role and identity in the headers. A common shape: let the platform handle who reaches the app, then check X-User-Org-Role for the handful of destructive actions.

Domain auto-join

An organisation can claim e-mail domains, so a colleague signing in with a matching address lands in it automatically rather than in an empty personal space. It runs only on a genuinely new sign-in — an existing account is never moved by it.