Authentication
The platform authenticates users through its own auth service — a GoTrue
deployment (mono-auth) that this chart always runs alongside the
applications, with its own database. There is no external auth project to point
at and no switch to turn it on: edisyl.auth.enabled defaults to true, and
the render refuses anything else while the API or the web application runs.
Users sign in with SAML through your identity provider, and nothing else. Email, phone and anonymous sign-in are pinned off, and no social provider is configured — Google sign-in was removed in chart 0.46.0. Turning SAML off would leave no way in at all, so the render refuses that too.
Declare your identity provider
Section titled “Declare your identity provider”The identity provider your users sign in through — the deployment owner’s IdP
— is declared in values, under deploymentIdp. The chart refuses to render
without it. The configurator’s Single sign-on
step asks for it and writes this block.
deploymentIdp: # Exactly one of metadataUrl or metadataXml. metadataUrl: "https://idp.example.com/app/saml/metadata" # The email domains that sign in through this IdP. domains: [example.com]Exactly one metadata source. Set metadataUrl or metadataXml — the
configurator’s “IdP metadata URL” or “IdP metadata XML” — never both and never
neither:
-
metadataUrlmust be HTTPS with a host. A URL lets the auth service pick up an IdP’s overlapping certificate rotation without a redeploy; a hard cutover still needs one. Whoever serves that URL can change the IdP’s signing certificates at any time, so use a URL only when it is the IdP vendor’s own. -
metadataXmlis the metadata document itself, for an IdP that publishes a file rather than a URL. Keep it under about 120 KB — past that the Job that registers it cannot start — and use a block scalar:deploymentIdp:metadataXml: |<?xml version="1.0" encoding="UTF-8"?><md:EntityDescriptor ...>...</md:EntityDescriptor>domains: [example.com]
The routed domains. domains (“Email domains routed to it”) is a non-empty list of bare email domains —
example.com, with no @ or scheme. A user who types an address on one of
them is sent to this IdP, and everyone it signs in on these domains joins the
deployment owner’s organization. The list is exact: a domain removed here is
released from the provider on the next deploy, so when you adopt an existing
registration, list all of its domains. The addresses in
bootstrap.adminEmails must be on one of them, or the owner row they create
is one nobody can sign in as.
bootstrap.enabled must stay true. The Job that registers the IdP renders
only with bootstrap on, so the render refuses deploymentIdp with it off.
Mock SAML, which signs in any address it is asked for, is refused unless both
env and config.appEnv are local. It is for a throwaway local cluster only.
In your identity provider
Section titled “In your identity provider”Create a SAML application in your IdP before the install, with these two endpoints on the auth service’s public host:
| Entity ID and SP metadata | https://auth.<your-domain>/auth/v1/sso/saml/metadata |
| ACS (reply) URL | https://auth.<your-domain>/auth/v1/sso/saml/acs |
An IdP that imports SP metadata can take both from the first URL. Make sure
the assertion carries the user’s email address. Then take the IdP’s own
metadata from the application: Okta and Entra ID publish a metadata URL for
it; Google Workspace publishes XML only, so it goes in metadataXml.
The cluster has to reach a metadata URL: the registration Job fetches it from inside the cluster, so egress to the IdP’s host must be open.
How it is registered
Section titled “How it is registered”The chart registers the IdP for you. A Job named
edisyl-idp-reconcile-<hash> registers deploymentIdp with the auth service,
updating an existing registration in place (matched by entity ID) so its
provider id survives, and records that provider id in the database. The API
trusts owner sessions only from the provider recorded there, so declaring the
IdP in values is the whole setup — there is no id to copy back into values and
no registration command to run.
The Job’s name carries a hash of its spec, so it runs again whenever the spec
changes: a change to deploymentIdp, the API image, the chart version, or any
value in edisyl-config. An unchanged release re-applies the finished Job as
a no-op. To run it again without a change — after rebuilding the auth
database, say — delete the Job and upgrade.
A failed registration does not fail helm install. It is a plain Job, not
a hook; on a fresh install it retries until the migrations, the owner
organization and the auth service exist. Wait for it to complete, and read the
provider id from the last lines of its log:
kubectl -n edisyl wait --for=condition=complete job -l app=edisyl-idp-reconcile --timeout=15mkubectl -n edisyl logs -l app=edisyl-idp-reconcile --tail=20On upgrades, helm upgrade --wait --wait-for-jobs makes a failed
registration fail the upgrade, and it is safe there because migrations run
before the upgrade — see Upgrading. Under Argo CD a
failed registration leaves the Application Degraded while the sync itself
completes; delete the Job and self-heal recreates it.
Its database
Section titled “Its database”The auth service does not use the application database. It gets its own —
a login role, a database it owns, and the connection secret both the
deployment and its prep hook read. The chart provisions all three from the
bundled CloudNativePG cluster when edisyl.auth.database.create says so, which
by default follows cnpg.enabled.
With your own PostgreSQL, you provision that database and role and point
edisyl.auth.database.secretName at a Secret holding its connection URI — see
Using your own infrastructure.
The secrets it needs
Section titled “The secrets it needs”Credentials are split by who mounts them, deliberately — a browser-facing server has no business holding a credential that can register an identity provider.
| Secret | Holds | Mounted on |
|---|---|---|
edisyl-auth |
What the service signs with: GOTRUE_JWT_KEYS, GOTRUE_JWT_SECRET and GOTRUE_SAML_PRIVATE_KEY |
The auth pod alone |
edisyl-auth-client |
AUTH_ANON_KEY — the consumer side, what the apps verify against |
The application pods |
edisyl-auth-admin |
AUTH_ADMIN_TOKEN, the credential for the auth service’s admin API |
The API and the edisyl-idp-reconcile Job |
No URL appears in any of them. Where the auth service lives is derived into the platform config from the hostname this chart publishes for it, so the address and the service cannot disagree.
The signing keys are yours to mint
Section titled “The signing keys are yours to mint”GOTRUE_JWT_KEYS is the service’s key set, and the chart cannot generate it —
Helm cannot produce an EC keypair. The API verifies every user token as
ES256, against the key set the auth service publishes at
/auth/v1/.well-known/jwks.json, with the issuer pinned to that same address.
A service configured with only a symmetric secret issues HS256 tokens with no
issuer claim, and then every authenticated request fails with
401 Invalid or expired token — sign-in included. It reads as a credential
problem; it is an algorithm one.
Secrets and signing keys has two ways to mint all of them, and explains why the key set needs both an EC entry and a verify-only HS256 one. They are yours alone — we never generate or hold signing material for a self-hosted deployment.
Signing in
Section titled “Signing in”Sign-in is through the web application, served at edisyl.<config.domain>
unless you set an explicit edisyl.edisyl.ingress.host — for example, to put
it on the apex instead.
Start at the web application’s /login, never from the IdP. Type your email
address first: the SSO button stays disabled until the field holds a domain,
and that domain is what routes to your IdP. An IdP-initiated sign-in never
completes a session, which looks like a failure when it is the wrong entry
point.
The first account that matters is the one in bootstrap.adminEmails: the seed
creates an owner row for that address, and it is what gates creating data
sources and other owner-level objects.
If the address you sign in with does not match one in bootstrap.adminEmails,
you get an owner row nobody can log in as, and your own account owns only its
personal workspace. The seed job is idempotent — adding the address and
re-running helm upgrade links the existing row rather than duplicating it.
Was this page helpful?
Thanks for the feedback.
