SPEC 001 Authentication Account - rafaelfqueiroz/allmywallet GitHub Wiki
SPEC-001 — Authentication & Account
| Status | Draft |
| PRD source | F1 (FR-1.1–1.6), FR-8.23 |
| Depends on | SPEC-003 (tenant model), SPEC-002 (config) |
| Required by | Every other spec, SPEC-020 |
| Milestone | M0 |
Description
Sign-in, session handling and account lifecycle for AllMyWallet. Google OAuth 2.0 is the only sign-in method: no password is ever created, transmitted or stored by this system.
That is a security decision before it is a convenience one — it removes credential storage, password reset flows, and credential-stuffing exposure from the product entirely. It is also the sole identity boundary behind which every tenant-scoped record in the system sits, so this spec is a prerequisite for all others.
First successful sign-in provisions the user's tenant and hands off to the onboarding flow in SPEC-020.
Business rules
| ID | Rule |
|---|---|
| BR-001-01 | Google OAuth 2.0 is the only authentication method. No password field exists anywhere in the product. |
| BR-001-02 | Only the openid, email and profile scopes are requested. No Google Drive, Calendar, Contacts or any other scope may be added without a documented privacy review. |
| BR-001-03 | The stable Google subject ID (sub), not the email address, is the identity key. Users can change their Google email; the account must survive it. |
| BR-001-04 | First successful sign-in creates exactly one User record and its tenant context, then routes to onboarding. Provisioning is idempotent — a retried callback must not create a second tenant. |
| BR-001-05 | Personal data stored is limited to: Google subject ID, email, display name, profile picture URL. Nothing else. |
| BR-001-06 | Sessions expire after a configurable period of inactivity (default 30 days). |
| BR-001-07 | Sign-out invalidates the session server-side. Clearing a cookie client-side is not sufficient. |
| BR-001-08 | Every request resolves its tenant from the authenticated session only. A user, org or tenant identifier accepted from a request parameter, header or body is a security defect. |
| BR-001-09 | A user can permanently delete their account from settings; the deletion itself is specified in SPEC-004. |
| BR-001-10 | OAuth state and PKCE parameters are validated on callback; a mismatched or replayed state is rejected. |
| BR-001-11 | Authentication endpoints are rate-limited per IP and per subject. |
| BR-001-12 | Account recovery when the Google account is lost is not offered. This is an accepted consequence of single-provider auth and must be stated in the sign-up screen, not buried in terms. |
Acceptance Criteria
- A new user signs in with Google and reaches an empty dashboard with no form fields to complete.
- Sign-up to signed-in state completes in under 30 seconds on a normal connection.
- Signing in a second time reuses the same tenant; no duplicate
Userrow is created. - Changing the email address on the Google account still resolves to the same AllMyWallet account.
- A replayed or tampered OAuth
stateparameter is rejected with no session created. - Signing out invalidates the session server-side: replaying the captured session cookie afterwards is refused.
- A session idle beyond the configured window is refused, and the window is changeable via config without a deploy.
- No password field, "forgot password" link, or credential input exists anywhere in the product.
- A request carrying a
user_idparameter for a different tenant is ignored — identity comes from the session (verified jointly with SPEC-003). - The sign-up screen states plainly that losing the Google account means losing access.
- Repeated failed auth attempts are rate-limited.
- Only
openid,email,profilescopes appear in the consent screen.
Out of Scope
- Email/password authentication, magic links, or any second identity provider.
- Multi-factor authentication beyond what Google itself enforces.
- Account recovery, account merging, or transferring data between accounts.
- Organizations, teams, shared portfolios, or any multi-user-per-tenant concept.
- Role-based access control — every user has exactly one role over exactly their own data.
- Impersonation or support-side login-as.
- The account deletion mechanics themselves (SPEC-004).
- Storing or handling any B3, broker or bank credential — prohibited product-wide (SPEC-003).
Decision Logs
| # | Decision | Alternatives considered | Rationale |
|---|---|---|---|
| DL-001-01 | Google OAuth is the only sign-in method. | Email+password; magic link; multiple OAuth providers | Removes credential storage and the entire password-breach class of risk. The target user already has a Google account. A second provider can be added later without redesign; adding passwords could not be undone as cheaply. |
| DL-001-02 | Identity keyed on Google sub, not email. |
Key on email address | Emails change and can be reassigned within Workspace domains. Keying on a mutable field would silently orphan or, worse, merge accounts. |
| DL-001-03 | No account recovery. | Support-mediated recovery via email proof | Any recovery path is an authentication bypass by definition, and building one securely for a product holding financial data is disproportionate at v1. Accepted and disclosed rather than half-built. Revisit if a second provider is added. |
| DL-001-04 | Session expiry is configurable, defaulting to 30 days. | Fixed 30 days; short expiry with refresh tokens | Long-horizon tracker checked weekly or monthly — a short session is pure friction for no threat-model gain. Configurable per SPEC-002 so it can tighten without a release. |
| DL-001-05 | Minimum OAuth scopes, enforced by rule not convention. | Request broader scopes for future features | Scope creep in OAuth is invisible to users until the consent screen, and expanding scopes later forces re-consent anyway. Nothing is requested until a feature needs it. |