Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Register Flow

This document explains how the email-based registration pipeline in the auth module is implemented and what a frontend client must do to integrate with it. The flow is deliberately split into two RPCs: one to issue a magic link by email and another to finalize the account creation. The sections below describe the data contracts, validation rules, and expected UX behavior at each step so that UI engineers can wire the screens without re-reading the Rust implementation.

Step 1. Request a registration email

Use the UserAuth.SendRegisterEmail RPC with the prospective user’s email address and optional referral code.

FieldNotes
emailRaw email string entered by the user.
referral_codeOptional referral/invitation code. Will be passed to Step 2 via URL query.

Backend behavior

  • The service first validates the domain against the configurable whitelist/blacklist. Requests to disallowed domains return INVALID_EMAIL immediately:
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct EmailDomainConfig {
    pub enable_white_list: bool,
    pub white_list: Box<[CompactString]>,
    pub enable_black_list: bool,
    pub black_list: Box<[CompactString]>,
}

impl EmailDomainConfig {
    pub fn check_addr(&self, addr: impl AsRef<str>) -> bool {
      // ...
    }
}
  • If the email already maps to an existing login, the call returns EMAIL_EXISTS so the UI can direct the user to the login or password reset flow.
  • When rate limiting is triggered (same address requested again before resend_interval elapses), the server still returns SENT but quietly suppresses a duplicate email. Surface a neutral “email sent” toast to avoid leaking account existence. The default resend_interval is 30 seconds.
  • For a fresh request, the service creates a magic-link record containing a 32-character auth_key, queues an email via RabbitMQ, and responds with SENT:
#[derive(Debug, Clone, PartialEq, Eq, sqlx::FromRow)]
pub struct EmailVerifyLink {
    pub id: i64,
    pub email: String,
    pub auth_key: String,
    pub send_at: PrimitiveDateTime,
    pub reason: EmailVerifyReason,
    pub user_id: Option<Uuid>,
    pub is_unused: bool,
}

const AUTH_KEY_LENGTH: usize = 32;

pub fn generate_auth_key() -> String {
    // ...
}

Frontend expectations

  • Present an email field, an optional referral code field, and an action button. On submission, call SendRegisterEmail and branch on the enum:
    • SENT: Show success UI (“Check your inbox for a magic link”) and inform the user to click the link in their email. The magic link will include the auth_key and the referral_code (if provided) as URL query parameters, automatically directing them to Step 2.
    • INVALID_EMAIL: Highlight the field with a validation error.
    • EMAIL_EXISTS: Offer links to sign in or reset password.
  • Because the backend may skip resending, add a visible countdown using the configured resend_interval (default 30 seconds) before enabling a “Resend” button.
  • The email template contains a clickable magic link that embeds the auth_key in the URL. When clicked, it should route the user directly to the registration completion page (Step 2) with the token and referral code automatically populated from URL query parameters.

When the user clicks the magic link from the email, they are directed to the registration completion page. The URL will contain:

  • auth_key – extracted from the URL query parameter, automatically validates the user’s email
  • referral_code – passed through from Step 1 via URL query parameter (if provided)

The magic link is time-limited. Backend enforcement uses link_expire_after (default 5 minutes). After that, registration attempts fail with INVALID_LINK.

On the frontend, the registration completion page should:

  1. Extract the auth_key from the URL query parameters (this proves the user has access to the email).
  2. Extract the referral_code from the URL query parameters (if present, this was provided in Step 1).
  3. Display a form to collect:
    • A password that satisfies the platform’s policy (policy enforcement happens upstream in the password module).
    • Display the referral code if present (read-only or hidden field).
    • A checkbox “Keep me signed in” that toggles auto-login.

Step 3. Finalize registration

Call UserAuth.RegisterUser with the collected data:

pub struct RegisterUser {
    pub auth_key: String,
    pub password: String,
    pub referral_code: Option<String>,
    pub auto_login: bool,
    pub ip: Option<IpAddr>,
    pub user_agent: Option<String>,
}
FieldRequiredNotes
auth_keyMagic link token from URL query parameter. Each token is single-use and tied to the email.
passwordPlain password; hashing happens server-side.
referral_codeOptional marketing code from URL query parameter (passed through from Step 1), forwarded unchanged.
auto_loginWhen true, the backend issues access & refresh tokens on success.
ipOptional. If the frontend can detect the client’s public IP (e.g., API gateway), pass it for session metadata.
user_agentOptional string captured from the browser; used for session/device history.

Response handling

RegisterUserReply can return four shapes based on the service result:

pub enum RegisterUserResult {
    Registered(Uuid),
    RegisteredWithSession(Uuid, AccessToken, RefreshToken),
    EmailAlreadyExists,
    InvalidLink,
}
  • REGISTERED_WITH_SESSION: Registration succeeded and a new session was created. The reply contains the user_id plus access_token and refresh_token. Store them immediately using the same rules as a login response, then route to the signed-in area.
  • REGISTERED: Registration succeeded but no session was created (because auto_login was false). Route to the login screen and preload the email for convenience.
  • gRPC error ALREADY_EXISTS: The email was registered after the magic link was issued. Show an “already registered” message and link to sign-in.
  • INVALID_LINK: Magic link was unknown, already used, or expired. Inform the user that the link is invalid/expired and offer to send a new registration email.

When auto-login is enabled, the backend records the session with the supplied IP and user agent before returning tokens, so capturing accurate metadata is important for the session list and security analytics.

Retrying after failures

If the magic link expires or has already been used, require the user to restart from Step 1 and request a new registration email. Once a link has been consumed, it cannot be retried.

UI checklist

  • Provide separate screens for Step 1 (email + referral code submission) and Step 2 (password entry after clicking magic link).
  • In Step 1, include both an email field and an optional referral code field.
  • Show a visible countdown for magic link expiration and resend availability (based on config defaults; make them configurable via environment/UI constants).
  • In Step 2, extract both auth_key and referral_code from URL query parameters automatically—no manual token entry is needed.
  • Display the referral code (if present) on the Step 2 page for user confirmation, either as a read-only field or hidden input.
  • Ensure all success paths funnel to analytics hooks alongside the user_id returned from the RPC for downstream tracking.
  • When auto-login is disabled, clearly direct the user to the login screen after successful registration.

This flow mirrors the backend implementation and should keep the frontend in sync with the server-side invariants without re-reading the Rust code every time changes are made.