Edit Page

User Registration & Email Verification

RESTHeart Cloud

Flow Overview

sequenceDiagram
  participant C as Client
  participant R as RESTHeart
  participant M as MongoDB
  participant E as Email

  C->>R: POST /auth/register
  Note over R: validate fields, zxcvbn score ≥ 3
  R->>M: check email uniqueness
  R->>M: create user (roles: $unauthenticated + verify token)
  M-->>R: OK
  R->>E: verification email
  R-->>C: 201 Created

  Note over C,E: user clicks link in email

  C->>R: GET /auth/verify?email=…&token=…
  R->>M: constant-time token compare + TTL check
  R->>M: set roles → user, unset verify token
  M-->>R: OK
  R-->>C: 302 + JWT cookie → frontend app URL

Registration flow

POST /auth/register is the public signup endpoint. It creates a new user and a new tenant in a single atomic operation.

Request

POST /auth/register
Content-Type: application/json

{
  "firstName": "Alice",
  "lastName":  "Rossi",
  "teamName":  "Acme",
  "email":     "alice@acme.com",
  "password":  "correct-horse-battery"
}

Server-side steps

  1. Validate all required fields.

  2. Enforce password strength via zxcvbn (score ≥ minimumPasswordStrength, default 3).

  3. Check email uniqueness — 409 Conflict if already registered.

  4. Generate a cryptographically random verificationToken (256-bit) and verificationCreatedAt timestamp.

  5. Create the user document with roles: ["$unauthenticated"] and the verification token.

  6. Create a membership document linking the user to the tenant as owner.

  7. Send a verification email containing a one-time link:

    {baseAppUrl}/auth/verify?email=alice@acme.com&token=<verificationToken>
  8. Return 201 Created.

Response

{ "message": "Registration successful. Check your email to verify your address." }

Error responses

Status Reason

400

Missing or invalid fields; password too weak

409

Email already registered

Note

Consents management: POST /auth/register does not persist user consents (terms & conditions, privacy policy). If your application requires consent tracking — for example to comply with GDPR or Italian transparency requirements — use a response interceptor on your deployment layer that:

  1. Intercepts successful POST /auth/register responses (status 201).

  2. Reads the consents object from the request body.

  3. Persists it in the user document (e.g. as consents.terms and consents.privacy with version, timestamp, IP, and accepted flag).

The same interceptor pattern applies to PATCH /auth/activate for invited users. See the restheart-cloud deployment for a reference implementation (AccountsConsentsSaver).


Email verification

GET /auth/verify?email=…​&token=…​ is sent as a link in the registration email.

Server-side steps

  1. Extract email and token from the query string.

  2. Find the user by email.

  3. Compare token against verificationToken using constant-time comparison (timing-attack mitigation).

  4. Check that verificationCreatedAt is within the TTL (verificationTokenTtlDays, default 7 days).

  5. Assign the system ACL role from accountsConfig.default-role (default: user) — this replaces the $unauthenticated role assigned at registration. $unset verificationToken and verificationCreatedAt.

  6. Issue a JWT access token + refresh cookie.

  7. Redirect to {frontendAppUrl}.

Expired token

If the token has expired, the endpoint returns 400 with a message inviting the user to request a new verification email from the login page.

Note
Re-sending a verification email is triggered by POST /auth/resend-verify (not yet implemented in v1 — users can contact support or attempt login which will prompt re-verification).