Labsco
auth0 logo

auth0-custom-domains

37

by auth0 · part of auth0/agent-skills

Use when setting up, verifying, or troubleshooting a custom Auth0 login domain (e.g. login.example.com). Covers CNAME setup, verification, TLS policy, Multiple Custom Domains, and Management API errors — even if the user just says "use my own domain for Auth0 login".

🧩 One of 7 skills in the auth0/agent-skills package — works on its own, and pairs well with its siblings.

This is the playbook your agent receives when the skill activates — you don't need to read it to use the skill, but it's here to audit before installing.

Auth0 Custom Domains

Drive Auth0 custom-domain work end-to-end: Auth0 Management API, DNS provider, verification polling, and the configuration that stitches everything together. Detects the user's DNS provider (Cloudflare, Route 53, Azure DNS, or other) and automates record creation when the provider supports it.

Overview

This skill is capability-based, not step-based. It groups the work a user might want to do into five distinct capabilities (setup, troubleshoot, manage, remove, health check), each with its own flow in a dedicated reference file. The main SKILL.md acts as a lobby: it holds the capabilities table, key concepts, prerequisites, and common mistakes that apply across all flows. When a user invokes the skill, pick the matching capability from the table, load its reference file, and follow that flow.

The capability design matches how users actually come to Auth0 custom domain work: "set one up," "mine is broken," "change something," "remove one," or "is my setup still working?" Each intent maps to a distinct flow with its own safety checks and hand-offs.

Interaction style

Ask questions as plain conversational text. Never use structured UI widgets (e.g., AskUserQuestion) except for a single yes/no confirmation immediately before a destructive or irreversible action (create, PATCH, delete). For everything else:

  • Capability routing: present a numbered list and wait for the user to reply
  • Input gathering: ask one focused question at a time; wait for a response before asking the next
  • Free-form values (hostnames, domain names, etc.): just ask directly — don't wrap them in a widget that forces a click before typing

Example of the right pattern for capability routing:

What do you want to do?

1. Set up a custom domain
2. Troubleshoot verification
3. Manage an existing domain
4. Remove a domain
5. Check domain health (read-only, safe starting point)

Example of the right pattern for a single input:

What's the hostname you want to set up? (e.g., login.example.com)

Error-code triage — CHECK THIS FIRST

If the user's message is primarily about an HTTP error code from the Management API (e.g., "I got a 403", "why is this returning 409?", a pasted error body, a log entry with a status code), answer from this table first. Do not default to general Auth0 knowledge — it leads to wrong advice on the Free-tier 403 case in particular. Only after the error-code answer, offer to route into the matching capability if the user wants to continue (e.g., "want me to walk through Set up with that fix in place?").

Status and contextCorrect diagnosis and fix
403 on POST /custom-domains (Free tier)Not a plan-tier problem. Custom domains are available on all plans including Free (confirmed in Auth0 docs: "To set up a free custom domain, Auth0 tenants must have a valid credit card on file for verification purposes and fraud prevention. The credit card will not be charged."). Fix at Dashboard → Tenant Settings → Billing by adding a card. Do NOT suggest a plan upgrade.
403 on POST /custom-domains with type: self_managed_certsThis is a plan issue. Self-managed certs are Enterprise-only. Either downgrade to type: auth0_managed_certs (works on all plans) or upgrade to Enterprise.
409 on POST /custom-domainsDomain already exists on this tenant or another. Run auth0 domains list to check; if on another tenant the user owns, delete it there first. Do not retry a fresh create.
400 on PATCH /custom-domains/{id} with type in bodytype is fixed at create time and rejected by PATCH. Route to delete (capability 4) + recreate (capability 1). Warn about auth downtime during the cutover.
400 with operation_not_supported on relying_party_identifierFeature-flag gate on the tenant. Retry without relying_party_identifier and ask Auth0 support to enable the flag.
404 on any custom-domain endpointWrong custom_domain_id, or wrong tenant. Verify with auth0 tenants list + auth0 domains list.
429Rate limited. Back off; the skill's verify-poll backoff pattern (5s, 10s, 20s, 30s, 60s) avoids this.

Full error-code reference with all cases and resolutions: references/api.md#error-codes.

Capabilities

When this skill is invoked and the user is NOT asking about an error code, ask the user which capability they want using a plain numbered list (see Interaction style above). Route to Check domain health first when the user reports a problem without a specific known cause, or when they're unsure which capability they need; it's the safe, read-only starter that will point them to the right follow-up.

#CapabilityWhat it does
1Set up a custom domainEnd-to-end: create the domain in Auth0, detect the DNS provider, write the CNAME record (automated on Cloudflare / Route 53 / Azure; guided on other providers), verify ownership, and report what to update in the user's apps. Handles first-time setup and adding to MCD. See references/capability-setup.md
2Troubleshoot verificationDomain stuck in pending_verification or verification failing. Diagnostic ladder: compare DNS to expected, check for proxies / CNAME flattening / conflicting records / propagation / private-zone issues, then retry. See references/capability-troubleshoot.md
3Manage existing domainsSurgical edits on already-configured domains: set or change the default (for MCD), update TLS policy, configure the custom client IP header, set the relying party identifier for passkeys, manage per-domain metadata (up to 10 key-value pairs readable from Actions), list domains and show status. Intent-driven. Certificate type is fixed at create time; PATCH rejects type changes. See references/capability-manage.md
4Remove a custom domainDelete a domain safely: warn if it's the default, surface dependent applications, delete in Auth0, clean up the CNAME in DNS. See references/capability-remove.md
5Check domain healthRead-only: list all custom domains, check DNS records match expected values, surface default-domain config, flag anything needing attention. Safe starter capability. See references/capability-health.md

Pick a capability, then follow the flow in its reference file. The Prerequisites and Key Concepts sections below apply across all capabilities.

Key Concepts

ConceptDescription
CNAME RecordDNS record pointing your custom domain to Auth0's edge (e.g., {tenant}.edge.tenants.auth0.com). Must stay in DNS permanently for certificate renewal
Auth0-Managed CertificateAuth0 provisions and auto-renews TLS certs every ~3 months. Default and recommended. Type is fixed at create time and cannot be changed via PATCH
Self-Managed CertificateTLS terminates at a reverse proxy (Cloudflare, CloudFront, Azure Front Door, or GCP LB). Enterprise only; verification uses TXT instead of CNAME. Type is fixed at create time and cannot be changed via PATCH; to change, delete and recreate the domain
NS DetectionLooking up the root domain's nameservers to identify the DNS provider and route to the correct automation tier
Multiple Custom Domains (MCD)Enterprise feature; up to 20 domains per tenant for multi-brand or multi-region
Default Custom DomainWhen MCD is configured, the domain used when a Management API call doesn't send the auth0-custom-domain header
Relying Party Identifier (RPID)Per-domain relying_party_identifier that decouples the custom domain hostname from the passkey rpId. Set at create or via PATCH. Lets you serve auth at login.example.com while passkeys bind to example.com for cross-surface reuse
TLS Policytls_policy on the domain controls minimum TLS version / cipher posture for Auth0-managed certs. Default recommended. Set at create or via PATCH
Custom Client IP Headercustom_client_ip_header tells Auth0 which request header carries the real client IP when traffic passes through a reverse proxy. Valid values: true-client-ip, cf-connecting-ip, x-forwarded-for, x-azure-clientip. Set at create or via PATCH
Domain MetadataUp to 10 custom key-value pairs attached to a custom domain (keys and values ≤ 255 chars). Read from Actions via event.custom_domain.domain_metadata for per-domain logic (region, brand, env tagging)

Full schema and token / iss behavior live in references/advanced.md.

  • auth0-branding: Customize Universal Login appearance (page templates require a verified custom domain)
  • auth0-organizations: Organization-specific branding for B2B multi-tenancy

References

External Docs