WorkNidhara – Security-First Auth Foundation for a Personal Finance & Growth Platform~5 min read
Security-First Auth & FinTech FoundationActive ProductionProprietarySolo owner & full-stack engineer

Nidhara – Security-First Auth Foundation for a Personal Finance & Growth Platform

NestJS, Prisma, and Next.js monorepo with Argon2 authentication, rotating refresh-token sessions, and audit logging.

Role:Solo Full-Stack Engineer
Timeline:Dec 2025 — Feb 2026
NestJS 11Prisma 7PostgreSQL 15Next.js 16TypeScript

Designed and built the monorepo, authentication engine, session lifecycle, Prisma data model, and documentation site alone.

My contribution

Solo owner & full-stack engineer

Designed and built the monorepo, authentication engine, session lifecycle, Prisma data model, and documentation site alone.

What I owned

  • npm workspaces monorepo: NestJS backend, Next.js frontend, Docusaurus docs
  • Signup, signin, refresh, and logout flows with Argon2 and dual-token issuance
  • Database-backed sessions with CSRF verification and revocation on replay or logout
  • Security event, account security state, and sudo session data models
  • Swagger documentation, response envelope interceptor, and structured Pino logging

Product context

Individuals managing personal finances and life records

Get authentication right before the ledger arrives.

Delivered the security foundation of a personal wealth and growth platform: Argon2 credentials, rotating refresh-token sessions with CSRF checks, audit events, and a documented monorepo ready for the finance ledger to be added.

Core challenge

Evidence: assumption

Personal finance and journaling tools are fragmented, and many leave users with weak credential storage and fragile session handling. A financial platform needs an auditable authentication foundation, with strict session invalidation, CSRF defenses, and event logging, in place before any ledgers are connected.

Who hurts:
account-holder

User benefit matrix

Strategyzer Canvas

The Value Proposition Canvas

Value PropositionNidhara
Customer SegmentIndividuals managing personal finances and life records
Expand value canvas
Products & Services
Gain Creators
Pain Relievers
Gains
Pains
Customer Jobs

Sector

Title

Body

Account Holder

Stolen or replayed session tokens could expose personal financial data

designed
Before

Long-lived refresh tokens in cookies with no replay detection

After

Single-use refresh tokens bound to a session record, rotated on every refresh and paired with a CSRF token

Metric: Refresh token reuse
Reusable until expiry→Single-use, revoked on replay
AuthAuthSession
personal
Platform Owner

No audit trail of sign-in activity

measured
Before

Unstructured console logs and no record of login outcomes

After

Security events (login success, login failure, logout, refresh rotation) stored with user-agent and IP metadata, plus structured JSON request logs

Metric: Tracked security event types
0→4
SecurityEventPino Logging
personal

Proof

Impact and product screens

My results

4Tracked security event typesSecurity events (login success, login failure, logout, refresh rotation) stored with user-agent and IP metadata, plus structured JSON request logs

Build

Stack and engineering choices

Technology

Frontend
  • Next.js 16 (App Router)
  • React 19
  • TailwindCSS 4
  • TypeScript
  • Docusaurus 3 (docs site)
Backend
  • NestJS 11
  • Argon2
  • Passport JWT
  • cookie-parser
  • nestjs-pino / pino-http
  • Swagger (OpenAPI)
Database
  • PostgreSQL 15
  • Prisma ORM 7 (6 models, 2 migrations)
DevOps & Infra
  • Docker Compose
  • npm workspaces
  • ESLint & Prettier
  • Jest

Key decisions

Personal finance and journaling tools are fragmented, and many leave users with weak credential storage and fragile session handling. A financial platform needs an auditable authentication foundation, with strict session invalidation, CSRF defenses, and event logging, in place before any ledgers are connected.

Protect credentials and session secrets against GPU-accelerated brute-force attacks.

Decision: Used Argon2 for credential verification and refresh token hashes instead of bcrypt. Trade-off: higher memory use per authentication request.

Outcome: Stronger resistance to hardware-assisted brute force on stored secrets.

Long-lived refresh tokens in cookies risk theft and cross-site request forgery.

Decision: Bound each refresh token to a session record, rotated the refresh hash on every /auth/refresh call, and required a matching client csrfToken. Trade-off: extra database writes on refresh.

Outcome: Refresh token reuse is rejected and background refresh from another site is blocked.

Sensitive account changes need re-authentication without interrupting the ongoing session.

Decision: Modeled a standalone SudoSession with a time-bounded sudoUntil and a verified escalation method (PASSWORD, RECOVERY_KEY, MFA). Trade-off: sensitive endpoints will need a second authorization check.

Outcome: A data model for step-up authentication is in place for when sensitive endpoints are built.

Plain console logs are hard to search and weak as an audit trail.

Decision: Integrated nestjs-pino with pino-http and a global ResponseInterceptor to emit structured JSON logs and a uniform response envelope. Trade-off: some extra bootstrap configuration.

Outcome: Searchable request and response logs for auditing and debugging.

Trust

Security and roadmap

Security & reliability

  • Argon2 hashing for passwords and refresh token hashes
  • Dual-token flow: short-lived access token plus httpOnly refresh cookie
  • Single-use refresh rotation with CSRF token verification; session revoked on replay or logout
  • Security events (LOGIN_SUCCESS, LOGIN_FAILED, LOGOUT, REFRESH_ROTATED) stored with IP and user-agent
  • Failed-login tracking and sudo session state modeled in the database

Future roadmap

  • Passkey (WebAuthn) and security question authentication
  • Financial accounts, immutable transaction ledgers, and savings goals
  • Personal development suite (LifeLog, Capsule, Knowledge base, Micro Actions)
Progressive Disclosure

Architectural Deep-Dive, Schemas & Workflows

Jump:

Technical Appendix

Nidhara is an npm workspaces monorepo with three workspaces: a NestJS 11 backend using Prisma and PostgreSQL, a Next.js 16 frontend, and a Docusaurus documentation site. This case study covers the authentication and session foundation, which is the part built so far. The finance ledger and personal growth features are planned, not shipped.


Architecture

flowchart TD
    subgraph Mono ["Monorepo (npm workspaces)"]
        FE["frontend (Next.js 16)"]
        DOCS["docs-site (Docusaurus)"]
        BE["backend (NestJS 11)"]
    end

    subgraph Pipeline ["Backend Pipeline"]
        INT["ResponseInterceptor + Pino Logger"]
        AUTHC["AuthController"]
        APPC["AppController"]
        GUARD["JWT Strategy & Guards"]
        INT --> AUTHC
        INT --> APPC
        AUTHC --> GUARD
    end

    subgraph Services ["Application Services"]
        AUTHS["AuthService (Argon2, token rotation)"]
        TOK["AuthTokensService (JWT sign/verify)"]
        USERS["UsersService"]
        AUTHC --> AUTHS
        AUTHS --> TOK
        AUTHS --> USERS
    end

    subgraph Data ["PostgreSQL (Prisma)"]
        MODELS[("6 Models")]
        AUTHS --> MODELS
        USERS --> MODELS
    end

    BE --> Pipeline

Request flow: Client Request → ResponseInterceptor & Pino → Controller (dto/) → Service → PrismaService → PostgreSQL.


Data Model

ModelPurpose
UserCore account record
AuthCredentialStored credential data, hashed with Argon2
AuthSessionOne record per session, holding the rotating refresh hash and CSRF verification state
SecurityEventImmutable log of LOGIN_SUCCESS, LOGIN_FAILED, LOGOUT, and REFRESH_ROTATED with IP and user-agent
UserAccountSecurityStateTracks failed logins and account security status
SudoSessionTime-bounded privilege escalation with a verified method (PASSWORD, RECOVERY_KEY, MFA)

Refresh Rotation Flow

  1. On signin, the server issues a short-lived access token and an httpOnly refresh cookie, and stores a hash of the refresh token on a new AuthSession.
  2. The client calls /auth/refresh with the cookie and its csrfToken.
  3. The server verifies the refresh hash and the CSRF token against the session record.
  4. On success, it issues a new access token and a new refresh token, and replaces the stored hash, so the old token cannot be used again.
  5. A replayed token or a logout revokes the session, and a security event is recorded.

Scope & Status

The project is at prototype stage. The backend exposes 5 endpoints across 2 controllers and has one smoke-level test (app.controller.spec.ts). Passkey and security-question authentication, the sudo escalation endpoints, and all finance features are on the roadmap. The SudoSession and UserAccountSecurityState tables exist in the schema, but the flows that use them are not built yet.


By the Numbers

MetricCount
Git commits (solo)18
Monorepo workspaces3
REST endpoints5 across 2 controllers
Backend services4 (AuthService, AuthTokensService, UsersService, PrismaService)
Prisma models6
Prisma migrations2
Backend spec files1 (1 test case)
Documentation pages30

Case closed

More work.