generic_oidc provider also create new accounts — but only for email addresses in a domain the hub has proven it controls via DNS.
This is the “company SSO” pattern: your team registers acme.com, proves DNS ownership, and from then on any new @acme.com member who authenticates through your Okta / Azure AD / Auth0 provider gets a member.dev account created for them automatically.
How it works at a glance
generic_oidc provider may create a brand-new account for an in-domain email. Everything else (connect flow, Facebook, generic OAuth2, row-1 returning logins) is unchanged from v1.
The connect-first rule
A verified-domain provider creates accounts — it never merges into an existing one. If a member already has a member.dev account withalice@acme.com (created via Google or a magic link, for example), logging in through the acme.com OIDC provider will not silently attach to that account. Alice will see a generic error and must sign in using her existing method, then connect the provider while logged in.
This is intentional and permanent. Silent email-based merges from a custom IdP would allow any hub owner who controls a domain to take over arbitrary member accounts.
One owner per domain
A domain may be verified by at most one hub globally. If another hub tries to verify the same domain, the/verify call returns 409 domain_already_owned. Domains are owned at the hub level and managed under the team-admin API.
Public email domains (gmail.com, outlook.com, yahoo.com, and all free-provider domains) cannot be verified — the backend rejects them at the POST /verified-domains step.
Exact full-domain match — verifying acme.com does NOT cover eu.acme.com (each subdomain must be registered and verified separately).
Step 1 — Register a domain
txt_record_host and txt_record_value are pre-computed — copy them verbatim to your DNS provider.
Step 2 — Publish the DNS TXT record
In your DNS provider (Route 53, Cloudflare, Google Cloud DNS, etc.), create a TXT record:
The record is published on a dedicated challenge subdomain — it does not interfere with other DNS records on
acme.com (SPF, DKIM, existing TXT entries, etc.).
Allow DNS propagation (typically seconds to a few minutes, though up to 48 hours in theory).
Step 3 — Verify ownership
Once the record is live, trigger the verification check:/verify as many times as needed until the DNS change propagates.
Step 4 — Enable a generic OIDC provider for the hub
If you haven’t already, register ageneric_oidc provider for the same hub. See Configure an external-login provider for the full setup. The verified-domain trust attaches to the hub — all generic_oidc providers configured on that hub can auto-create accounts for verified domains.
Once both the domain is verified and the provider is configured and enabled:
alice@acme.comvisits the hub and clicks “Log in with Acme SSO”.- The backend redirects her to the OIDC provider, authenticates her, and receives a signed id_token with
email: "alice@acme.com"andemail_verified: true. - The backend checks: is
acme.comverified for this hub? Yes. Does a contact foralice@acme.comalready exist? No. → Creates a new contact (JIT) and issues a token pair. - Alice is logged in, no manual connect step required.
Domain lifecycle management
List all domains for a hub
pending and revoked entries.
Retrieve a single domain
Remove a domain (revoke)
Freshness checks
The backend re-verifies that the DNS TXT record is still present before creating any new account (approximately once per hour per domain). If the TXT record has been removed, the domain is automatically revoked and new-account creation fails. Existing members are not affected. Keep the TXT record in DNS for as long as you want the auto-create behavior to remain active.Domain attributes reference
Common errors
Security notes
- Exact-domain match only. Verifying
acme.comdoes not grant trust toeu.acme.comor any other subdomain. - Signed email required. The OIDC provider must return
email_verified: truein a signedid_token. Generic OAuth2 providers (no id_token) never earn domain trust even if a domain is verified. - No enumeration. All failed login attempts from a
generic_oidcprovider that find an existing account return the same generic error — the specific reason (account_exists_connect_required) is written to the audit log only. - Public domains blocked. The Public Suffix List is used to block free-provider and public-suffix domains at registration time.
registration_enabledstill applies. If the hub has disabled open registration, the domain-verified auto-create path is also blocked — the verified domain is a trust mechanism, not a registration bypass.
See also
- Log in with an external provider — the member-facing flow (v1 + v2)
- Configure an external-login provider (Admin) — register Google, Facebook, generic OIDC/OAuth2
- Login with Hub — the inverse direction (hub as OIDC Identity Provider)