Putting Hosted Auth Pages on Your Own Domain

·4 min read

custom-domainsoauth2dnstls

Hosted login pages are the right default. The authorization server owns the credential handling, your application never touches a password, and you inherit the provider's work on rate limiting, breach detection, and passkey support.

The usual cost is the address bar. Your user is on example.com, clicks sign in, and lands on example-prod-3.someauthvendor.com. That moment is where the flow feels wrong — it's the same visual pattern as a phishing redirect, and users who have been trained to check the domain will hesitate exactly when you need them not to.

Mapping a custom domain fixes it. Here's what actually changes.

What moves, and what doesn't

After mapping, every endpoint your users touch is served from your domain:

authorization_endpoint   https://auth.example.com/oauth2/authorize
token_endpoint           https://auth.example.com/oauth2/token
jwks_uri                 https://auth.example.com/.well-known/jwks.json
end_session_endpoint     https://auth.example.com/oauth2/logout

The tenant's canonical hostname (<tenant>.<region>.authaction.com) keeps working. Mapping a domain adds a route; it doesn't remove one. That matters during migration — you can point a staging client at the canonical host and production at the custom domain, and both function.

The cookie argument

Branding is the visible reason. Cookie behaviour is the one that bites you later.

An authorization server on a vendor domain is a completely separate site from your application as far as the browser is concerned. Any cookie it sets is third-party, and third-party cookies are now blocked by default in Safari and Firefox and increasingly restricted in Chrome. That affects silent re-authentication, session checks in an iframe, and anything relying on the authorization server recognising a returning user without a full redirect.

Serve auth from auth.example.com while your app is on app.example.com and both are the same registrable domain. Cookies scoped to .example.com are first-party. SameSite=Lax behaves the way you'd expect across the redirect instead of silently dropping.

If you plan to use silent refresh, this is the difference between a design that works and one that quietly degrades as browsers tighten defaults.

Setup

Three steps, and DNS propagation is the slow one.

1. Add the domain in Tenant Settings → Custom Domain. Up to five per tenant, and it can't be a subdomain of authaction.com.

2. Create a CNAME pointing your subdomain at the tenant's canonical hostname:

Type Name Target
CNAME auth.example.com acme.eu.authaction.com

The target follows <tenant>.<region>.authaction.com. The region segment is the one your tenant data lives in — eu keeps it in the EU, which matters if you have data residency obligations.

Use a subdomain, not the apex. CNAME at a zone apex isn't valid DNS, and while some providers offer ALIAS or ANAME records to work around it, an apex dedicated to auth isn't what you want anyway.

3. Verify in the dashboard. AuthAction does a DNS lookup to confirm the CNAME resolves to your canonical hostname. Propagation is usually minutes but the TTL on any previous record governs — if you had something else at that name, wait out the old TTL before assuming the setup is broken.

Certificates

Once verified, TLS is provisioned automatically. Nothing to upload, no CSR, no renewal to diary.

You can check what any deployment is serving:

$ echo | openssl s_client -servername auth.example.com \
    -connect auth.example.com:443 2>/dev/null \
  | openssl x509 -noout -issuer -subject -dates

issuer=  C=US, O=Let's Encrypt, CN=YE2
subject= CN=auth.example.com
notBefore=Jul 29 09:49:12 2026 GMT
notAfter=Oct 27 09:49:11 2026 GMT

Let's Encrypt, roughly ninety days, renewed for you. Each mapped domain gets its own certificate rather than sharing a multi-SAN certificate across tenants — which means the certificate for your domain names only your domain, and nothing about your setup is visible to anyone inspecting another tenant's.

If you want to see this working on live deployments rather than take our word for it, auth.illam.de and auth.mozhilingo.com are both running this configuration. Run the command above against either.

Things that catch people

Registering the new redirect URIs. Your callback URLs don't change, but the authorization server your app points at does. Update the issuer or base URL in your SDK configuration, and confirm the application's allowed origins cover the new domain. A redirect_uri_mismatch immediately after a domain migration is almost always this.

CAA records. If your domain publishes a CAA record restricting which authorities may issue certificates, and Let's Encrypt isn't among them, provisioning fails with an error that doesn't obviously point at DNS. Check with dig CAA example.com before assuming the verification is stuck.

Proxying the CNAME. If your DNS provider offers to proxy the record — Cloudflare's orange cloud being the common case — that breaks the verification lookup and interferes with certificate issuance. Leave it unproxied.

Existing sessions. Cookies set on the canonical hostname don't transfer to the custom domain. Users with a live session will be asked to sign in again after the switch. Worth timing deliberately rather than discovering through support tickets.

Where to look next

The OIDC Discovery tool will fetch and format the configuration a custom domain serves, which is a fast way to confirm the endpoints moved. For the CORS side of a browser client talking to a new auth origin, the CORS Tester shows which headers are present.

Full setup reference is in the custom domains documentation.


Custom domains on the free tier

Map your own domain to your hosted auth pages, with certificates provisioned and renewed automatically. No paid tier, no manual certificate management.

Free, unlimited users. No credit card required.