Skip to content

feat: Add Microsoft authentication adapter#472

Open
DENGXUELIN wants to merge 3 commits into
parse-community:mainfrom
DENGXUELIN:add-microsoft-authentication
Open

feat: Add Microsoft authentication adapter#472
DENGXUELIN wants to merge 3 commits into
parse-community:mainfrom
DENGXUELIN:add-microsoft-authentication

Conversation

@DENGXUELIN

@DENGXUELIN DENGXUELIN commented May 13, 2026

Copy link
Copy Markdown

Summary

  • Add ParseMicrosoft authentication helpers for Microsoft authData
  • Support secure auth code payloads with code + redirect_uri and insecure auth mode id + access_token payloads
  • Add callback, async/await, and Combine test coverage

Addresses the Microsoft Graph adapter listed in #55.

Testing

  • git diff --check
  • Not run: swift test is unavailable in this local Windows environment because the swift executable is not installed. GitHub Actions should run the full macOS/Linux/Windows CI matrix on this PR.

Summary by CodeRabbit

Release Notes

  • New Features
    • Microsoft account authentication now supported for user login and linking to existing accounts
    • Available with async/await syntax for modern Swift concurrency patterns
    • Combine publisher support for reactive implementation patterns
    • Multiple authentication methods supported including OAuth authorization code flow and token-based authentication

@parse-github-assistant

parse-github-assistant Bot commented May 13, 2026

Copy link
Copy Markdown

🚀 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.

Tip

  • Keep pull requests small. Large PRs will be rejected. Break complex features into smaller, incremental PRs.
  • Use Test Driven Development. Write failing tests before implementing functionality. Ensure tests pass.
  • Group code into logical blocks. Add a short comment before each block to explain its purpose.
  • We offer conceptual guidance. Coding is up to you. PRs must be merge-ready for human review.
  • Our review focuses on concept, not quality. PRs with code issues will be rejected. Use an AI agent.
  • Human review time is precious. Avoid review ping-pong. Inspect and test your AI-generated code.

Note

Please respond to review comments from AI agents just like you would to comments from a human reviewer. Let the reviewer resolve their own comments, unless they have reviewed and accepted your commit, or agreed with your explanation for why the feedback was incorrect.

Caution

Pull requests must be written using an AI agent with human supervision. Pull requests written entirely by a human will likely be rejected, because of lower code quality, higher review effort and the higher risk of introducing bugs. Please note that AI review comments on this pull request alone do not satisfy this requirement. Our CI and AI review are safeguards, not development tools. If many issues are flagged, rethink your development approach. Invest more effort in planning and design rather than using review cycles to fix low-quality code.

@coderabbitai

coderabbitai Bot commented May 13, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@DENGXUELIN has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 60 minutes before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f15ebf63-91b7-4bb8-9b2e-862fb9f666c4

📥 Commits

Reviewing files that changed from the base of the PR and between 515a86d and af06fc3.

📒 Files selected for processing (1)
  • Tests/ParseSwiftTests/ParseMicrosoftCombineTests.swift
📝 Walkthrough

Walkthrough

This PR adds complete Microsoft OAuth authentication support to ParseSwift: core callback APIs, async/await wrappers, Combine publishers, and comprehensive tests for each API style.

Changes

Microsoft Authentication Support

Layer / File(s) Summary
Core Microsoft Authentication Implementation
Sources/ParseSwift/Authentication/3rd Party/ParseMicrosoft/ParseMicrosoft.swift
Introduces generic ParseMicrosoft<AuthenticatedUser> type conforming to ParseAuthentication with internal AuthenticationKeys helpers to build authData for standard OAuth (code + redirect_uri) and insecure modes (id + access_token). Public APIs provide login/link with multiple parameter signatures, mandatory key validation, and ParseUser convenience accessors (static var microsoft and instance var microsoft).
Async/Await Support
Sources/ParseSwift/Authentication/3rd Party/ParseMicrosoft/ParseMicrosoft+async.swift
Adds async/await wrappers for all login and link variants using withCheckedThrowingContinuation to bridge callback-based implementations, enabling modern Swift concurrency patterns when available.
Combine Publisher Support
Sources/ParseSwift/Authentication/3rd Party/ParseMicrosoft/ParseMicrosoft+combine.swift
Provides loginPublisher and linkPublisher methods returning Future<AuthenticatedUser, ParseError> for all parameter variants, enabling reactive authentication flows when Combine is available.
Callback-based API Tests
Tests/ParseSwiftTests/ParseMicrosoftTests.swift
Comprehensive XCTest suite validating callback-based authentication: authData dictionary construction, mandatory key validation, login via code/redirectURI and authData, link via code/redirectURI and authData, unlink, and error handling for invalid keys.
Async/Await API Tests
Tests/ParseSwiftTests/ParseMicrosoftAsyncTests.swift
XCTest suite exercising async/await flows when Swift concurrency is available: async login, link, unlink, and assertions for user state, session tokens, and Microsoft provider linkage.
Combine Publisher Tests
Tests/ParseSwiftTests/ParseMicrosoftCombineTests.swift
XCTest suite validating Combine publishers when available: loginPublisher, linkPublisher, unlinkPublisher, and provider linkage state assertions with mocked server responses.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 5 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Engage In Review Feedback ⚠️ Warning Review feedback about misleading test descriptions was not addressed. ParseMicrosoftCombineTests.swift still uses "Save" instead of "Login"/"Link"/"Unlink" in 7 test expectations. Fix expectation descriptions to use operation-specific names or discuss with reviewer why current approach is acceptable.
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: Add Microsoft authentication adapter' begins with the required 'feat:' prefix and accurately describes the main change of adding Microsoft authentication support.
Description check ✅ Passed The PR description includes a clear summary of changes, references a related issue (#55), and provides testing notes, but lacks the new PR checklist structure and TODOs section from the template.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Security Check ✅ Passed No security vulnerabilities detected. Credentials properly handled, input validation present, no logging of sensitive data, secure async patterns, only standard framework imports.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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

Comment @coderabbitai help to get the list of available commands and usage tips.

@DENGXUELIN DENGXUELIN changed the title Add Microsoft authentication adapter feat: add Microsoft authentication adapter May 13, 2026
@parse-github-assistant

Copy link
Copy Markdown

I will reformat the title to use the proper commit message syntax.

@parse-github-assistant parse-github-assistant Bot changed the title feat: add Microsoft authentication adapter feat: Add Microsoft authentication adapter May 13, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (2)
Tests/ParseSwiftTests/ParseMicrosoftCombineTests.swift (1)

89-358: ⚡ Quick win

Add Combine tests for insecure-mode Microsoft overloads.

The suite doesn’t currently exercise loginPublisher(id:accessToken:) and linkPublisher(id:accessToken:), so one supported auth mode remains unvalidated in this layer.

Proposed test additions
+    func testLoginInsecureMode() {
+        var subscriptions = Set<AnyCancellable>()
+        let expectation1 = XCTestExpectation(description: "Login insecure mode")
+
+        var serverResponse = LoginSignupResponse()
+        serverResponse.authData = [
+            serverResponse.microsoft.__type: [
+                "id": "testing-id",
+                "access_token": "testing-token"
+            ]
+        ]
+
+        let encoded = try! serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)
+        MockURLProtocol.mockRequests { _ in
+            MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)
+        }
+
+        User.microsoft.loginPublisher(id: "testing-id", accessToken: "testing-token")
+            .sink(receiveCompletion: { completion in
+                if case let .failure(error) = completion { XCTFail(error.localizedDescription) }
+                expectation1.fulfill()
+            }, receiveValue: { user in
+                XCTAssertEqual(user, User.current)
+                XCTAssertTrue(user.microsoft.isLinked)
+            })
+            .store(in: &subscriptions)
+
+        wait(for: [expectation1], timeout: 20.0)
+    }
+
+    func testLinkInsecureMode() throws {
+        var subscriptions = Set<AnyCancellable>()
+        let expectation1 = XCTestExpectation(description: "Link insecure mode")
+
+        _ = try loginNormally()
+        MockURLProtocol.removeAll()
+
+        let serverResponse = LoginSignupResponse()
+        let encoded = try! serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)
+        MockURLProtocol.mockRequests { _ in
+            MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)
+        }
+
+        User.microsoft.linkPublisher(id: "testing-id", accessToken: "testing-token")
+            .sink(receiveCompletion: { completion in
+                if case let .failure(error) = completion { XCTFail(error.localizedDescription) }
+                expectation1.fulfill()
+            }, receiveValue: { user in
+                XCTAssertEqual(user, User.current)
+                XCTAssertTrue(user.microsoft.isLinked)
+            })
+            .store(in: &subscriptions)
+
+        wait(for: [expectation1], timeout: 20.0)
+    }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Tests/ParseSwiftTests/ParseMicrosoftCombineTests.swift` around lines 89 -
358, Add Combine tests that call the insecure-mode Microsoft overloads by
duplicating the pattern from testLoginAuthData and testLinkAuthData: create a
serverResponse (LoginSignupResponse), encode/decode to produce userOnServer,
mock the network with MockURLProtocol.mockRequests returning the encoded
response, build authData via
ParseMicrosoft<User>.AuthenticationKeys.id.makeDictionary(id: "testing",
accessToken: "token_value") and then call
User.microsoft.loginPublisher(id:accessToken:) and
User.microsoft.linkPublisher(id:accessToken:) respectively, subscribing and
asserting equality with User.current, userOnServer properties, and that
microsoft.isLinked is true; name the new tests e.g. testLoginInsecureMode and
testLinkInsecureMode and mirror the existing expectation/store logic so they
follow the same structure as the other Combine tests.
Tests/ParseSwiftTests/ParseMicrosoftTests.swift (1)

116-121: ⚡ Quick win

Consider adding end-to-end tests for insecure auth mode.

While this test verifies dictionary construction for the insecure auth mode (id + access_token), there are no tests that actually call login(id:accessToken:) or link(id:accessToken:) through the full flow with mock server responses. The PR summary states that two auth payload modes are supported, but only the secure OAuth flow (code + redirect_uri) is tested end-to-end.

🧪 Suggested test additions

Add tests similar to testLogin and testLinkLoggedInUserWithMicrosoft, but using:

User.microsoft.login(id: "user_id", accessToken: "access_token") { result in
    // assertions
}

This would ensure the insecure auth mode works correctly through the complete authentication flow.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Tests/ParseSwiftTests/ParseMicrosoftTests.swift` around lines 116 - 121, Add
end-to-end tests that exercise the insecure auth payload path (id +
access_token) by invoking User.microsoft.login(id:accessToken:){...} and
User.microsoft.link(id:accessToken:){...} and asserting success/failure and
server request/response handling just like the existing testLogin and
testLinkLoggedInUserWithMicrosoft tests; ensure the tests use mock server
responses matching the insecure payload built by
ParseMicrosoft.AuthenticationKeys.id.makeDictionary(id:accessToken:) and verify
the created/linked user state and any returned session/token fields.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Sources/ParseSwift/Authentication/3rd`
Party/ParseMicrosoft/ParseMicrosoft.swift:
- Around line 209-211: The error message passed to completion(.failure(...)) in
ParseMicrosoft (the string that currently reads "Should have authData in
consisting of keys \"code\" and \"redirectURI\", or \"id\" and
\"accessToken\".") has a grammatical mistake; update that message in the failing
branch (the completion(.failure(...)) call) to read "Should have authData
consisting of keys \"code\" and \"redirectURI\", or \"id\" and \"accessToken\"."
so it matches the login method's phrasing.
- Around line 140-142: Update the error message string in ParseMicrosoft.swift
where the completion is invoked with completion(.failure(.init(code:
.unknownError, message: "..."))): change "Should have authData in consisting of
keys \"code\" and \"redirectURI\", or \"id\" and \"accessToken\"." to use
correct grammar by removing "in" so it reads "Should have authData consisting of
keys \"code\" and \"redirectURI\", or \"id\" and \"accessToken\"." This edit is
in the completion failure branch that validates authData.

In `@Sources/ParseSwift/Authentication/3rd`
Party/ParseMicrosoft/ParseMicrosoft+async.swift:
- Around line 28-33: The continuation.resume call is incorrect for Result-based
callbacks: in each async wrapper for the Microsoft login methods (the functions
that call self.login(code:redirectURI:id:options:completion:),
self.login(token:options:completion:) and
self.login(credential:options:completion:)) replace continuation.resume with
continuation.resume(with:) so the Result<AuthenticatedUser, ParseError> passed
into the completion is forwarded properly; keep the same completion argument but
call continuation.resume(with: result) (i.e., use resume(with:) to accept the
Result) in all three async login methods.

In `@Tests/ParseSwiftTests/ParseMicrosoftAsyncTests.swift`:
- Around line 89-285: Add async tests covering the insecure auth-mode endpoints
by creating two new `@MainActor` test methods modeled on testLogin and testLink:
implement testLoginInsecureMode() that builds a LoginSignupResponse, uses
ParseMicrosoft<User>.AuthenticationKeys.id.makeDictionary(id:accessToken:) to
create authData, encodes/decodes the server response and mocks the network, then
calls User.microsoft.login(id:accessToken:) and asserts equality with
User.current and expected fields; implement testLinkInsecureMode() that reuses
loginNormally(), prepares a LoginSignupResponse with updatedAt, mocks the
response, then calls User.microsoft.link(id:accessToken:) and asserts updatedAt,
username/password/link state similar to testLink; use the same helper types
(LoginSignupResponse, MockURLProtocol) and assertions as existing tests.

---

Nitpick comments:
In `@Tests/ParseSwiftTests/ParseMicrosoftCombineTests.swift`:
- Around line 89-358: Add Combine tests that call the insecure-mode Microsoft
overloads by duplicating the pattern from testLoginAuthData and
testLinkAuthData: create a serverResponse (LoginSignupResponse), encode/decode
to produce userOnServer, mock the network with MockURLProtocol.mockRequests
returning the encoded response, build authData via
ParseMicrosoft<User>.AuthenticationKeys.id.makeDictionary(id: "testing",
accessToken: "token_value") and then call
User.microsoft.loginPublisher(id:accessToken:) and
User.microsoft.linkPublisher(id:accessToken:) respectively, subscribing and
asserting equality with User.current, userOnServer properties, and that
microsoft.isLinked is true; name the new tests e.g. testLoginInsecureMode and
testLinkInsecureMode and mirror the existing expectation/store logic so they
follow the same structure as the other Combine tests.

In `@Tests/ParseSwiftTests/ParseMicrosoftTests.swift`:
- Around line 116-121: Add end-to-end tests that exercise the insecure auth
payload path (id + access_token) by invoking
User.microsoft.login(id:accessToken:){...} and
User.microsoft.link(id:accessToken:){...} and asserting success/failure and
server request/response handling just like the existing testLogin and
testLinkLoggedInUserWithMicrosoft tests; ensure the tests use mock server
responses matching the insecure payload built by
ParseMicrosoft.AuthenticationKeys.id.makeDictionary(id:accessToken:) and verify
the created/linked user state and any returned session/token fields.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 05af3ca0-e320-4204-9bc2-0afb3114ee30

📥 Commits

Reviewing files that changed from the base of the PR and between 645180e and 2d41275.

📒 Files selected for processing (6)
  • Sources/ParseSwift/Authentication/3rd Party/ParseMicrosoft/ParseMicrosoft+async.swift
  • Sources/ParseSwift/Authentication/3rd Party/ParseMicrosoft/ParseMicrosoft+combine.swift
  • Sources/ParseSwift/Authentication/3rd Party/ParseMicrosoft/ParseMicrosoft.swift
  • Tests/ParseSwiftTests/ParseMicrosoftAsyncTests.swift
  • Tests/ParseSwiftTests/ParseMicrosoftCombineTests.swift
  • Tests/ParseSwiftTests/ParseMicrosoftTests.swift

Comment thread Tests/ParseSwiftTests/ParseMicrosoftAsyncTests.swift
@DENGXUELIN

Copy link
Copy Markdown
Author

Implemented the CodeRabbit feedback in 515a86d: added insecure auth mode coverage for callback, async/await, and Combine flows; fixed the authData validation message grammar; and made the async continuation forwarding explicit with resume(with:).

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 13, 2026

Copy link
Copy Markdown

@DENGXUELIN Thanks for implementing the feedback and detailing the changes in commit 515a86d! I'll kick off a new review of the PR now.

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@DENGXUELIN

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 13, 2026

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Tests/ParseSwiftTests/ParseMicrosoftCombineTests.swift`:
- Line 91: Several XCTestExpectation instances in ParseMicrosoftCombineTests
(e.g., the variable expectation1 and the other expectations at the mentioned
locations) use the generic description "Save" which is misleading; update each
XCTestExpectation(description: "...") to a clear, specific description that
matches the operation being tested (for example "SaveUser", "FetchObjects",
"DeleteObject", "UpdateRecord", etc.) so failures show the actual intent—locate
the expectations declared at the referenced positions (the one currently named
expectation1 and the expectations at the other noted lines) and replace the
string literal "Save" with an accurate, descriptive name for that test step.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e31a496d-8316-4d7d-99ac-210b7965b582

📥 Commits

Reviewing files that changed from the base of the PR and between 2d41275 and 515a86d.

📒 Files selected for processing (5)
  • Sources/ParseSwift/Authentication/3rd Party/ParseMicrosoft/ParseMicrosoft+async.swift
  • Sources/ParseSwift/Authentication/3rd Party/ParseMicrosoft/ParseMicrosoft.swift
  • Tests/ParseSwiftTests/ParseMicrosoftAsyncTests.swift
  • Tests/ParseSwiftTests/ParseMicrosoftCombineTests.swift
  • Tests/ParseSwiftTests/ParseMicrosoftTests.swift
🚧 Files skipped from review as they are similar to previous changes (3)
  • Tests/ParseSwiftTests/ParseMicrosoftAsyncTests.swift
  • Sources/ParseSwift/Authentication/3rd Party/ParseMicrosoft/ParseMicrosoft+async.swift
  • Sources/ParseSwift/Authentication/3rd Party/ParseMicrosoft/ParseMicrosoft.swift

Comment thread Tests/ParseSwiftTests/ParseMicrosoftCombineTests.swift Outdated
@DENGXUELIN

Copy link
Copy Markdown
Author

This PR is ready for maintainer review. I addressed the CodeRabbit findings in 515a86d, and the visible CodeRabbit / Commit Message / Snyk checks are now green. The upstream CI workflow is currently waiting for maintainer approval to run for this fork PR.

@DENGXUELIN

Copy link
Copy Markdown
Author

Bounty payment address if needed: BSC / BEP20 wallet

@DENGXUELIN

Copy link
Copy Markdown
Author

Correction: bounty payment address if needed: BSC / BEP20 wallet 0xEF8139503b8416FB0eded1d33F7eBcCA3C32A83E.

@DENGXUELIN

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 14, 2026

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@DENGXUELIN

Copy link
Copy Markdown
Author

I rechecked this branch after the latest CodeRabbit note. The expectation descriptions in ParseMicrosoftCombineTests are already operation-specific on the current head commit af06fc3 and are no longer using the generic "Save" label. If CodeRabbit is still showing the earlier finding, it may be reflecting the previous incremental review window rather than the latest head state.

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.

1 participant