feat(users): implement OAuth SRP binding flow#452
Conversation
- Fix user enumeration vulnerabilities with generic error responses - Add rate limiting to critical endpoints using @nestjs/throttler - Implement batch getUsersDtoByIds to resolve N+1 query issues - Replace synchronous bcrypt operations with async versions - Add secure login with constant-time authentication
- Replace automatic user creation with user choice mechanism - Add OAuth state token system for secure multi-step authentication - Implement decision page flow allowing users to: * Create new account with customizable username/nickname * Bind OAuth account to existing user account - Add new API endpoints: * GET /users/auth/oauth/state - retrieve OAuth state information * POST /users/oauth/create - create new user from OAuth decision * POST /users/oauth/bind - bind OAuth to existing user - Enhance nickname validation to support Chinese characters - Improve error handling with better user-facing messages - Add comprehensive test coverage for new OAuth scenarios Breaking Changes: - Replace UsersService.loginWithOAuth() with initiateOAuthFlow() - OAuth callback now redirects to different pages based on user state: * /oauth-success - existing OAuth connection * /oauth-verify - email conflict (force binding) * /oauth-complete - new decision page for user choice This improves user experience by eliminating forced automatic registration and allowing users to maintain control over their account creation process.
…troller - Update SRP tests to expect generic InvalidLoginCredentialsError - Add @UseFilters decorator to UsersController - Fix user profile e2e test user ID
- Update SRP tests to use generic error types - Add error filter to users controller - Fix foreign key constraint in user profile queries
Add explicit string type check before calling indexOf() to prevent parameter tampering attacks in verify() and decode() methods
* feat(users): enhance security and performance - Fix user enumeration vulnerabilities with generic error responses - Add rate limiting to critical endpoints using @nestjs/throttler - Implement batch getUsersDtoByIds to resolve N+1 query issues - Replace synchronous bcrypt operations with async versions - Add secure login with constant-time authentication * feat(oauth): implement user-friendly OAuth flow with decision page - Replace automatic user creation with user choice mechanism - Add OAuth state token system for secure multi-step authentication - Implement decision page flow allowing users to: * Create new account with customizable username/nickname * Bind OAuth account to existing user account - Add new API endpoints: * GET /users/auth/oauth/state - retrieve OAuth state information * POST /users/oauth/create - create new user from OAuth decision * POST /users/oauth/bind - bind OAuth to existing user - Enhance nickname validation to support Chinese characters - Improve error handling with better user-facing messages - Add comprehensive test coverage for new OAuth scenarios Breaking Changes: - Replace UsersService.loginWithOAuth() with initiateOAuthFlow() - OAuth callback now redirects to different pages based on user state: * /oauth-success - existing OAuth connection * /oauth-verify - email conflict (force binding) * /oauth-complete - new decision page for user choice This improves user experience by eliminating forced automatic registration and allowing users to maintain control over their account creation process. * fix: resolve SRP auth test failures and add error filter to users controller - Update SRP tests to expect generic InvalidLoginCredentialsError - Add @UseFilters decorator to UsersController - Fix user profile e2e test user ID * fix: resolve test failures and database constraint issues - Update SRP tests to use generic error types - Add error filter to users controller - Fix foreign key constraint in user profile queries * fix(auth): prevent type confusion in token validation Add explicit string type check before calling indexOf() to prevent parameter tampering attacks in verify() and decode() methods * test(users): add unit tests for cookie helper utilities * test(users): enhance unit tests for OAuth user creation and login flows
|
Caution Review failedFailed to post review comments. Configuration used: CodeRabbit UI ⛔ Files ignored due to path filters (2)
📒 Files selected for processing (12)
🧰 Additional context used🧬 Code Graph Analysis (8)src/users/users.error.ts (1)
src/users/users.spec.ts (1)
src/users/helpers/cookie.helper.ts (1)
src/users/DTO/oauth.dto.ts (1)
src/users/helpers/cookie.helper.spec.ts (2)
src/users/users.service.spec.ts (1)
src/users/users.controller.ts (4)
src/users/users.service.ts (4)
🪛 GitHub Actions: Build and Test Dev Dockersrc/users/users.spec.ts[error] 396-396: Test error: Failed to publish cache invalidation message for user ID: 1 to Redis channel 'cache:user:updated'. Reason: Redis connection failed. src/users/users.controller.spec.ts[error] 1291-1291: Test failure: Expected mockUsersService.createOAuthUserFromDecision to be called with 5 arguments but received 8. Mismatch in function call arguments. 🪛 GitHub Actions: Automatic Testsrc/users/users.spec.ts[error] 396-396: Redis connection failed during cache invalidation message publish to channel 'cache:user:updated'. src/users/users.controller.spec.ts[error] 1291-1291: Jest test failure: Expected call arguments mismatch in 'createOAuthUserFromDecision'. Expected 5 arguments but received 8. [error] Multiple OAuth callback and binding errors reported by UsersController including: 'OAuth callback failed: Some OAuth error', 'OAuth binding callback failed: Service error during binding', 'OAuth binding callback failed: Invalid binding state format', 'OAuth verification failed: Verification failed', 'OAuth callback failed: Authorization code is required', 'OAuth callback failed: Failed to get user info', 'OAuth callback failed: OAuth flow error', 'OAuth binding initialization failed: Binding init failed', 'OAuth binding initialization failed: URL generation failed', 'OAuth unbinding failed: Unbind failed'. [error] OAuth callback errors with invalid authorization codes reported: 'OAuth callback failed: Invalid authorization code' repeated twice. [error] OAuth verification failures including 'PasswordNotMatchError' for users 'TestLegacyUser-7865507314' and 'TestLegacyUser-7949979987', and 'OAuth session not found or expired'. [error] OAuth binding to existing user failed due to invalid login credentials and invalid or expired OAuth state tokens, and username already registered error for 'TestLegacyUser-4517685835'. 🪛 GitHub Actions: Automatic Test Coveragesrc/users/users.spec.ts[error] 396-396: Redis connection failed error during test: Failed to publish cache invalidation message for user ID: 1 to Redis channel 'cache:user:updated'. src/users/users.controller.spec.ts[error] 1291-1291: Test failure in UsersController Additional OAuth methods createOAuthUser: Expected call to createOAuthUserFromDecision with 5 arguments but received 8 arguments. 🪛 Biome (1.9.4)src/users/helpers/cookie.helper.spec.ts[error] 434-434: Avoid the delete operator which can impact performance. Unsafe fix: Use an undefined assignment instead. (lint/performance/noDelete) src/users/users.controller.ts[error] 1408-1409: Change to an optional chain. Unsafe fix: Change to an optional chain. (lint/complexity/useOptionalChain) 🔇 Additional comments (44)
WalkthroughThis update introduces a comprehensive refactor and expansion of OAuth and SRP authentication flows. It adds new DTOs, controller endpoints, and service methods for OAuth user creation, binding, and SRP integration. Enhanced error handling, rate limiting, and security improvements such as prevention of user/email enumeration and batch user DTO fetching are included. Extensive new and updated tests cover these flows. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Frontend
participant UsersController
participant UsersService
participant AuthService
participant CookieHelper
User->>Frontend: Initiate OAuth login
Frontend->>UsersController: /auth/oauth/callback?code=...&state=...
UsersController->>UsersService: initiateOAuthFlow(providerId, userInfo, ip, ua)
alt Existing OAuth user
UsersService-->>UsersController: [OAuthUserDto, refreshToken]
UsersController->>CookieHelper: setRefreshTokenCookie(res, refreshToken, expires)
UsersController->>Frontend: Redirect to success page
else Requires verification (password/SRP)
UsersService-->>UsersController: {requiresVerification, ...}
UsersController->>Frontend: Redirect to verification page
else Requires user decision
UsersService-->>UsersController: {requiresDecision, stateToken}
UsersController->>Frontend: Redirect to decision page with stateToken
end
User->>Frontend: Submit decision (create/bind)
Frontend->>UsersController: /oauth/create or /oauth/bind with stateToken, credentials
UsersController->>UsersService: createOAuthUserFromDecision(...) or bindOAuthToExistingUser(...)
UsersService-->>UsersController: [OAuthUserDto, refreshToken]
UsersController->>CookieHelper: setRefreshTokenCookie(res, refreshToken, expires)
UsersController->>Frontend: Redirect to success page
Possibly related PRs
Suggested reviewers
Poem
✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
No description provided.