Set up a custom login domain

A custom domain such as login.acme.com serves every end-user surface of your environment: hosted login, the account portal, the Admin Portal, the OIDC and OAuth endpoints, SSO, SAML and SCIM, and the links in emails. Your own application's domain is not hosted by KeenAuth. The development environment has no custom domains.

Before you start

Step 1: add the domain

Call Add a custom domain. The domain starts in pending_dns and the response lists the DNS records to publish.

Step 2: publish two DNS records

Type Name Value
TXT _akp-verify.<hostname> idp-verify=<26-character base32 token>
CNAME <hostname> <environment-slug>.<region>.edge.keenauth.app

Keep the TXT record in DNS permanently, also after the domain is active. It is the proof of ownership: if the domain changes hands, the previous owner can no longer have the page served.

Both records must be visible. The check runs every 5 minutes for 72 hours, then hourly for 30 days. To restart a stopped check, call Verify a custom domain.

Step 3: check CAA records

If the domain or any parent domain has a CAA record, it must allow both ACME certificate authorities that KeenAuth uses. Otherwise the domain returns to pending_dns with the failure reason caa_blocked, and the dashboard shows the exact CAA line to add. If no CAA record exists, nothing is needed.

Certificate and lifecycle

KeenAuth obtains and renews the TLS certificate for you. A certificate is renewed when less than 30 days of its life remain. If renewal fails for 7 days you get the custom_domain.certificate_renewal_failed event and an email. Event delivery is not available yet; it comes with webhooks in Phase 6A.

Status Meaning Next
pending_dns Added; waiting for the TXT and CNAME records Both seen: issuing
issuing Certificate is being issued Issued: active. CAA block: pending_dns with caa_blocked. Not issued within 72 hours: pending_dns with certificate_failed
active In service A failed daily check: degraded
degraded The TXT or CNAME record has been missing for a day or more; the domain still serves Fixed: active. Not fixed for 7 days: disabled
disabled Out of service; the certificate is deleted and sessions on this host are invalidated You restart with :verify: pending_dns
released The domain or the environment was deleted After 30 days of quarantine the name can be added again

An active domain is checked once every 24 hours. Subscribe to the events custom_domain.verified, custom_domain.activated, custom_domain.degraded and custom_domain.disabled to be told when something changes. These events are not available yet; delivery comes with webhooks and the event API in Phase 6A.

Primary domain and removal

One domain of the environment is primary; email links use it. Change it with Make a custom domain primary. When the environment's issuer follows the primary domain, changing the primary domain changes the issuer and is a planned operation scheduled at least 7 days ahead.

A primary domain, or the domain that is the issuer, cannot be deleted (409 custom_domain_in_use). Choose another primary domain first. A domain used as a passkey rpId cannot be deleted or disabled either (409 domain_in_use_by_rp_id).

Several domains in one environment

On Enterprise an environment can have several verified domains. Each domain has its own session cookie, so there is no silent SSO between domains. Passkeys across domains depend on the rpId choice and on the related origins list, which holds at most 5 registered-domain labels and only active domains of the same environment. Each application can have its own branding on every domain; see Brand your login pages.