Skip to content

feat(auth): add pluggable auth state store#22

Open
Kawshikk-Shrii wants to merge 1 commit into
thunderavi:mainfrom
Kawshikk-Shrii:feat/auth-state-store
Open

feat(auth): add pluggable auth state store#22
Kawshikk-Shrii wants to merge 1 commit into
thunderavi:mainfrom
Kawshikk-Shrii:feat/auth-state-store

Conversation

@Kawshikk-Shrii
Copy link
Copy Markdown

Summary

This PR introduces a production-ready, pluggable auth state store for handling refresh tokens, password reset tokens, email verification tokens, enterprise sessions, MFA data, OAuth state, and login attempt tracking.

Previously, auth-related state was stored directly in in-memory maps inside core/auth.js and core/enterpriseAuth.js. That approach works for local development but is not reliable in production because state is lost on server restart and cannot be shared across multiple running instances.

This change moves auth state management behind a store interface while keeping an in-memory adapter for development and test environments.

Closes #15


Changes Made

  • Added a new core/authStore/ module.
  • Added MemoryAuthStore for development and test usage.
  • Added DatabaseAuthStore for persistent production usage.
  • Added an auth store factory for selecting the correct store adapter.
  • Added a new migration for auth store tables.
  • Migrated refresh token storage from process memory to the auth store.
  • Migrated password reset token and email verification token storage to the auth store.
  • Migrated enterprise sessions, MFA secrets, OAuth state, and login attempt tracking to the auth store.
  • Added support for expiry, revocation, cleanup, and audit-friendly timestamps.
  • Added SHA-256 hashing for sensitive token storage in the database adapter.
  • Added optional encryption/decryption hooks for MFA secrets.
  • Added unit tests for both memory and database-backed auth store behavior.
  • Added multi-instance tests to verify shared persistent auth state.
  • Updated existing auth and enterprise auth tests for the async store flow.
  • Updated connection pool timer behavior with unref() to avoid Jest open-handle warnings.

Testing

The following checks were run successfully:

npm run verify
npm test

Test result:

Test Suites: 1 skipped, 44 passed, 44 of 45 total
Tests:       9 skipped, 278 passed, 287 total
Snapshots:   0 total

Notes

  • The in-memory auth store remains the default when no database connection is provided.
  • The database-backed auth store is selected when a Knex instance is passed.
  • Static OAuth provider configuration remains in memory because it is configuration data, not transient auth state.
  • Raw sensitive tokens are not stored in the database; token lookups use SHA-256 hashes.
  • MFA secret encryption is supported through optional encryption/decryption hooks.
  • No secrets, generated logs, local build output, or temporary files are included.
  • This PR keeps the scope focused on issue Add a production-ready auth state store for refresh tokens, sessions, and MFA data #15.

@Kawshikk-Shrii
Copy link
Copy Markdown
Author

Hi, I have raised this PR for issue #15.

I’ve added a pluggable auth state store with memory and database-backed adapters, migrated the existing in-memory auth state usage, and added tests for expiry, revocation, cleanup, and multi-instance behavior.

Checks passed locally with:

npm run verify
npm test

Test result:

Test Suites: 1 skipped, 44 passed, 44 of 45 total
Tests: 9 skipped, 278 passed, 287 total

Please review it when you get a chance. Thank you!

@thunderavi
Copy link
Copy Markdown
Owner

Hi @Kawshikk-Shrii, thanks for the PR. The overall approach is good and focused for issue #15.

I checked the implementation and also ran the tests locally:

npm run verify
npm test -- --runInBand
npm run typecheck

All of these passed.

However, I found one important integration issue before this can be approved/merged.

AuthManager and EnterpriseAuth currently do not pass the constructor options into createAuthStore(), so even when a knex instance is provided, they still use MemoryAuthStore instead of DatabaseAuthStore.

Current code:

// core/auth.js
this.store = options.store || createAuthStore();

// core/enterpriseAuth.js
this.store = config.store || createAuthStore();

Because of that, this code still selects the memory store:

new AuthManager({ knex })
new EnterpriseAuth({ knex })

Expected behavior: passing { knex } should select DatabaseAuthStore.

Please update this to pass the options/config into the factory, for example:

// core/auth.js
this.store = options.store || createAuthStore(options);

// core/enterpriseAuth.js
this.store = config.store || createAuthStore(config);

Also please add/adjust tests to prove that:

  • new AuthManager({ knex }) uses DatabaseAuthStore
  • new EnterpriseAuth({ knex }) uses DatabaseAuthStore
  • the default without knex still uses MemoryAuthStore

After this fix, I can review again. If everything still passes, we can approve, add the GSSoC labels, and merge.

@thunderavi thunderavi moved this from Backlog to Ready in @thunderavi's Easy.Js May 23, 2026
@thunderavi thunderavi added level:advanced Advanced-level contribution mentor:thunderavi Reviewed by thunderavi type:feature Feature implementation labels May 23, 2026
@thunderavi
Copy link
Copy Markdown
Owner

Hi @Kawshikk-Shrii, please confirm whether you are still interested in continuing work on this PR/issue.

The remaining requested fix is the { knex } store-selection issue mentioned in the review comment. If you want to continue, please push the update to this same PR branch.

If you are not interested or not available to continue, please let me know so I can assign the issue to another contributor.

@Kawshikk-Shrii
Copy link
Copy Markdown
Author

Yeah. I am interested and want to contribute and continue to work in this PR.

@thunderavi
Copy link
Copy Markdown
Owner

Hi @Kawshikk-Shrii, your PR now has merge conflicts in:

  • core/auth.js
  • core/enterpriseAuth.js

This happened because another security PR was merged into main and it changed the same auth files.

Please sync your branch with the latest main and resolve the conflicts. While resolving, make sure you keep both changes:

  1. Keep the new JWT secret validation from main.
  2. Keep your auth store implementation.
  3. Apply the requested fix:
    • AuthManager should use createAuthStore(options)
    • EnterpriseAuth should use createAuthStore(config)

After resolving conflicts, push to the same PR branch. Once CI passes, I will re-review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

level:advanced Advanced-level contribution mentor:thunderavi Reviewed by thunderavi type:feature Feature implementation

Projects

Status: Ready

Development

Successfully merging this pull request may close these issues.

Add a production-ready auth state store for refresh tokens, sessions, and MFA data

2 participants