Self-Registration & Public Catalog
Who this guide is for: Tenant admins who want people to create their own learner accounts (instead of admin-only invites), and to expose selected courses in a public, unauthenticated catalog.
Overview
Self-registration lets visitors create their own learner account from a public page at
/register. You control whether it’s on, who may register, and whether new accounts need
email verification and/or admin approval before they can sign in. You can also publish a
public course catalog at /browse that anonymous visitors can browse before signing up.
Everything is off by default — nothing is exposed until you opt in.
Enabling self-registration
- Go to Admin → Settings → User Management → Self-registration.
- Turn on Allow self-registration. A public form appears at
/register. - Choose your gates (all independent):
- Require email verification — the learner must click a link emailed to them before they can sign in (recommended; on by default).
- Require admin approval — new accounts land in a Pending approvals queue and can’t sign in until you approve them.
- Require CAPTCHA — adds a Cloudflare Turnstile challenge to the form to deter bots (on by default).
- Optionally restrict email domains: enter one domain per line (e.g.
acme.com). Only matching addresses may register. Leave blank to allow any domain. - Save.
Configuration reference
| Setting | Values | Effect |
|---|---|---|
| Allow self-registration | on / off (default off) | Master switch for the /register page |
| Require email verification | on (default) / off | Blocks sign-in until the emailed link is clicked |
| Require admin approval | on / off (default off) | Routes new accounts to the approval queue |
| Require CAPTCHA | on (default) / off | Turnstile challenge on the form |
| Email-domain allowlist | list of domains; blank = any | Server-side enforced; exact-match (sub-domains don’t match) |
CAPTCHA keys. Turnstile needs
NEXT_PUBLIC_TURNSTILE_SITE_KEYandTURNSTILE_SECRET_KEYset in the environment. CAPTCHA is enforced only when the Require CAPTCHA toggle is on and both keys are configured. If the keys are missing, the challenge can’t render, so CAPTCHA is simply not enforced and registration proceeds without it — set both keys to turn real bot protection on.
Terms of Service (optional)
On the same page, the Terms of Service box lets you paste text that appears on the registration form with a required “I accept” checkbox. Leave it blank to skip. Updating the text re-prompts new registrants only (existing users are unaffected).
Approving registrations
When Require admin approval is on:
- New sign-ups appear under Settings → User Management → Self-registration → Pending approvals.
- Click Approve to activate the account (the learner can then sign in) or Reject (the account is blocked and soft-deleted).
- Every approve/reject is written to the audit log.
Until approved, a pending learner who tries to sign in sees a “your account is awaiting approval” message — never a generic error.
Public catalog
Expose selected courses to anonymous visitors:
- Open a course → Catalog Settings → turn on Public catalog.
- The course must also be Published and not Hidden to appear.
- Visitors browse the catalog at
/browse(no sign-in required). Each tile shows the course price (or Free), and clicking a course opens a detail pop-up with its description and outline.
Only courses you explicitly opt in are public — the flag is off by default for every course.
Anonymous landing
When self-registration is on, anonymous visitors who land on your portal’s root URL are
taken straight to the public catalog (/browse) — the storefront front door — instead of the
sign-in page. When self-registration is off, the root URL goes to Sign in as before,
and the Register button is hidden on the catalog (there’s no public sign-up to send them to).
Signed-in users always go to their normal home.
Selling courses from the catalog (e-commerce)
If you’ve set course prices (Course pricing & coupons) and connected Stripe (Stripe Connect payments), visitors can add paid courses to a cart and buy several at once. Checkout requires them to sign in or register first (honoring every self-registration setting above — domain allowlist, CAPTCHA, Terms of Service, and approval). Payment is taken on Stripe’s secure hosted page; on success the buyer is enrolled in every course in the cart. Free courses aren’t sold through the cart — learners enrol in those from the course page.
How accounts are gated at sign-in
| State | Sign-in result |
|---|---|
| Active + verified | Allowed |
| Pending approval | Blocked — “awaiting approval” |
| Email not verified (self-registered) | Blocked — “confirm your email” |
| Rejected | Blocked (treated as disabled) |
Only self-registered accounts are subject to the email-verification gate — admin-created, SCIM, and imported users are never affected.
Troubleshooting
| Problem | Cause / fix |
|---|---|
/register shows “Registration isn’t available” | Self-registration is off — enable it in Settings. |
| ”Registration is restricted to approved email domains” | The email’s domain isn’t on the allowlist. Add it, or clear the allowlist to allow any. |
| ”CAPTCHA verification failed” (and no CAPTCHA box is shown) | The Require CAPTCHA toggle is on but the platform’s Turnstile keys aren’t set, so the widget can’t render. CAPTCHA is now enforced only when both keys are configured — set NEXT_PUBLIC_TURNSTILE_SITE_KEY + TURNSTILE_SECRET_KEY to enable real bot protection, or turn off Require CAPTCHA. |
| ”CAPTCHA verification failed” (with a visible challenge) | The challenge wasn’t completed, or the keys are incorrect. Complete the challenge / verify the Turnstile keys. |
| Sign-up form loads but the CAPTCHA box never appears (form can’t be submitted) | The browser blocked the Turnstile script. This affected all portals briefly before the current release (fixed platform-side); if it persists, hard-reload (Ctrl+Shift+R) and check for a browser extension blocking challenges.cloudflare.com. |
| Learner verified email but still can’t sign in | Approval is also required — approve them in the queue. |
A course isn’t showing at /browse | It must be Published, not Hidden, and have Public catalog on. |
| The portal root goes to Sign in, not the catalog | The anonymous landing routes to /browse only when self-registration is on. Enable it, or send visitors to /browse directly. |
| A public course has no price / shows “Free” | No active price is set. Add one in the course editor (Course pricing & coupons). |
| Buyers see “This seller isn’t accepting payments yet” at checkout | Stripe isn’t connected. Finish Stripe Connect onboarding. |
| Didn’t receive the verification email | Check spam; confirm SES is configured for the tenant sender. The link expires in 24 hours. |
| ”This portal has reached its plan’s user limit” | Free plan is at its 5-active-user cap — registration cannot add a 6th account. Free a seat (deactivate a user) or upgrade in Admin Panel → Settings → Billing. |