In this article
August 4, 2026
August 4, 2026

A practical guide to customizing AuthKit: Hints, branding, and org-specific signup rules

How far you can push screen hints and branding before you need the API, and how to control signup and membership on a per-org basis

Explore with AI
Open in ChatGPT
Open in Claude
Open in Perplexity

Most teams start with AuthKit's hosted UI because it removes an enormous amount of work: password policies, email verification, MFA enrollment, bot detection, and SSO routing all come for free. But as an app matures, support tickets start to cluster around the same theme: "can we skip this screen," "can we make sign-up invite-only for this one customer," "can we stop new people from auto-joining our workspace." These are all solvable without abandoning AuthKit, but the right answer depends on whether you're customizing the hosted experience or replacing it.

This post walks through three related problems: how far you can take AuthKit's hosted UI through hints, branding, and CSS; when it makes more sense to drop to the headless Authentication API instead; and how to shape signup and membership rules at the organization level, including disabling signup and turning off auto-membership.

Start with what the hosted UI already gives you

Before reaching for a custom flow, it's worth knowing exactly what the hosted UI supports, since a lot of "advanced" requests turn out to be a parameter or a dashboard setting away.

AuthKit's authorization URL (GET /user_management/authorize, or the SDK equivalent) accepts several parameters that control where a user lands and what's pre-filled, without you building any UI at all:

  • screen_hint: set to sign-up or sign-in to send a user directly to one screen instead of AuthKit's default detection logic. This only applies when provider is authkit.
  • login_hint: pre-fills the email or username field, useful when your app already knows who's trying to sign in.
  • domain_hint: pre-fills the domain field for Microsoft OAuth or Google SAML connections.
  • organization_id: when passed alongside provider=authkit, the organization is automatically selected during the flow, which skips the organization picker screen entirely.
  • invitation_token: redeems a pending invitation during authentication, which also opens up signup for that user even if signup is disabled environment-wide.

Combining these gets you a long way toward "skipping screens" without writing a custom form: a link from a marketing site can hint sign-up, an invite email can carry both an invitation_token and organization_id, and a returning user's session can pre-fill login_hint so they're not retyping an email address they already gave you.

For visual customization, the dashboard's branding editor covers logos, colors, fonts, page layout (including a two-column split layout with a custom content panel), and custom sign-in and sign-up copy. When that's not granular enough, AuthKit exposes custom CSS scoped to specific pages via the data-hak-page attribute, so you can target things like sign-up/registration, sign-in/password, mfa/enrollment, or organization-selection independently. This is enough to reorder OAuth buttons, restyle the header on just the sign-up page, or add a background image, all while staying on WorkOS's hosted domain and keeping the built-in bot protection, localization, and error handling.

The practical rule of thumb: if the ask is "change how a screen looks" or "change which screen someone lands on," reach for hints, branding, or custom CSS first. These options don't require you to reimplement password resets, MFA, or email verification yourself.

When you have to drop to the password API

Screen hints and CSS get you a customized hosted flow, not a custom-built one. Some requests genuinely can't be satisfied without going headless: fully embedding the login form inside your own app's layout (not a redirect), building a native mobile experience, implementing a multi-step onboarding wizard that interleaves with authentication, or supporting a design system that the content panel and CSS overrides can't replicate.

In these cases, the Authentication API lets you build and own the UI entirely, while WorkOS still handles the credential storage, password hashing, and session issuance behind it. The password grant (grant_type: password) takes an email and password and returns a user object, access token, and refresh token directly, no redirect involved. The same API surface handles email verification codes, Magic Auth codes, organization selection when a user belongs to more than one org, and TOTP for MFA, each as its own grant type with its own pending-token handshake.

Going headless is a real tradeoff, not just more code to write. You take on:

  • Password policy UX: AuthKit enforces your password strength rules automatically in its own forms; in a custom UI, you're responsible for surfacing validation errors clearly before submission.
  • Bot and abuse protection: the hosted UI includes automatic bot detection tuned by WorkOS; a custom form needs its own equivalent, such as rate limiting or CAPTCHA.
  • Localization: AuthKit's hosted pages are translated into dozens of locales out of the box; a custom UI needs its own i18n.
  • Every edge case in the state machine: email verification required, MFA challenge, organization selection, and invitation redemption each surface as a distinct error response that your UI has to handle explicitly, where the hosted flow handles them for you.

A common middle ground worth considering before a full rebuild: keep the hosted UI for sign-up and sign-in, but use hints and branding to get it close enough, and reserve the API-driven approach for one specific screen (say, an in-app "add a teammate" flow) rather than replacing the whole authentication surface.

Org-specific signup and membership rules

The second cluster of requests is less about how a screen looks and more about who's allowed to get in, and that's where WorkOS's organization-level settings do the heavy lifting.

  • Disabling signup entirely. Signup can be turned off per environment from the authentication section of the dashboard. With it off, AuthKit and the API both reject new registrations, with one deliberate exception: a valid invitation token still allows signup, even in an otherwise closed environment. This is the mechanism behind an invite-only launch: seed an initial set of invitations from a script or the dashboard, let existing members send further invites up to a quota, and never expose open registration to the public.
  • Domain policy vs. organization policy. These are the two dashboard-level controls for authentication rules and they're enforced differently. A domain policy applies to every user whose email matches one of an organization's verified domains, regardless of which organization they pick during sign-in, and it's the mechanism for automatically adding domain-matched users as members without an invitation. An organization policy, by contrast, only kicks in once a member has actually selected that organization during sign-in, and it's what you'd use to require SSO or MFA for guest members who don't share the organization's email domain. If a request sounds like "everyone at acme.com should be forced through their identity provider," that's a domain policy; if it's "anyone signing into the Acme workspace needs MFA, including contractors," that's an organization policy.
  • Turning off auto-membership. Two related features are both enabled by default and both independently toggleable in the dashboard: automatic membership by verified email domain, and SSO just-in-time provisioning. When SSO JIT is on, a user whose domain matches a verified organization is automatically created and added as a member the moment they authenticate through that org's identity provider, no invitation required. Disabling either setting is the right move when an IT contact wants to control membership manually through invitations instead, and it's worth calling out that guest users (whose domain isn't verified for the org) already require an invitation regardless, since JIT provisioning doesn't extend to them.

Put together, a few concrete patterns fall out of these controls:

  • Fully closed beta: disable signup, invite everyone by hand or via script, disable auto-membership so even domain-matched users need an explicit invite.
  • Self-serve with enterprise carve-outs: leave signup and JIT provisioning on by default, but set a domain policy on specific enterprise customers to force SSO and stop new members from joining that domain outside their IdP.
  • Contractor access without shared domains: keep JIT provisioning for the core team, but rely on organization policy plus invitations for guests, since they'll never match a verified domain.

Choosing between the three levers

Most "advanced AuthKit" requests reduce to a question of which lever actually controls the behavior: a screen hint or branding change for how something looks or which screen it lands on; the dashboard's signup, domain policy, and organization policy settings for who's allowed in and how they get added; and the Authentication API only when the hosted UI's customization ceiling has genuinely been hit. Reaching for the API first is the most common overcorrection, since it trades a maintained, localized, bot-resistant flow for one you now own end to end, for a problem that a screen_hint and a dashboard toggle might have solved in an afternoon.

For the full parameter list and dashboard walkthroughs referenced here, see the AuthKit documentation.