Multica Docs

Sign-in and signup

Configure email verification codes, Google sign-in, and who can sign up.

Multica signs users in with email verification codes by default; Google OAuth can be added on top. Existing users can always sign in again — signup restrictions only decide whether new accounts can be created.

Email verification codes

After the user enters an email address, Multica sends a 6-digit verification code. The code is valid for 10 minutes; once it verifies, the browser receives a sign-in cookie.

Email can be delivered through Resend or SMTP. When both are configured, SMTP_HOST takes priority.

Using Resend

  1. Verify a sending domain and create an API key at Resend.

  2. Set:

    RESEND_API_KEY=re_xxxxxxxxxxxxxxxx
    RESEND_FROM_EMAIL=[email protected]
  3. Restart the API service.

RESEND_FROM_EMAIL must belong to a domain already verified in Resend.

Using SMTP

At minimum, set the host and sender address:

SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USERNAME=multica
SMTP_PASSWORD=<password>
SMTP_FROM_EMAIL=[email protected]

Common connection modes:

ScenarioConfiguration
Internal anonymous relaySMTP_PORT=25, leave username and password empty
STARTTLSSMTP_PORT=587; upgrades to TLS by default when the server supports it
Implicit TLSSMTP_PORT=465, or set SMTP_TLS=implicit explicitly

If SMTP_FROM_EMAIL is unset, it falls back to RESEND_FROM_EMAIL. Private CAs or self-signed certificates require adding the CA to the container trust store; SMTP_TLS_INSECURE=true skips certificate verification and should only be used temporarily on a trusted internal network.

Some strict relays also require a valid EHLO name:

SMTP_EHLO_NAME=mail.example.com

Behavior without an email service

The server still starts, but verification codes and invitation links are only written to the log; no email is sent. This suits local development, not production.

The startup log states whether the current mode is Resend API, SMTP relay, or DEV mode.

Fixed local verification code

Local automated tests can set a fixed verification code:

APP_ENV=development
MULTICA_DEV_VERIFICATION_CODE=888888

The code must be 6 digits. The fixed code is ignored when APP_ENV=production.

Do not enable a fixed code on a publicly reachable instance. The production combination is APP_ENV=production with an empty MULTICA_DEV_VERIFICATION_CODE.

Google sign-in

  1. Create an OAuth 2.0 client in the Google Cloud Console.

  2. Add the Multica frontend's callback URL to Authorized redirect URIs:

    https://multica.example.com/auth/callback
  3. Set:

    GOOGLE_CLIENT_ID=xxxxx.apps.googleusercontent.com
    GOOGLE_CLIENT_SECRET=GOCSPX-xxxxxxxxxxxxxxx
    GOOGLE_REDIRECT_URI=https://multica.example.com/auth/callback
  4. Restart the API service.

The URLs in the Google Console and in GOOGLE_REDIRECT_URI must match exactly, including protocol, port, and trailing slash. Once configured, the sign-in page shows a Google sign-in button; the frontend image needs no rebuild.

Signup restrictions

Three variables together decide whether a new account can be created:

VariableEffect
ALLOWED_EMAILSFull email addresses allowed to sign up, comma-separated
ALLOWED_EMAIL_DOMAINSEmail domains allowed to sign up, comma-separated
ALLOW_SIGNUPWhether signup is allowed when no allowlist is configured; defaults to true

The evaluation order is:

  1. The email matches ALLOWED_EMAILS — allow.
  2. Or its domain matches ALLOWED_EMAIL_DOMAINS — allow.
  3. With no allowlist configured and ALLOW_SIGNUP=true — allow.
  4. Otherwise, if the email has a pending, unexpired workspace invitation — allow.
  5. Otherwise — reject.

Common configurations:

# Company domain and invited users
ALLOW_SIGNUP=false
ALLOWED_EMAIL_DOMAINS=company.com

# Also admit one external collaborator
ALLOWED_EMAILS=[email protected]

Both allowlists also work as an explicit exception list when ALLOW_SIGNUP=false.

Invitations and signup restrictions

A pending, unexpired workspace invitation allows its email address to create an account even when ALLOW_SIGNUP=false or the address does not match ALLOWED_EMAILS or ALLOWED_EMAIL_DOMAINS. This exception also applies when ALLOW_SIGNUP=true with an allowlist configured: allowlists are not a hard boundary against invited users.

Existing users can continue to sign in. New users without a matching allowlist entry or open signup need a pending, unexpired invitation; missing, expired, accepted, declined, and revoked invitations do not grant signup permission. The invitation is checked when requesting a login code and again when creating the account, including Google sign-in.

You do not need to add ordinary invitees to ALLOWED_EMAILS or restart the server. The invitation must still be accepted through the normal invitation flow to join the workspace.

Revoking an invitation does not delete an account already created using it or prevent that existing account from signing in.

Session lifetime

Sessions slide. The lifetime below is an idle bound, not a countdown from sign-in: once a session drops below half of it, the next request re-issues it with a full lifetime again, so an account in continuous use is never signed out on a schedule. There is no absolute cap.

The bound is one-sided. A session is only re-issued once it is past the halfway point, so a session last used while it still had more than half its lifetime left is not extended — the idle gap that is always survivable is half the value below, not all of it.

Adjust with AUTH_TOKEN_TTL, which accepts a Go duration or a positive integer of seconds:

AUTH_TOKEN_TTL=720h

The minimum is 60s; anything shorter is clamped up to it and logs a warning at startup. Below that, the renewal cadence the server derives would fall under the floor clients apply to it, and clients would check for renewal less often than the session can survive.

Restart the API service after changing it. The value applies to sessions issued or re-issued afterwards — because sessions slide, an existing session picks up the new lifetime the next time it is re-issued.

Next steps