API Authentication
Default Mode (Authentication Disabled)
Out of the box, Orchard runs with authentication disabled (orchard.security.oauth2.enabled: false). In this mode, all requests are permitted without a token, and every request is resolved to the same shared "local" cultivator — there's no per-request identity check:
curl http://localhost:8080/api/grovesThe default cultivator's UUID is 11111111-1111-1111-1111-111111111111 unless overridden via the orchard.dev.default-cultivator-id server property. Trowel doesn't send any identity header in this mode, and the server doesn't look for one.
OAuth2 / JWT (Production)
For production deployments, enable OAuth2 in application.yml:
orchard:
security:
oauth2:
enabled: true
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: https://fence.your-domain.comWith OAuth2 enabled, the server validates JWT tokens from the configured issuer. Pass the token via the Authorization header:
curl -H "Authorization: Bearer <jwt-token>" http://localhost:8080/api/grovesThe API's OAuth2 resource server config is issuer-agnostic, so any OAuth2/OIDC-compatible identity provider (Keycloak, Auth0, Okta, etc.) can technically issue the issuer-uri. In practice, Orchard ships its own first-party authorization server, Fence, as part of the platform — most deployments point issuer-uri at Fence rather than standing up a separate IdP.
Fence
Fence is Orchard's built-in OAuth2/OIDC authorization server (the fence module). It issues and validates the JWTs described above, so self-hosters generally don't need to configure an external identity provider just to turn on authentication — see Deployment for running Fence alongside the API server.
Fence itself can delegate the human sign-in step to an upstream identity provider (configured under fence.upstream) rather than storing passwords — this only affects how a cultivator proves who they are to Fence, not how the Orchard API validates tokens, which always happens against Fence's own issuer.
CLI login (device authorization grant)
Trowel authenticates via the OAuth 2.0 device authorization grant (RFC 8628):
trowel loginThis requests a device code from Fence, opens your browser to a verification URL with a short code to confirm, then polls Fence until you approve the request. On success, Trowel stores the access and refresh tokens in ~/.orchard/config.toml and sends the access token as a Bearer Authorization header on subsequent requests automatically. See trowel login in the CLI Reference for flags.
SSH gateway tokens
The SSH gateway accepts a short-lived owner token as an SSH password, as an alternative to a registered SSH key. Exchange a Fence-issued access token for one:
curl -X POST https://fence.example.com/gateway-token \
-H "Authorization: Bearer <access-token>"{ "token": "eyJhbGciOiJSUzI1NiIs..." }The token is valid for 5 minutes and is scoped to the gateway only (aud: orchard-gateway, scope: gateway-ssh). Connect with ssh -p 2222 <grove-id>@<gateway-host> and paste the token at the password prompt. The gateway accepts it only if the token's email belongs to the grove's owner. The access token must carry an email claim, or Fence returns 400 Bad Request.
When OAuth2 is disabled, anyone with network access to the API is treated as the same shared default cultivator — there is no per-cultivator isolation at all. Always enable OAuth2 (and run Fence) in production environments exposed to a network.