Skip to content

Registration control

Closing sign-up is not one switch. Rakomi exposes one switch per account-creation path, because the paths have different trust models — so “registration is closed” is a statement about a set of settings, not about a single field.

This page is the list of those paths, in the order to set them.

PathSwitchDefault
Registration mode (tenant-wide ceiling)signup_mode (open / closed / invite_only) — set from the dashboard Settings pageopen
Password / email self-registrationself_registration_enabledopen
Social sign-up — Google, GitHub, Microsoftgoogle_oauth_allow_signup, github_oauth_allow_signup, microsoft_oauth_allow_signupopen
Social sign-up — every other configurable providerthe provider’s own allow_signupclosed, and the provider must be enabled explicitly first
Anonymous sessions, and their upgrade to a permanent accountthe tenant’s anonymous sign-in settingoff
Enterprise SSO — just-in-time provisioningjit_provisioning_enabled on the connection (optionally narrowed by jit_require_group)provisions unless set to false
EUDI wallet sign-inthe EUDI setting for the tenantoff
SCIM 2.0 directory syncadministrator-initiated — not gated by any switch on this page; provisioned via the tenant’s own API token, never a stranger’s actionalways available when SCIM is configured

SCIM 2.0 (RFC 7643 Core Schema, RFC 7644 Protocol) directory sync is deliberately excluded from every switch above. Every other row in this table gates a path a stranger initiates — someone authenticating against your tenant for the first time. SCIM provisioning is administrator-initiated: your own API token acts, not a stranger, so none of the switches on this page — including a closed registration mode — affect it.

signup_mode is the tenant-wide registration-posture ceiling — open, closed, or invite_only. It is broader than self_registration_enabled, which gates the password/email endpoint alone. The ceiling caps password/email self-registration, both anonymous-session-claim variants, EUDI wallet sign-in, the enterprise-SSO just-in-time fallback — and social sign-up, for every provider, Google, GitHub, Microsoft and Apple as well as every other configurable one.

The per-provider allow_signup switches stay meaningful underneath it: they decide which providers admit new users while the mode is open. They cannot re-open a path the mode has closed. The refusal a stranger sees is not one uniform shape across the paths — treat “was the account created” as the contract, not the specific error envelope of any one flow.

Composing the settings: a per-provider override, if set, wins; otherwise the tenant-wide floor (signup_default) applies — and both are capped by the tenant-wide mode above. If the mode is closed, no per-provider override or floor value re-opens registration until the mode itself changes.

invite_only is a fully accepted value: registration is refused unless the person has a live invitation for their exact email address. Send invitations from the dashboard’s Settings page (Owner role) — each one is a single-use, expiring (7-day) token tied to one email address. The invited person completes registration either by following the link in the invitation email, or by supplying their invited email directly to any registration channel:

  • Password / email registration requires the invitation’s own token (carried automatically by the email link, as ?invite=<token> on the register page) — the registrant types their own email into the form, so a bare email match is not enough proof of receipt.
  • Social / OAuth-first sign-up (Google, GitHub, Microsoft, Apple, and every other configurable provider) needs no token — the identity provider’s own verified email claim is the proof, and a matching live invitation for that email is sufficient.
  • Enterprise SSO just-in-time provisioning and EUDI wallet sign-in are capped by the tenant-wide ceiling exactly as they are for closedinvite_only does not add a per-connection invitation step to those channels; use jit_require_group (SSO) or turn off EUDI wallet sign-in if you need to restrict those specifically.

An invitation is single-use: it stops being valid the moment the registration it was for succeeds, and it cannot be reused for a second account.

See the invite-only registration recipe for a runnable, end-to-end example of the password/email variant: validating the token before showing the form, submitting it with invite_token, and handling every refusal shape (including why the register endpoint deliberately answers every invite-related failure with the same opaque code, unlike the more specific validate lookup).

A tenant that existed before this feature shipped never explicitly set signup_mode: its value was derived once, at migration time, from its self_registration_enabled setting at that time (trueopen, falseclosed).

signup_closed_reason is a free-text field visible in the dashboard UI to every admin of the tenant. Do not put personal data about a named third party in it.

Every new tenant starts with signup_mode: open. This is the deliberate platform default — self-serve sign-up “just works” the moment you create a tenant, with no switch to flip first. It is not a placeholder value waiting for you to configure something; it is the intended starting posture for an Auth-as-a-Service tenant.

If you are not ready for strangers to create accounts yet — you are still building, or you want to control who gets in first — switch signup_mode before you publish anything that points at your tenant, not after:

  • invite_only if you want to onboard a known set of people yourself and let them refer others under your control (see the invite-only recipe above).
  • closed if account creation should wait until you flip it back — existing users keep signing in either way (see Existing users always keep signing in).

Setting the mode is entirely yours to do, at any time, from the dashboard Settings page — nothing about the platform’s default forces a particular launch sequence on you. The point of documenting the default here is so it is a conscious choice, not a surprise discovered after a stranger has already registered.

A tenant can turn on minor protection, which requires collecting a date of birth at registration so users under the tenant’s configured age threshold are recognized and handled under the tenant’s own parental-consent policy. This was originally a password/email-only control. It now applies everywhere a stranger can create an account — password/email, every social provider (Google, GitHub, Microsoft, Apple, and every other configurable one), the EUDI wallet channel, and claiming an anonymous session into a permanent account.

Social sign-up itself is not extended with an age-collection step. Instead, when minor protection is on for a tenant, account creation through any of those channels is refused: the visitor is sent back with a message that new-account registration is not available through that method, and is directed to the tenant’s own registration form (which does collect the necessary information) or to contact the tenant administrator.

What an integrator’s application receives:

  • On the hosted consent screen for Google, GitHub, Microsoft or Apple, the browser is redirected back to your application’s OAuth error page with error=minor_protection_signup_blocked.
  • On every other channel — a provider your own client drives directly, and the EUDI wallet channel — the API responds with 403 and error code tenant/social_signup_blocked_minor_protection.

This is the same refusal shape family as signup_disabled above, and the same rule applies: treat “was the account created” as the contract, not the exact envelope of any one flow.

Existing users are unaffected. Signing in with an already-linked provider, and linking a new provider to an account that already exists in the tenant, never evaluate minor protection — only the creation of a brand-new account does.

Minor protection, its age threshold, and whether parental consent is required are tenant-wide settings, configured from the dashboard Settings page next to signup_mode above. They are not a row in the table above because they do not close a path outright — they add an age condition to every creation path that table already covers.

  1. Set self_registration_enabled to false.
  2. Set allow_signup to false for every social provider you have enabled. Each configurable provider carries the flag on its own settings.
  3. If you use anonymous sessions, turn them off for the tenant. Upgrading an anonymous session into a permanent account is a different flow from self-registration and is not covered by the switches above, and the tenant-level anonymous setting is the control for it. Removing the upgrade step from your own UI is not a substitute — the endpoint stays callable by anything holding an anonymous session token.
  4. If you have an enterprise SSO connection, set jit_provisioning_enabled to false on it explicitly. Leaving it unset provisions new users on first successful sign-in, which is usually what an SSO customer wants and is exactly what you do not want while sign-up is closed. jit_require_group narrows provisioning to one directory group if you want it open but bounded.
  5. If you have enabled EUDI wallet sign-in, it admits users on a successful presentation. Turn it off for that tenant if closed sign-up is a requirement.

Steps 3–5 cover features that are off unless you turned them on. If you have not enabled them, they are not open paths for you.

Read the effective state back from GET /v1/auth/config, which reports self_registration_enabled alongside the tenant’s enabled providers. The registration mode and floor (signup_mode, signup_default) are not part of that response — read and set them from the dashboard’s Settings page instead; the public API deliberately does not expose the mode.

Every switch on this page gates account creation. None of them gates login.

A user who already exists in the tenant signs in normally under a closed sign-up — including the first time they use a social provider, provided the email on the provider account matches theirs. Rakomi attaches the provider to the existing account instead of treating it as a new sign-up. A user who does not exist receives a signup_disabled error on the redirect instead of an account.

That is what makes the common invite-only shape work:

Provision your users up front (directory sync, CSV import, or the admin API), close every path above, and let people sign in with the identity provider your company already uses. Colleagues get in. Everyone else is refused.

Two details to get right before relying on it:

  • The match is on the email address. A staff member whose provider account uses a different address than the one you provisioned is a new user as far as Rakomi is concerned, and a closed sign-up refuses them. Provision the address they actually sign in with.
  • Provision users as email-verified. An account imported without a verified email is treated as unclaimed, so the first successful social sign-in on that address takes ownership of it. Importing as verified keeps you in control of who owns the account.

When to use an enterprise connection instead

Section titled “When to use an enterprise connection instead”

The recipe above is an allow-list by provisioning: access is bounded by the set of users you created. It is not an allow-list by domain — there is no setting that means “anyone with an @example.com address may sign up, nobody else.”

If that is what you want, use an enterprise connection (SAML or OIDC) rather than social sign-in:

  • you map your email domains to the connection, so users at those domains are routed to your identity provider;
  • new users are provisioned just-in-time on first successful sign-in, which you can further restrict to a group in your directory;
  • the boundary is enforced by your identity provider — someone outside your organisation has nothing to authenticate against at all.

It also revokes correctly: when your directory disables someone, they lose access. A rule that merely matches on the email domain does not, because the address outlives the employment.

See the SAML SSO guide to set one up.

  • They do not remove an existing user. Closing sign-up affects who can be created.
  • They do not disable a provider. A provider with allow_signup set to false stays available for login — that is the point. To take it off the sign-in screen entirely, disable the provider itself.
  • They do not apply retroactively. Accounts created before you closed sign-up remain.