Skip to main content

Turn on email sign-in

app.identity.mode: local makes Prism its own front door: only allowlisted emails can sign in, each sign-in mails a link that works once, and owning the mailbox is the whole credential — there are no passwords anywhere in it. This is the multi-user path for a deployment with no IdP integration yet, and it is replaced later by easyauth or iap — see Sign in with Entra ID — without anyone losing their access.

Their saved work is a separate question, and worth knowing before you choose: saved prompts, conversations and feedback key on the identity the front door asserts, which under local mode is the email address and under an IdP is usually a provider-issued id. Switching therefore hands everyone a clean slate unless the proxy is configured to keep asserting the address; the last section of the Entra page has the setting.

Identity and roles is the reference for what each value means. This is the order to do them in, and the check that stops you discovering a problem at the worst moment.

Why the order matters. Every value below can be right, every pod can be running, the self test can be green on every other line — and the install is still dead on arrival if your relay will not deliver to the one person who can let anybody else in. There is no password to fall back on and no second door. So the relay is proved before anyone relies on it, and the recovery path is worth reading before you need it rather than after.

1. Decide who the bootstrap administrators are​

app.auth.superAdmins is a list of emails, and it is the only way anyone signs in at first: those people log in, then add everybody else on the App users page (/admin → App users).

Pick at least two, at different mailboxes. This is the cheapest insurance available against the recovery procedure at the bottom of this page, and the one moment where adding a colleague costs nothing.

2. Gather what the relay needs​

ValueWhat it is
smtp.hostyour relay's hostname
smtp.port587 for STARTTLS, 465 for implicit TLS
smtp.tlsstarttls, implicit, or none. Any other value fails at render, so an unknown setting cannot quietly mean cleartext.
smtp.fromAddressthe sender. It must be an address your relay accepts MAIL FROM for — this is the single most common reason a relay refuses.
smtp.usernameonly if your relay authenticates. Empty means no AUTH, which is normal for a relay that trusts network position.
smtp-passwordthe Secret key for that AUTH password, if there is one. Never a values file.
app.auth.baseUrlthe external URL your users browse to. The emailed link points at it and the pod cannot infer it — get this wrong and links arrive pointing somewhere nobody can reach.

Two more with sensible defaults: app.auth.magicLinkMinutes (how long a link stays valid) and app.auth.sessionDays (how long the cookie lasts).

Certificates are verified by default, chain and hostname, on both TLS modes. If your relay presents a private-CA certificate the pod cannot verify, the right fix is at the relay. smtp.tlsVerify: false keeps TLS but trusts whoever answers — on the connection that carries sign-in links, so take that knowingly or not at all. For a relay with no TLS, smtp.tls: none is the honest setting rather than an unverified handshake.

3. Confirm the pod can reach the relay​

Outbound to smtp.host:smtp.port from the namespace, which is a firewall rule your cluster may not already have — mail relays are often on a different path from HTTPS egress:

nc -z -w 5 <relay host> <relay port> && echo open

Run it from a pod in the target namespace, for the reason in Prove the egress: a laptop that can reach the relay proves nothing about what the namespace is permitted to do.

4. Upgrade​

helm upgrade <release> <chart> -n <namespace> -f <your values file> \
--set app.identity.mode=local \
--set app.auth.baseUrl=https://<your host> \
--set 'app.auth.superAdmins={[email protected],[email protected]}' \
--set smtp.host=<relay> --set smtp.fromAddress=<sender>

The modes are mutually exclusive and the app refuses to start with more than one configured. If anything required is missing, the install fails at render or the app refuses to boot with a log line naming every missing value — which is deliberate. A pod that came up anyway would serve a sign-in page whose emails go nowhere.

5. Prove the relay before anyone depends on it​

Run the self test. Its smtp relay line connects, negotiates TLS, authenticates if a username is set, and then asks the relay — address by address — whether it would deliver to each bootstrap administrator. It does this with MAIL FROM/RCPT TO and then RSET/QUIT, never sending a message, so running it repeatedly cannot spam anyone.

The per-address detail is the point. A relay that accepts your domain in general and refuses one specific address is a green line on any check that stops at "the relay answered", and a dead install for the person that address belongs to.

6. Sign in, then hand out access​

Open the app, request a link, click it. One thing worth knowing before you raise a support call about it: corporate mail scanners that pre-fetch links do not consume the token. The link opens a confirmation page, and only its "Continue to Prism" button — a form POST, which scanners never submit — spends it. A scanned link still works when the person clicks it.

From /admin → "App users", add everyone else. They are ordinary users; only the emails in app.auth.superAdmins start as super admins.

What an upgrade does to the admin list​

Seeding is additive, never reconciling. Every boot creates a super-admin row for any listed email that lacks one, and touches nothing else. Two consequences that surprise people:

  • Shortening the list revokes nobody. Revoking an administrator is done in-app — demote or remove on /admin → App users — and for a bootstrap admin you must also remove them from app.auth.superAdmins, or the next restart re-adds them.
  • Re-listing a demoted admin re-promotes nobody. Seeding never touches an existing row, so an address the allowlist has seen before keeps whatever role it has now. The skipped seed is logged as seed_skipped_existing, which is why an upgrade can honestly report having added nobody.

One rule is enforced on top: the last super admin can never be removed or demoted. Hand an install over by promoting the new owner first, then demoting yourself.

Locked out — nobody can sign in​

The break-glass path needs cluster access rather than a Prism login, which is what makes it break-glass. Add an email to app.auth.superAdmins and helm upgrade.

It must be an address the allowlist has never seen — per the rule above, a listed address that was demoted in-app stays demoted, so re-listing the person who locked themselves out achieves nothing. Use a fresh one.

For a diagnostic report while locked out, the self-test CLI runs through kubectl exec with no sign-in at all — see the self test.

Three places, in this order: the self test's smtp relay line; the app's app_events table or its log, which records every refused request — an address not on the allowlist, an address rate-limited (three links per address per 15 minutes), or a delivery failure as auth_email_failed with the relay's own error; and then spam.

The sign-in page deliberately says "check your email" in all of those cases rather than telling an unauthenticated visitor which addresses exist. The operator's records are where the truth is.

When auth_email_failed carries a TLS error, the symptom decides the fix and the two look alike: Local sign-in separates a certificate the pod cannot verify from a handshake that stalls, which want opposite settings.

If you are stuck: send the self test screenshot — the smtp relay line carries the relay host, port, TLS mode and sender, and never the password — and the auth_email_failed event if there is one. Between them they distinguish a relay that refused from a message that was accepted and lost downstream, which are different teams' problems.