controller_signup

Controller which displays a form to sign up (rendered from signup.tpl).

It also implements the necessary postbacks to perform the signup and log a user in.

Data flow

The signup page can be reached directly through the signup dispatch rule, or by asking the notification system for a #signup_url{}. The mod_signup observe_signup_url/2 observer stores the caller supplied arguments in mod_server_storage:

#signup_url{
    props = Props,
    signup_props = SignupProps
}

Props are resource properties for the person that will be created or updated, for example a prefilled email, name_first, or depiction_url. SignupProps are signup control values and identities, for example {user_id, Id}, {ready_page, Url}, or {identity, {Type, Key, IsUnique, IsVerified}}.

The observer generates a random check id, stores {CheckId, Props, SignupProps}, and returns the signup URL with xs=CheckId. When this controller renders the page it reads the xs query argument, performs m_server_storage:secure_lookup/2, and only accepts the stored payload when the returned check id matches the query value. Accepted values are exposed to signup.tpl as:

  • props: a map with prefilled resource properties. Empty email values are

    removed so the email step can still ask for an address.
  • signup_props: the stored signup properties as a proplist.

  • email: the prefilled email from props, when present.

Without a valid xs, the controller renders with empty signup properties and default props. The xs value itself is not posted back. Instead, the stored payload is carried forward as template variables in each wire postback (props=props signup_props=signup_props). This keeps the browser-visible form state limited to the values the template already needs to render, while the original xs token is only used to bootstrap the first page render.

The controller accepts these postbacks:

  • signup_email_step1: validates and prechecks the email address. If the address

    is new and local signup is possible, a short one-time code is mailed using email_signup_code.tpl. If the address is already known, or an external provider handles the domain, the second step shows a logon link and/or external provider buttons instead.
  • signup_email_step2: checks the mailed one-time code. On success, the code is

    deleted and the account details form is rendered.
  • signup_email_step3: verifies the email did not change, checks the terms

    checkbox, merges posted form properties with any prefilled props, combines identities from signup_props with the verified email identity, creates or updates the user through mod_signup:signup_existing/5, logs the user on, and sends a one-time authentication token to the client auth model for redirect.
  • signup_go_step1: returns the browser UI to the first email step.

  • signup_resend_code: replaces the stored one-time code for the email address

    and sends a new email_signup_code.tpl message.

Template structure

The public signup page is signup.tpl. It extends base.tpl, adds the logon CSS in html_head_extra, and fills content_area by including _signup_box.tpl. Other pages can include _signup_box.tpl directly when they need the signup UI without the surrounding page inheritance. The signup box handles already logged-on users and otherwise includes:

  • _signup_with_email.tpl for the three-step email signup flow.

  • all _logon_extra.tpl templates supplied by active authentication modules for

    SSO signup options.

_signup_with_email.tpl includes _signup_with_email_step1.tpl for the first email form and renders empty containers for steps two and three. The controller fills those containers with _signup_with_email_step2.tpl and _signup_with_email_step3.tpl after the corresponding postbacks.

_signup_with_email_step1.tpl renders the email address form and posts signup_email_step1. If an email address was supplied through props, it shows that address with a Change link. The Change postback re-renders _signup_with_email_step1.tpl without the prefilled email so the visitor can enter another address.

_signup_with_email_step2.tpl shows the selected email address, the mailed code form, send status, resend action, existing-account logon link, external-provider options, and error states.

_signup_with_email_step3.tpl renders the final signup form. It defines blocks around the form, field set, individual field groups, and error area so sites can override the shape of the final step. It uses the configuration exposed through m.signup.config.username_equals_email to decide whether the username is hidden and equal to the email address, or entered separately by the user.

Email address confirmation

There are two email checks in the complete signup lifecycle.

The first check happens before account creation. signup_email_step1 sends the short code rendered by email_signup_code.tpl. Codes are stored in the mod_signup gen_server under the tag {signup, EmailNorm}. They are replaced on resend, expire by generational garbage collection, are rate-limit checked through #auth_precheck{}, and are deleted after a successful signup_email_step2. This confirms that the visitor can read the mailbox before the account is created. The verified email is then added to the signup identities as {identity, {email, Email, false, true}} unless an email identity was already supplied in signup_props.

The second check is the account identity confirmation handled by mod_signup and controller_signup_confirm. If signup is requested with confirmation enabled and no non-password identity is already verified, mod_signup creates the user unpublished and unverified, inserts unverified identities, and sends email_verify.tpl through the #identity_verification{} observer. The email contains a signup_confirm URL with the identity verification key.

controller_signup_confirm renders signup_confirm.tpl. That template extends base.tpl and immediately posts the key back to the confirmation controller. The confirmation controller looks up the identity by verification key, publishes the user resource, marks the account and identity as verified, emits #signup_confirm{id=UserId}, logs the user on, and redirects to the first #signup_confirm_redirect{} result or to the user's page.

Edit on GitHub