Skip to content
downpipes docs

Identity and access in downpipes: sign-in, roles and change control

Identity and access in downpipes answers three separate questions: how a person proves who they are, what that person is then allowed to do, and how an account governs changes to either. This page sets the model for the whole section before any how-to page, written for a self-hoster standing up downpipes for their team.

Two facts shape everything that follows. The first is that authority is decided server-side in the engine, which runs inside your own Cloudflare account, and the console only mirrors what the engine would allow. The second is that the engine derives a stable, immutable identity from each sign-in and keys every authority decision on that identity, never on the email a person happens to use today.

This section has a canonical home for each detail. This overview connects them and states the load-bearing facts once, so the rest reads as elaboration rather than a fresh argument each time.

Four independent ways in

A request authenticates by one of a few methods, and the engine resolves exactly one of them per request. The point of the design is that the paths are independent: no single sign-in mechanism is a prerequisite for the others, so an outage in one is a sign-in button that does not work, never a lockout.

Sign-in path What it is What it carries
Passkey front door The engine’s own WebAuthn login, the free self-hosted front door. A successful login issues a short-lived signed session cookie. A verified email and a stable subject derived from the credential.
Cloudflare Access A verified Cloudflare Access JWT presented as a header, the higher-assurance path attributable to an email. A verified email and a stable subject built from the Access issuer and subject.
Native identity provider The engine’s own OIDC, OAuth2 or SAML session, minted after the engine itself completes the flow with no Cloudflare Access in the path. Optional, per connection. A verified email and a connection-scoped stable subject.
Break-glass admin token The bare ADMIN_TOKEN bearer fallback, presented as an explicit header. It is unattributable and all-or-nothing. No email and no subject, so it resolves to the owner break-glass.

On the passkey front door, whether the email box is required depends on what you are doing. Setting up a passkey needs your email, so the engine can bind the new credential to it. Signing in does not: leave the box blank and the resident passkey your device already holds is offered without a username.

The precedence at the gate is deliberate. A header-borne Access JWT is checked first, then the engine’s own session cookie (passkey, OIDC or SAML, told apart by the signed payload), then the bare token. A present-but-invalid Access JWT or session cookie is rejected outright and is never quietly downgraded to a weaker method.

An identity-provider outage is never a lockout

The passkey front door and the break-glass token stay independent of any external identity provider by design. If your OIDC or SAML connection is unreachable, that one “Sign in with…” button is down, and a passkey-bound owner and the break-glass path still work. The bridge recipe and the connect pages restate this rule: keep at least one passkey-bound owner and the break-glass path that do not depend on any identity provider, so a provider outage cannot lock the account out of itself.

The break-glass token is the one path with no attributable identity. Because a shared secret should not pose as an identified person, it does not read the role table at all. It is the owner or it is nothing. That same lack of a stable identity is why the break-glass token can neither propose nor approve a four-eyes change, covered under change control below.

Authority is a capability model, not a rank ladder

Once a person is authenticated, what they may do is decided by an explicit capability map, ROLE_CAPABILITIES. Each role holds a fixed set of named capabilities such as downpipe.write, restore.apply or roles.write, and a route allows a caller only when the caller’s role holds the capability that route requires. The decision runs through one primitive, can(role, capability), which is a single map lookup followed by a set membership test. There is no separate ranking that decides a per-route allow.

This matters because two of the six built-in roles are not steps on a cumulative line. restore-operator is recovery-only and access-admin is people-only. Each holds a precise subset of owner’s powers for one job, so neither is a prefix of owner and neither can be expressed by a single numeric rank. An internal rank does still exist, but only to fold role resolution and grant expiry cleanly, never to decide whether a request is allowed.

On top of the six built-ins, an account can compose its own named capability bundles. These custom roles sit alongside the built-ins and never replace them, and an identity-provider group mapping is an optional additive layer that resolves a group to one of these roles. The full table and the composition rules each have their own page.

Where authority is defined Canonical page
The six built-in roles and the exact capability each holds Roles and capabilities
Composing an account-defined named capability bundle Custom roles
Resolving an identity-provider group to a role Group-to-role mapping

Two capabilities, keys.ceremony and posture.riskaccept, are the owner’s alone. No other built-in holds them, no custom role may include them, and no group mapping can confer them, so the break-glass owner stays the single named holder of both. The roles reference page proves the bar in detail.

Authority keys on a stable subject

The engine stores a role against a caller’s stable, immutable subject, under a key of the form role:sub:<subject>, not against the mutable email. The subject is the principal the engine derives from the sign-in. A Cloudflare Access caller’s subject is its issuer joined to its Access subject. A passkey caller’s subject is its credential principal. A native identity-provider caller’s subject is scoped to the connection it signed in through, so the same person across two connections is two subjects and can never collide.

Keying on the subject has direct consequences for safety. A recycled or reassigned email can never inherit a departed member’s role, because the new person authenticates to a different subject and reads a different or empty role entry. The same person signing in with a different email case is still recognised as the same subject, so they cannot pose as a distinct second party in dual control. The email is retained for display and for the audit trail, and it is never the axis an authority decision turns on.

An invitation is the one place an email is used as a key, and only until first sign-in. An owner or access-admin invites by email under role:pending:<email>, because the subject is not yet known. On the invitee’s first verified request the engine binds the pending grant to their subject, records the email on the subject-keyed entry, and deletes the pending row. From then on the authority is the subject’s.

What is enforced where

Everything in this section is enforced server-side in the engine and surfaced in the console. The console is a faithful client mirror of the engine’s gates: an action a caller cannot perform is shown disabled with the reason stated, rather than hidden and then failing with a 403 when pressed. When the engine denies a route it returns a structured forbidden body naming the capability the route required and the role the caller resolved to, which the console uses to say exactly which capability was missing.

The governance lives in the engine alone. The control-plane and the Go command-line tool carry none of it. The control-plane is a thin surface that does not hold this role model, and the command-line tool is an offline recovery and verification aid that operates on archives rather than on the live engine’s authority. If you read about roles, group mappings or four-eyes change control anywhere, it is the engine that is enforcing them.

The console mirror is not the boundary

A surface in the console can be more restrictive than the engine, and that is safe: it simply hides an affordance the engine would have allowed. It can never be more permissive. Every write is gated on the capability set at the engine’s write boundary, so a console that offered an action the engine forbids would be rejected there. Treat the console as guidance and the engine as the control.

Change control sits on top

An account can turn on an opt-in four-eyes gate over config changes, so that a second authorised person must approve a config mutation before it applies. It is off by default, and while it is off a config change applies inline exactly as it would without the feature. When it is on, the second approver must differ from the proposer on the stable-subject axis and must hold the same capability the original change required.

This is a distinct mechanism from the dual control that protects a live-data restore, and from the Cloudflare config backup and restore feature. They are easy to confuse because all three involve approval or configuration, so the boundaries are worth stating once.

Mechanism What it gates Where it lives
Four-eyes change control Config mutations such as saving a downpipe, setting a role, or a notify rule, once armed Change control
Restore dual control Applying a restore over live data, binding to the plan hash Dual control for restores
Cloudflare config backup Backing up and previewing your Cloudflare account configuration Covered in the operations section

A map of the section

The pages below make up the identity section. Read them in roughly this order if you are setting up access for the first time.

  • Roles and capabilities is the authoritative role-by-capability table for the six built-in roles, and the home for the owner-reserved capabilities.
  • Custom roles walks through composing a named capability bundle and the guardrails that keep it from exceeding its creator.
  • Group-to-role mapping covers how a verified sign-in’s groups resolve to a role, the strongest-wins combine with a per-person grant, and why a group can never confer owner.
  • Change control explains the opt-in four-eyes gate over config changes, what it covers, and the asymmetric off-switch.

Single sign-on with an external identity provider has its own set of pages covering the SSO model and the OIDC, OAuth2 and SAML connection setup. downpipes supports eight named providers plus generic OIDC and OAuth2; its SAML support is sign-only and service-provider-initiated only, with no way to accept an identity-provider-initiated sign-in. Those pages are part of this section and sit beside the ones above.

The no-custody posture, restated for identity

downpipes holds no secrets it does not need, and the vendor holds nothing at all. Restated for identity, that means the role table, the group mappings and the custom-role catalogue are all metadata. A role entry carries a subject, an email for display, and the grant detail. A custom role carries a name, a label, a capability list, a per-screen visibility map, a presentation hint and a landing screen. None of these records carries a secret or any key material, so they are safe to read back into your own console and safe to record in the audit trail.

Two related points complete the picture. A connection record for an external identity provider holds a secret descriptor, a reference to where the secret lives, rather than the secret value itself. The credential registry that tracks expiries stores labels and dates, not the credentials. And the engine holds no Cloudflare API token at rest. What the engine does hold, by default, is a decryption-capable operational private key under the two-recipient posture, which is how it can verify and work with your sealed archives. The vendor never holds keys or tokens.

Where this fits

  • No-custody trust model explains the custody boundary this section inherits, and what the vendor and the engine each hold.
  • Roles and capabilities is the next page to read for the exact authority each built-in role carries.
  • First run and setup covers becoming the bootstrap owner and the first sign-in, before you grant anyone else a role.
  • Audit log records every authority decision, including the operator identity behind it, and is tamper-evident.

Last updated .