Skip to content

Authentication modes

Every public access entry on an application carries an authentication mode. The check happens at Caddy on the device hosting the workload, before any request reaches the workload itself. The five modes:

policies: { auth: { modes: [none] } }

Anyone who knows the URL can reach the service. No credential check. Use for marketing sites, public APIs, anything genuinely meant to be open.

If you don’t want the URL itself to be discoverable, pair none with a generated (random-suffix) hostname. The hostname acts as a weak shared secret — fine for low-stakes sharing, not fine as a real access control.

edgible-login — Edgible organization members only

Section titled “edgible-login — Edgible organization members only”
policies: { auth: { modes: [edgible-login] } }

A request reaches the workload only if the requester has a valid Edgible session for a member of your organization. Visiting in a browser triggers a sign-in flow; if the user is a member of the right org, the request goes through and the user stays logged in for the session.

Use for internal tools — dashboards, admin UIs, on-call runbooks. It removes the need to run a VPN: your team logs into Edgible (which they already do) and the existing session also serves as the authn for these tools.

The check is membership only — a per-app role model isn’t part of edgible-login mode. If you need finer-grained authorization, do it inside your application after the request lands. To restrict to a subset of organizations, set policies.auth.allowedOrganizations.

policies: { auth: { modes: [api-key] } }

The request must include a bearer token issued for this application. Caddy verifies the token against a list the agent receives from the control plane.

Issue a token with the CLI:

Terminal window
edgible application api-keys create \
--app-id <app-id> \
--name "ci-deploy-key" \
--expires 2026-12-31

Send it on every request:

Terminal window
curl https://api.example.com/v1/things \
-H "Authorization: Bearer <key>"

Tokens can be listed (api-keys list), deleted (api-keys delete), and given an expiry. Rotation is your responsibility — the platform doesn’t auto-rotate API keys.

Use for programmatic access from scripts, CI pipelines, partner integrations, or any other machine consumer.

short-code — rotating short-lived tokens

Section titled “short-code — rotating short-lived tokens”
policies: { auth: { modes: [short-code] } }

Like api-key, but the token is shorter, the lifetime is shorter, and it can be capped to a maximum number of uses. Designed for sharing brief access — “send this link to the contractor for the next two hours.”

Terminal window
edgible application short-codes create \
--app-id <app-id> \
--name "contractor-access" \
--expires "2026-04-30T18:00:00Z" \
--max-uses 50

The created code is included in the URL or in a query parameter, depending on how the consumer wants to use it. Toggle a code on or off without deleting it (short-codes toggle).

Use when you want to share access without provisioning an account, and you want the access to disappear on its own.

app-native — your application’s own login is the control

Section titled “app-native — your application’s own login is the control”
routes:
- path: /*
target: { workload: web, port: http }
policies: { auth: { modes: [app-native] } }

The platform passes the request through unchanged: the application’s own authentication is the declared access control. This is deliberately distinct from nonenone declares the path genuinely anonymous, while app-native records that a check exists, just not a platform one. Two constraints, both enforced:

  • Exclusive. app-native cannot be combined with any other mode — pass-through plus a platform check is contradictory, and the platform rejects the combination.
  • Path-scoped. Declare it on a routes[] entry (or a legacy pathPolicies entry), not as an access-level policies.auth.modes value — the platform rejects it at the root.

auth.modes is a set — list more than one and they are OR-combined: a request that satisfies any listed mode is served. The common case is letting both humans and machines reach the same endpoint:

policies: { auth: { modes: [edgible-login, api-key] } }

A browser with no credential is redirected to the Edgible login (the edgible-login behavior), while a request carrying a valid Authorization: Bearer <key> is served directly (the api-key behavior) without the redirect.

none is exclusive — it means “no check at all,” so it cannot be combined with another mode; the platform rejects [none, …].

auth.modes combines auth methods on one endpoint — it is not how you give different audiences different policies. For different auth per path on the same hostname, use a routes[] table with per-route policies.auth. For genuinely different surfaces — separate hostnames, separate TLS — declare multiple access entries, one per audience, each with its own auth.modes (requires agent ≥ 1.2.0 on the target device). See Multiple access entries for the worked example.

Edgible’s auth modes authenticate the caller — they don’t authorize the call beyond membership. None of them inspect the request body, and none of them read JWT claims for your application. Per-path scoping exists (routes[] carries per-route policies.auth), but the check is still caller authentication, not authorization. Anything beyond “the caller has a credential” lives inside your workload — Caddy hands the request through, and you decide what the user is allowed to do.

For WAF-style request inspection, IP allow-lists, and rate-limiting, see the additional policies fields documented in the YAML reference.