Skip to content

feat: Add login with additional auth data #1858

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

SteffenKeller
Copy link

@SteffenKeller SteffenKeller commented Aug 12, 2025

New Pull Request Checklist

Issue Description

Closes: #1839

Approach

A logInWithUsernameInBackground function is added that takes additional authData.

In order to prevent sending the authData.mfa object on every subsequent PFUser update, the authData.mfa key is removed from the response payload on login so it is not kept in memory for future saves. This is needed because otherwise Parse Server would be calling validateUpdate inside the Auth Adapter which fails without a valid TOTP.

The login function can be called like this:

PFUser.logInWithUsername(inBackground: username, password: password, authData: ["mfa": ["token": authCode]])

TODOs before merging

  • Add tests
  • Add changes to documentation (guides, repository pages, in-code descriptions)

Summary by CodeRabbit

  • New Features
    • Added login with username/password plus optional extra authentication data (e.g., MFA) via new public APIs; supports body (POST) parameters and revocable sessions.
  • Bug Fixes
    • Prevents transient MFA data from being persisted in user authentication data.
  • Documentation
    • Updated login docs to describe passing additional authentication data.
  • Tests
    • Added tests for parameters-based/MFA login flow; removed obsolete null-result login test.

Copy link

🚀 Thanks for opening this pull request! We appreciate your effort in improving the project. Please let us know once your pull request is ready for review.

Copy link

coderabbitai bot commented Aug 12, 2025

📝 Walkthrough

Walkthrough

Adds a POST-based /login flow that accepts additional parameters (e.g., authData) by introducing a new PFRESTUserCommand factory, extending PFUserController and PFUser APIs to pass authData parameters, sanitizing transient MFA authData from persisted user state, and adding unit tests for the new flow.

Changes

Cohort / File(s) Summary
REST Login Command (POST body)
Parse/Parse/Internal/Commands/PFRESTUserCommand.h, Parse/Parse/Internal/Commands/PFRESTUserCommand.m
Adds +logInUserCommandWithParameters:revocableSession:error: to build a POST /login with body parameters and revocable-session header; retains existing GET-based login variant.
User Controller API and Flow
Parse/Parse/Internal/User/Controller/PFUserController.h, Parse/Parse/Internal/User/Controller/PFUserController.m
Updates controller API to accept optional parameters (parameters) for username/password login; implements POST login via the new command; sanitizes server response to remove transient authData.mfa before constructing/saving PFUser.
Public PFUser API
Parse/Parse/Source/PFUser.h, Parse/Parse/Source/PFUser.m
Adds public login APIs that accept authData (async BFTask and block variants) which forward parameters to controller; ensures transient MFA authData is not persisted during merges.
Unit Tests
Parse/Tests/Unit/UserCommandTests.m, Parse/Tests/Unit/UserControllerTests.m
Adds tests covering POST /login with parameters and controller flow (including revocable session header and MFA authData expectations); removes prior null-result login test.

Sequence Diagram(s)

sequenceDiagram
  participant App
  participant PFUser
  participant PFUserController
  participant PFRESTUserCommand
  participant ParseServer

  App->>PFUser: logInWithUsernameInBackground(username,password,authData)
  PFUser->>PFUserController: logInCurrentUserAsyncWithUsername:password:parameters:revocableSession:
  PFUserController->>PFRESTUserCommand: logInUserCommandWithParameters:revocableSession:error:
  PFRESTUserCommand->>ParseServer: POST /login { username, password, authData }
  ParseServer-->>PFRESTUserCommand: Response (user dictionary, session)
  PFRESTUserCommand-->>PFUserController: Response dictionary
  PFUserController->>PFUserController: Sanitize authData (remove mfa)
  PFUserController->>PFUser: Construct PFUser from sanitized data
  PFUserController-->>App: Return BFTask resolving with PFUser
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Assessment against linked issues

Objective Addressed Explanation
Add API to login with additional authData (Issue #1839)
Ensure transient authData (e.g., mfa) is not persisted on PFUser (Issue #1839)
Implement POST /login using body parameters for username/password plus authData (Issue #1839)
Provide unit tests covering authData login path (Issue #1839)

Assessment against linked issues: Out-of-scope changes

Code Change Explanation
Removal of null-result login test (Parse/Tests/Unit/UserControllerTests.m) The linked issue requested authData login support; deleting the existing null-result test is unrelated to adding authData support and changes test coverage for invalid-login handling.

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the "Integrations" page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 60b22dd and 2d2b59f.

📒 Files selected for processing (1)
  • Parse/Tests/Unit/UserControllerTests.m (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • Parse/Tests/Unit/UserControllerTests.m

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.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@parseplatformorg
Copy link
Contributor

parseplatformorg commented Aug 12, 2025

🎉 Snyk checks have passed. No issues have been found so far.

security/snyk check is complete. No issues have been found. (View Details)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (6)
Parse/Parse/Source/PFUser.h (2)

170-177: Docstring should include params and server-version note

Please align the doc with neighboring APIs by documenting parameters and noting the minimum Parse Server version for MFA.

 /**
  Logs in a user with username and password and additional authentication data (e.g., MFA).

  The authData keys must follow the Parse Server spec, for example:
      @{ @"mfa": @{ @"token": authCode } }

- This data is only sent as part of the login request and is not persisted on the PFUser instance.
+ This data is only sent as part of the login request and is not persisted on the PFUser instance.
+ 
+ @param username The username of the user.
+ @param password The password of the user.
+ @param authData Optional additional auth data to be sent only during login (e.g., MFA).
+ 
+ @discussion Requires Parse Server 6.0+ for MFA/authData during login. Transient keys such as "mfa"
+ received from the server response are sanitized and not persisted on the PFUser instance.
  */

182-186: Expand the block variant doc for consistency

Match the style of other block-based APIs by documenting parameters and behavior.

-/** Block variant of login with additional authData. */
+/**
+ Block variant of login with additional authData.
+ 
+ @param username The username of the user.
+ @param password The password of the user.
+ @param authData Optional additional auth data to be sent only during login (e.g., MFA).
+ @param block The block to execute. It has the signature: ^(PFUser *user, NSError *error).
+ */
Parse/Tests/Unit/UserCommandTests.m (1)

44-61: Strengthen header assertion

Assert the exact header content, not just the count, to avoid silent regressions in header names/values.

-    XCTAssertEqual(command.additionalRequestHeaders.count, 1);
+    XCTAssertEqualObjects(command.additionalRequestHeaders, (@{ @"X-Parse-Revocable-Session" : @"1" }));
Parse/Parse/Internal/Commands/PFRESTUserCommand.h (1)

26-34: Clarify parameter type and add server-version note

  • Use generics for parameters to improve readability and type hints.
  • Document that POST /login with additional auth requires Parse Server 6+.
 /**
  Creates a login command with a JSON body, allowing additional parameters such as authData.

  This posts to the login route and is required for features like MFA where additional
  authentication data must be supplied alongside username/password.
+ Requires Parse Server 6.0+ for MFA/authData during login.
  */
-+ (instancetype)logInUserCommandWithParameters:(NSDictionary *)parameters
++ (instancetype)logInUserCommandWithParameters:(NSDictionary<NSString *, id> *)parameters
                               revocableSession:(BOOL)revocableSessionEnabled
                                          error:(NSError **)error;
Parse/Parse/Source/PFUser.m (1)

369-374: Consider extracting MFA sanitization logic into a reusable method

The MFA sanitization logic appears in multiple locations (lines 369-374, 655-660). This duplication could lead to maintenance issues if the sanitization requirements change.

Consider extracting this into a private helper method:

+- (NSDictionary *)_sanitizeAuthDataRemovingMFA:(NSDictionary *)authData {
+    if ([authData isKindOfClass:[NSDictionary class]] && authData[@"mfa"]) {
+        NSMutableDictionary *mutable = [authData mutableCopy];
+        [mutable removeObjectForKey:@"mfa"];
+        return [mutable copy];
+    }
+    return authData;
+}

Then use it in both locations:

-    // Remove transient MFA auth provider from persisted state
-    if ([newAuthData isKindOfClass:[NSDictionary class]] && newAuthData[@"mfa"]) {
-        NSMutableDictionary *mutable = [newAuthData mutableCopy];
-        [mutable removeObjectForKey:@"mfa"];
-        newAuthData = [mutable copy];
-    }
+    // Remove transient MFA auth provider from persisted state
+    newAuthData = [self _sanitizeAuthDataRemovingMFA:newAuthData];
Parse/Parse/Internal/User/Controller/PFUserController.m (1)

136-137: Consider validating required parameters

While the code handles nil username/password by providing empty strings, this might lead to less informative error messages from the server.

Consider validating required parameters before making the request:

-        NSMutableDictionary *merged = [@{ @"username": username ?: @"",
-                                          @"password": password ?: @"" } mutableCopy];
+        if (!username || !password) {
+            return [BFTask taskWithError:[PFErrorUtilities errorWithCode:kPFErrorUsernameMissing
+                                                                 message:@"Username and password are required."]];
+        }
+        NSMutableDictionary *merged = [@{ @"username": username,
+                                          @"password": password } mutableCopy];
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6c3aff0 and 60b22dd.

📒 Files selected for processing (8)
  • Parse/Parse/Internal/Commands/PFRESTUserCommand.h (1 hunks)
  • Parse/Parse/Internal/Commands/PFRESTUserCommand.m (1 hunks)
  • Parse/Parse/Internal/User/Controller/PFUserController.h (1 hunks)
  • Parse/Parse/Internal/User/Controller/PFUserController.m (2 hunks)
  • Parse/Parse/Source/PFUser.h (1 hunks)
  • Parse/Parse/Source/PFUser.m (3 hunks)
  • Parse/Tests/Unit/UserCommandTests.m (1 hunks)
  • Parse/Tests/Unit/UserControllerTests.m (1 hunks)
🔇 Additional comments (7)
Parse/Parse/Internal/Commands/PFRESTUserCommand.m (1)

68-79: LGTM: POST /login with body parameters

The new factory cleanly mirrors the existing GET variant, sets the revocable-session header, and uses POST for body parameters (authData). No issues found.

Parse/Tests/Unit/UserControllerTests.m (1)

238-271: AI summary inconsistency: test not removed

The AI summary mentions removal of testLogInCurrentUserWithUsernamePasswordNullResult, but it’s still present here. No change requested; just flagging the discrepancy.

Parse/Parse/Source/PFUser.m (2)

853-864: Well-implemented login API with authData support

The new login API correctly handles optional authData parameter and maintains backward compatibility. The implementation properly delegates to the controller with the parameters dictionary only when authData is present.


866-871: LGTM: Block-based variant follows established patterns

The block-based convenience method correctly delegates to the task-based variant and maintains consistency with other SDK methods.

Parse/Parse/Internal/User/Controller/PFUserController.h (1)

41-48: Clear documentation for the new login method

The documentation comment effectively explains the purpose and usage of the parameters dictionary, particularly for MFA support. The method signature is well-designed to maintain backward compatibility.

Parse/Parse/Internal/User/Controller/PFUserController.m (2)

129-167: Well-structured login implementation with proper parameter handling

The implementation correctly:

  1. Merges username/password with additional parameters
  2. Prevents authData persistence by only sending it in the request body
  3. Handles error cases consistently with existing login methods
  4. Saves the user as the current object after successful login

The comment on line 139-140 clearly explains the design decision.


69-81: AuthData sanitization is sufficient; no other transient providers found

A repository-wide search confirms that "mfa" is the only transient key in authData. The current logic already removes "mfa" and correctly preserves any other keys (or drops the entire authData when empty). No changes required.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support for Login with additional authData
2 participants