Skip to content
investiDocs

Create an account

Sign up at /setup, how each account is a private workspace, login limits and 30-day sessions.

On this page

Every Investi deployment starts at /setup. The first person to sign up creates the workspace; anyone else who signs up gets their own private account on the same deployment.

First run#

When the database has no users, Investi sends you to /setup automatically. Any app page redirects there, and so does /login. The page title reads "Create your workspace".

The form asks for:

Field Rule
Your name Required.
Email Required. Must look like name@domain.tld. Stored lowercased and trimmed.
Password At least 10 characters.

When the account is created you are signed in immediately and land on /home?welcome=1, where the onboarding panel offers to import history or load the sample portfolio.

The first account is recorded as the original owner in a single-row lock table inside the same database transaction that creates the user. Two people submitting the form at the same moment cannot both become the first account.

Additional accounts#

After the first account exists, /setup reads "Create an account" and links to sign-in. Any number of accounts can be created. Each is its own workspace: portfolio, trade history, research, policies and tokens are all keyed by user, and no account can see another's data.

An email can only be used once. Signing up with an existing email returns "An account with that email already exists. Sign in instead, or use a different email."

Who may sign up#

Sign-up is open: anyone who can reach /setup can create an account. Each account is a separate private workspace, so a new account never sees anyone else's portfolio, history, research or Schwab connection.

To stop scripted mass sign-ups, each network (client IP) can create at most 10 accounts per hour. Past that, /setup shows "Too many sign-ups from this network. Try again in an hour."

Signing in#

/login takes your email and password. On success you are sent to the page you originally asked for, or /home. The next redirect target is restricted to paths on the same origin, so a crafted link cannot bounce you to another site.

A wrong email and a wrong password produce the same message, "That email and password don't match." Unknown emails still run a full password hash so response timing does not reveal which emails exist.

Passwords are hashed with scrypt (N=16384, r=8, p=1, 16-byte random salt). Investi has no password reset flow; if you lose a password, an operator with database access has to replace the hash.

Login rate limits#

Login attempts are counted in one-minute windows:

Limit Allowed per minute
Per account (by email) 8
Per client IP 30

Going over either limit shows "Too many attempts. Wait a minute and try again." The client IP comes from the platform's x-real-ip or x-vercel-forwarded-for header, not the spoofable left-most X-Forwarded-For hop.

Warning: The limiter lives in server memory. On a multi-instance deployment each instance counts separately, and a restart clears the counters. It is aimed at casual guessing on a personal deployment, not a distributed attack. Put the deployment behind a WAF if that matters to you.

Sessions#

  • A successful sign-in or sign-up creates a session that lasts 30 days from creation. It is not extended by activity.
  • The browser holds a random token in the investi_session cookie: HttpOnly, SameSite=Lax, path /, and Secure in production.
  • The server stores only a SHA-256 hash of that token, so a database leak does not expose usable sessions.
  • Signing out deletes the session row and clears the cookie.

API calls made with the session cookie get every scope, but state-changing requests (POST, PUT, PATCH, DELETE) must come from the same origin or they are rejected with 403 csrf. Tokens for scripts and integrations are created separately in Settings; see the REST API.

Next steps#