Skip to content

feat(auth): support built-in OAuth methods#439

Open
yordis wants to merge 16 commits into
masterfrom
yordis/feat-built-in-oauth-authentication
Open

feat(auth): support built-in OAuth methods#439
yordis wants to merge 16 commits into
masterfrom
yordis/feat-built-in-oauth-authentication

Conversation

@yordis

@yordis yordis commented Jul 15, 2026

Copy link
Copy Markdown
Member
  • PostgreSQL's method-oriented authentication model gives operators a familiar way to reason about password and OAuth access side by side.
  • Modern deployments need external IdP bearer-token authentication without making database auth depend on plugin-only extension points.
  • Password authentication should remain available while OAuth is introduced so operators can migrate deliberately.

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@cursor

cursor Bot commented Jul 15, 2026

Copy link
Copy Markdown

PR Summary

High Risk
Large changes to authentication, token validation, OAuth callback/cookies, and composite routing affect every HTTP/UI login path and are security-critical.

Overview
Adds multi-method authentication so operators can enable password and OAuth together via Auth:Methods, with legacy internal mapped to password and plugins registered only when they do not clash with built-in method names.

Introduces a built-in OAuth stack: OIDC/JWT Bearer validation (OAuthAuthenticationProvider), a composite provider that routes Basic, Bearer, and client-certificate traffic, and optional certificate-only internal auth when OAuth is enabled without password. New Auth:OAuth options cover issuer, audiences, browser endpoints, and claim mapping.

The admin UI gains a PKCE authorization-code browser flow (challenge/callback endpoints, protected PKCE cookie, token exchange), stores the access token in an oauth_token cookie (replacing oauth_id_token), and shows OAuth alongside Basic on sign-in with clearer oauth_error handling. HTTP 401 challenges now advertise every supported scheme (e.g. Basic and Bearer).

Configuration, telemetry, and startup validation now key off authentication methods (built-in user store for password/OAuth-only setups, default-user password rules) instead of a single AuthenticationType.

Reviewed by Cursor Bugbot for commit 0a09f35. Bugbot is set up for automated code reviews on this repo. Configure here.

@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@yordis, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 28 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c1826084-4048-42f1-94bd-7c4b4513c49e

📥 Commits

Reviewing files that changed from the base of the PR and between e404de6 and 0a09f35.

📒 Files selected for processing (3)
  • src/EventStore.ClusterNode/Components/Pages/SignIn.razor
  • src/EventStore.ClusterNode/Components/Services/OAuthBrowserFlowEndpoints.cs
  • src/EventStore.Core.Tests/Authentication/OAuthBrowserFlowServiceTests.cs

Walkthrough

Authentication now supports multiple configured methods, composite provider routing, OAuth JWT validation, and an OAuth PKCE browser sign-in flow. Configuration, middleware challenges, telemetry, cookies, UI rendering, startup wiring, and automated tests were updated.

Changes

Authentication and OAuth integration

Layer / File(s) Summary
Authentication contracts and provider composition
src/EventStore.Core/Authentication/..., src/EventStore.Core/Configuration/ClusterVNodeOptions.cs, src/EventStore.ClusterNode/ClusterVNodeHostedService.cs
Adds normalized multi-method configuration, OAuth JWT validation, composite routing, certificate enforcement, provider factories, and plugin resolution.
Method reporting and host integration
src/EventStore.Core/ClusterVNode.cs, src/EventStore.Core/Configuration/..., src/EventStore.ClusterNode/Components/Services/..., src/EventStore.ClusterNode/Program.cs
Updates capability checks, telemetry, configuration display, middleware challenges, Data Protection registration, and conditional OAuth endpoint wiring.
OAuth PKCE browser flow
src/EventStore.ClusterNode/Components/Services/OAuthBrowserFlowEndpoints.cs, src/EventStore.ClusterNode/Components/Services/UiCredentialCookie.cs, src/EventStore.ClusterNode/ui-assets/js/ui-auth.js
Protects PKCE state in cookies, validates callbacks, exchanges authorization codes, stores OAuth tokens, and updates browser authorization handling.
Sign-in presentation
src/EventStore.ClusterNode/Components/Services/SecurityBrowserService.cs, src/EventStore.ClusterNode/Components/Pages/SignIn.razor
Detects OAuth browser-flow support and renders OAuth, Basic, or configuration-error states with callback messages.

Validation coverage

Layer / File(s) Summary
Authentication and browser-flow tests
src/EventStore.Core.Tests/Authentication/..., src/EventStore.Core.Tests/Services/Transport/Http/..., src/EventStore.Core.XUnit.Tests/Authentication/..., src/EventStore.Core.XUnit.Tests/Configuration/...
Tests JWT validation, OAuth metadata, PKCE callbacks, cookie behavior, composite certificate routing, multi-scheme challenges, method normalization, and startup validation.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

Sequence Diagram(s)

sequenceDiagram
  participant SignInPage
  participant OAuthBrowserFlowService
  participant OAuthProvider
  participant UiCredentialCookie
  SignInPage->>OAuthBrowserFlowService: request PKCE challenge
  OAuthBrowserFlowService-->>SignInPage: challenge and correlation state
  SignInPage->>OAuthProvider: browser authorization
  OAuthProvider->>OAuthBrowserFlowService: callback with code and state
  OAuthBrowserFlowService->>OAuthProvider: exchange authorization code
  OAuthBrowserFlowService->>UiCredentialCookie: append OAuth token
  OAuthBrowserFlowService-->>SignInPage: redirect to /ui/signin
Loading

Poem

A bunny hops through OAuth’s bright trail,
With PKCE tucked beneath its tail.
Bearer and Basic now share the door,
Composite guards route requests ashore.
Cookies remember the token’s glow—
Sign in, little hare, and go!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly matches the main change: adding built-in OAuth authentication support alongside existing auth methods.
Description check ✅ Passed The description is directly related to the changeset and accurately describes OAuth and password authentication coexistence.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch yordis/feat-built-in-oauth-authentication

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.

Comment thread src/EventStore.Core/Authentication/AuthenticationMethodNames.cs Outdated
yordis added 2 commits July 15, 2026 02:18
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment thread src/EventStore.ClusterNode/Components/Pages/SignIn.razor Outdated
Comment thread src/EventStore.ClusterNode/Components/Pages/SignIn.razor Outdated

@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: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/EventStore.ClusterNode/Components/Pages/SignIn.razor (1)

52-88: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Prevent duplicate error messages when multiple auth methods are supported.

Because Message is conditionally rendered inside both the Authentication.SupportsOAuthBrowserFlow and Authentication.SupportsBasic blocks, an error (such as invalid credentials or a failed OAuth flow) will be displayed twice on the screen if both methods are enabled.

Consider lifting the message display above the individual authentication sections so it is rendered only once.

🎨 Proposed UI fix
 		else
 		{
+			`@if` (!string.IsNullOrWhiteSpace(Message))
+			{
+				<div class="mb-6 rounded-2xl border border-red-200 bg-red-50 p-4 text-sm font-bold text-red-800">`@Message`</div>
+			}
+
 			`@if` (Authentication.SupportsOAuthBrowserFlow)
 			{
 				<div class="mb-6 rounded-[1.5rem] border border-es-ink/10 bg-es-cloud/70 p-5">
 					<h2 class="text-2xl font-black tracking-tight text-es-ink">Continue with OAuth</h2>
 					<p class="mt-2 text-sm leading-6 text-es-muted">Use the configured browser sign-in flow for this node.</p>
 					<button class="mt-4 rounded-2xl bg-es-ink px-5 py-3 text-sm font-black text-white shadow-lg shadow-es-ink/15 transition hover:bg-es-green" type="button" data-ui-oauth-signin data-ui-oauth-return="`@Destination`" data-ui-oauth-type="`@Authentication.Type`" data-ui-oauth-properties="`@Authentication.PropertiesJson`">Continue with OAuth</button>
-					`@if` (!string.IsNullOrWhiteSpace(Message))
-					{
-						<p class="mt-4 rounded-2xl border border-red-200 bg-red-50 p-4 text-sm font-bold text-red-800">`@Message`</p>
-					}
 					<p class="mt-4 hidden rounded-2xl border border-red-200 bg-red-50 p-4 text-sm font-bold text-red-800" data-ui-oauth-status></p>
 				</div>
 			}
 
 			`@if` (Authentication.SupportsBasic)
 			{
 			<EditForm Model="Input" FormName="ui-signin" OnValidSubmit="SignInUser">
 				<AntiforgeryToken />
 				<DataAnnotationsValidator />
 
 				<div class="grid gap-4">
 					<label class="text-sm font-bold text-es-muted">
 						Username
 						<InputText autocomplete="username" autofocus class="mt-2 w-full rounded-2xl border border-es-ink/10 bg-white px-4 py-3 text-es-ink outline-none transition focus:border-es-green focus:ring-4 focus:ring-es-green/15" `@bind-Value`="Input.Username" />
 						<ValidationMessage For="() => Input.Username" />
 					</label>
 					<label class="text-sm font-bold text-es-muted">
 						Password
 						<InputText autocomplete="current-password" type="password" class="mt-2 w-full rounded-2xl border border-es-ink/10 bg-white px-4 py-3 text-es-ink outline-none transition focus:border-es-green focus:ring-4 focus:ring-es-green/15" `@bind-Value`="Input.Password" />
 						<ValidationMessage For="() => Input.Password" />
 					</label>
 				</div>
 
-				`@if` (!string.IsNullOrWhiteSpace(Message))
-				{
-					<p class="mt-5 rounded-2xl border border-red-200 bg-red-50 p-4 text-sm font-bold text-red-800">`@Message`</p>
-				}
-
 				<div class="mt-6 flex flex-wrap gap-2">
🤖 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 `@src/EventStore.ClusterNode/Components/Pages/SignIn.razor` around lines 52 -
88, Move the shared Message display out of the
Authentication.SupportsOAuthBrowserFlow and Authentication.SupportsBasic
sections and render it once above those authentication method blocks. Preserve
the existing conditional visibility and styling, while removing both duplicated
inline Message elements.
🧹 Nitpick comments (3)
src/EventStore.Core/Authentication/CompositeAuthenticationProvider.cs (2)

34-35: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Prevent potential duplicate keys in aggregated public properties.

If multiple underlying providers return the same property key, SelectMany will yield duplicates. If downstream consumers load these properties into a Dictionary, this will throw an ArgumentException. Consider filtering by distinct keys to make the aggregate sequence safer.

♻️ Proposed refactor
 	public override IEnumerable<KeyValuePair<string, string>> GetPublicProperties() =>
-		providers.SelectMany(provider => provider.GetPublicProperties() ?? []);
+		providers
+			.SelectMany(provider => provider.GetPublicProperties() ?? [])
+			.DistinctBy(p => p.Key);
🤖 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 `@src/EventStore.Core/Authentication/CompositeAuthenticationProvider.cs` around
lines 34 - 35, Update CompositeAuthenticationProvider.GetPublicProperties to
deduplicate aggregated properties by their key after flattening provider
results. Preserve each key’s first property value and continue ignoring null
property collections, ensuring downstream consumers receive unique keys.

67-75: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Hardcoded scheme selection limits extensibility.

The SelectScheme method explicitly binds the composite provider routing to Bearer, UserCertificate, and Basic. While this covers the immediate built-in methods, it makes the composite provider rigid and unaware of additional future schemes (such as those introduced by external plugins).

Consider mapping the intended scheme dynamically from the AuthenticationRequest if possible, so that routing adheres better to the Open-Closed Principle for future auth types.

🤖 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 `@src/EventStore.Core/Authentication/CompositeAuthenticationProvider.cs` around
lines 67 - 75, Update SelectScheme to derive the authentication scheme from
AuthenticationRequest or the existing extensible scheme-resolution mechanism
instead of hardcoding Bearer, UserCertificate, and Basic. Preserve the current
built-in routing behavior and fallback while allowing externally registered
authentication schemes to be selected without modifying this method.
src/EventStore.Core.Tests/EventStore.Core.Tests.csproj (1)

29-29: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff

Consider avoiding upward dependencies in test projects.

Adding a project reference from EventStore.Core.Tests to EventStore.ClusterNode breaks the dependency direction (Core $\rightarrow$ ClusterNode).

If this reference is needed to test ClusterNode components (such as the newly added browser flow endpoints), consider moving those tests to an EventStore.ClusterNode.Tests project to preserve clear architectural boundaries.

🤖 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 `@src/EventStore.Core.Tests/EventStore.Core.Tests.csproj` at line 29, The
EventStore.Core.Tests project now depends upward on EventStore.ClusterNode.
Remove the EventStore.ClusterNode project reference from EventStore.Core.Tests
and move the ClusterNode-specific tests, including browser flow endpoint
coverage, into an EventStore.ClusterNode.Tests project.
🤖 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 `@src/EventStore.ClusterNode/Components/Services/OAuthBrowserFlowEndpoints.cs`:
- Around line 42-54: Replace the unbounded _pendingChallenges state used by
CreateCodeChallenge with a short-lived encrypted browser cookie containing the
PKCE verifier, and recover and validate it during the OAuth callback. Remove the
per-request PruneExpired iteration and correlationId dictionary dependency,
ensuring cookie settings bind the challenge to the user agent and prevent Login
CSRF. If server-side storage is retained, use a bounded IMemoryCache with
expiration and require an explicit correlation cookie during callback
validation.

In `@src/EventStore.ClusterNode/Components/Services/SecurityBrowserService.cs`:
- Around line 28-32: Complete the OAuth browser-flow property contract in
SecurityBrowserService by requiring response_type and scope alongside the
existing properties before setting SupportsOAuthBrowserFlow. In
src/EventStore.ClusterNode/ui-assets/js/ui-auth.js lines 106-108, update the
flow-start validation to require code_challenge_uri, redirect_uri,
response_type, and scope before proceeding.

In `@src/EventStore.ClusterNode/Program.cs`:
- Line 297: Update the OAuthBrowserFlowService registration in Program so its
HttpClient uses a SocketsHttpHandler configured with an appropriate
PooledConnectionLifetime instead of an unmanaged new HttpClient(). Preserve the
existing OAuth options and TimeProvider.System arguments.

In `@src/EventStore.Core/Authentication/AuthenticationMethodNames.cs`:
- Around line 32-33: Update AuthenticationMethodNames.Normalize to handle a null
method before calling Trim, returning the appropriate normalized fallback
without throwing. Preserve the existing IsLegacyInternal behavior and
normalization for non-null methods.
- Around line 13-19: Update FromOptions to null-coalesce options.Methods to an
empty array before the LINQ Where call, preserving the existing filtering,
normalization, and deduplication behavior when methods are provided.

---

Outside diff comments:
In `@src/EventStore.ClusterNode/Components/Pages/SignIn.razor`:
- Around line 52-88: Move the shared Message display out of the
Authentication.SupportsOAuthBrowserFlow and Authentication.SupportsBasic
sections and render it once above those authentication method blocks. Preserve
the existing conditional visibility and styling, while removing both duplicated
inline Message elements.

---

Nitpick comments:
In `@src/EventStore.Core.Tests/EventStore.Core.Tests.csproj`:
- Line 29: The EventStore.Core.Tests project now depends upward on
EventStore.ClusterNode. Remove the EventStore.ClusterNode project reference from
EventStore.Core.Tests and move the ClusterNode-specific tests, including browser
flow endpoint coverage, into an EventStore.ClusterNode.Tests project.

In `@src/EventStore.Core/Authentication/CompositeAuthenticationProvider.cs`:
- Around line 34-35: Update CompositeAuthenticationProvider.GetPublicProperties
to deduplicate aggregated properties by their key after flattening provider
results. Preserve each key’s first property value and continue ignoring null
property collections, ensuring downstream consumers receive unique keys.
- Around line 67-75: Update SelectScheme to derive the authentication scheme
from AuthenticationRequest or the existing extensible scheme-resolution
mechanism instead of hardcoding Bearer, UserCertificate, and Basic. Preserve the
current built-in routing behavior and fallback while allowing externally
registered authentication schemes to be selected without modifying this method.
🪄 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: 6b104ea7-2516-47e1-84e1-ff04932deea7

📥 Commits

Reviewing files that changed from the base of the PR and between b2235e2 and 6f30bb9.

📒 Files selected for processing (27)
  • src/Directory.Packages.props
  • src/EventStore.ClusterNode/ClusterVNodeHostedService.cs
  • src/EventStore.ClusterNode/Components/Pages/SignIn.razor
  • src/EventStore.ClusterNode/Components/Services/ConfigurationBrowserService.cs
  • src/EventStore.ClusterNode/Components/Services/OAuthBrowserFlowEndpoints.cs
  • src/EventStore.ClusterNode/Components/Services/SecurityBrowserService.cs
  • src/EventStore.ClusterNode/Components/Services/UiCredentialCookie.cs
  • src/EventStore.ClusterNode/Program.cs
  • src/EventStore.ClusterNode/ui-assets/js/ui-auth.js
  • src/EventStore.Core.Tests/Authentication/CompositeAuthenticationProviderTests.cs
  • src/EventStore.Core.Tests/Authentication/OAuthAuthenticationProviderTests.cs
  • src/EventStore.Core.Tests/Authentication/OAuthBrowserFlowServiceTests.cs
  • src/EventStore.Core.Tests/EventStore.Core.Tests.csproj
  • src/EventStore.Core.Tests/Services/Transport/Http/Authentication/authentication_middleware_should.cs
  • src/EventStore.Core.XUnit.Tests/Authentication/AuthenticationMethodNamesTests.cs
  • src/EventStore.Core/Authentication/AuthenticationMethodNames.cs
  • src/EventStore.Core/Authentication/CompositeAuthenticationProvider.cs
  • src/EventStore.Core/Authentication/CompositeAuthenticationProviderFactory.cs
  • src/EventStore.Core/Authentication/OAuth/OAuthAuthenticationProvider.cs
  • src/EventStore.Core/Authentication/OAuth/OAuthAuthenticationProviderFactory.cs
  • src/EventStore.Core/ClusterVNode.cs
  • src/EventStore.Core/Configuration/ClusterVNodeOptions.cs
  • src/EventStore.Core/Configuration/ClusterVNodeOptionsValidator.cs
  • src/EventStore.Core/EventStore.Core.csproj
  • src/EventStore.Core/Services/Transport/Http/AuthenticationMiddleware.cs
  • src/EventStore.Core/Telemetry/TelemetryService.cs
  • src/EventStore.Core/Util/Opts.cs
💤 Files with no reviewable changes (1)
  • src/EventStore.Core/Util/Opts.cs

Comment thread src/EventStore.ClusterNode/Components/Services/OAuthBrowserFlowEndpoints.cs Outdated
Comment thread src/EventStore.ClusterNode/Components/Services/SecurityBrowserService.cs Outdated
Comment thread src/EventStore.ClusterNode/Program.cs Outdated
Comment thread src/EventStore.Core/Authentication/AuthenticationMethodNames.cs
Comment thread src/EventStore.Core/Authentication/AuthenticationMethodNames.cs Outdated
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment thread src/EventStore.ClusterNode/Components/Services/OAuthBrowserFlowEndpoints.cs Outdated
Comment thread src/EventStore.Core/Configuration/ClusterVNodeOptions.cs
Comment thread src/EventStore.Core/Authentication/AuthenticationMethodNames.cs
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment thread src/EventStore.ClusterNode/Program.cs Outdated
Comment thread src/EventStore.ClusterNode/Components/Services/OAuthBrowserFlowEndpoints.cs Outdated
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment thread src/EventStore.ClusterNode/Components/Pages/SignIn.razor Outdated
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment thread src/EventStore.ClusterNode/ClusterVNodeHostedService.cs
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment thread src/EventStore.Core/Authentication/OAuth/OAuthAuthenticationProvider.cs Outdated
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment thread src/EventStore.ClusterNode/Components/Services/OAuthBrowserFlowEndpoints.cs Outdated
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment thread src/EventStore.ClusterNode/ClusterVNodeHostedService.cs
Comment thread src/EventStore.Core/Configuration/ClusterVNodeOptionsValidator.cs

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

🧹 Nitpick comments (2)
src/EventStore.Core.Tests/Authentication/CompositeAuthenticationProviderTests.cs (1)

54-54: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Dispose the generated test certificate.

X509Certificate2 encapsulates unmanaged resources. To prevent handle leaks and memory exhaustion in the test runner, ensure the certificate is properly disposed after the request is created.

♻️ Proposed fix
-		var request = HttpAuthenticationRequest.CreateWithValidCertificate(context, "admin", CreateCertificate());
+		using var certificate = CreateCertificate();
+		var request = HttpAuthenticationRequest.CreateWithValidCertificate(context, "admin", certificate);
🤖 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
`@src/EventStore.Core.Tests/Authentication/CompositeAuthenticationProviderTests.cs`
at line 54, Update the test around
HttpAuthenticationRequest.CreateWithValidCertificate and CreateCertificate so
the generated X509Certificate2 is disposed after the request is created, using
scoped disposal while preserving the existing request setup.
src/EventStore.Core.Tests/Authentication/OAuthBrowserFlowServiceTests.cs (1)

26-26: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Dispose OAuthBrowserFlowService instances.

The OAuthBrowserFlowService implements IDisposable (and manages an HttpClient). To prevent resource exhaustion in test environments, ensure that these instances are cleanly disposed of by making them using variables.

  • src/EventStore.Core.Tests/Authentication/OAuthBrowserFlowServiceTests.cs#L26-L26: change to using var service = Service(new TokenHandler());
  • src/EventStore.Core.Tests/Authentication/OAuthBrowserFlowServiceTests.cs#L45-L45: change to using var service = Service(handler);
  • src/EventStore.Core.Tests/Authentication/OAuthBrowserFlowServiceTests.cs#L72-L72: change to using var service = Service(handler);
  • src/EventStore.Core.Tests/Authentication/OAuthBrowserFlowServiceTests.cs#L93-L93: change to using var service = Service(handler);
  • src/EventStore.Core.Tests/Authentication/OAuthBrowserFlowServiceTests.cs#L117-L117: change to using var service = Service(handler);
  • src/EventStore.Core.Tests/Authentication/OAuthBrowserFlowServiceTests.cs#L141-L141: change to using var service = Service(handler);
🤖 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 `@src/EventStore.Core.Tests/Authentication/OAuthBrowserFlowServiceTests.cs` at
line 26, OAuthBrowserFlowService test instances are not being disposed. In
src/EventStore.Core.Tests/Authentication/OAuthBrowserFlowServiceTests.cs at
lines 26, 45, 72, 93, 117, and 141, declare each Service(...) result as a using
variable so every OAuthBrowserFlowService is disposed at the end of its test.
🤖 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.

Nitpick comments:
In
`@src/EventStore.Core.Tests/Authentication/CompositeAuthenticationProviderTests.cs`:
- Line 54: Update the test around
HttpAuthenticationRequest.CreateWithValidCertificate and CreateCertificate so
the generated X509Certificate2 is disposed after the request is created, using
scoped disposal while preserving the existing request setup.

In `@src/EventStore.Core.Tests/Authentication/OAuthBrowserFlowServiceTests.cs`:
- Line 26: OAuthBrowserFlowService test instances are not being disposed. In
src/EventStore.Core.Tests/Authentication/OAuthBrowserFlowServiceTests.cs at
lines 26, 45, 72, 93, 117, and 141, declare each Service(...) result as a using
variable so every OAuthBrowserFlowService is disposed at the end of its test.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: dcbda19c-e113-426f-a627-0d31aaf46c7c

📥 Commits

Reviewing files that changed from the base of the PR and between 6f30bb9 and 23c663e.

📒 Files selected for processing (16)
  • src/EventStore.ClusterNode/ClusterVNodeHostedService.cs
  • src/EventStore.ClusterNode/Components/Services/OAuthBrowserFlowEndpoints.cs
  • src/EventStore.ClusterNode/Components/Services/SecurityBrowserService.cs
  • src/EventStore.ClusterNode/Program.cs
  • src/EventStore.ClusterNode/ui-assets/js/ui-auth.js
  • src/EventStore.Core.Tests/Authentication/CompositeAuthenticationProviderTests.cs
  • src/EventStore.Core.Tests/Authentication/OAuthAuthenticationProviderTests.cs
  • src/EventStore.Core.Tests/Authentication/OAuthBrowserFlowServiceTests.cs
  • src/EventStore.Core.Tests/Authentication/SecurityBrowserServiceTests.cs
  • src/EventStore.Core.Tests/EventStore.Core.Tests.csproj
  • src/EventStore.Core.XUnit.Tests/Authentication/AuthenticationMethodNamesTests.cs
  • src/EventStore.Core/Authentication/AuthenticationMethodNames.cs
  • src/EventStore.Core/Authentication/OAuth/OAuthAuthenticationProvider.cs
  • src/EventStore.Core/Authentication/UserCertificateAuthenticationProvider.cs
  • src/EventStore.Core/Authentication/UserCertificateAuthenticationProviderFactory.cs
  • src/EventStore.Core/Configuration/ClusterVNodeOptions.cs
🚧 Files skipped from review as they are similar to previous changes (8)
  • src/EventStore.Core.XUnit.Tests/Authentication/AuthenticationMethodNamesTests.cs
  • src/EventStore.ClusterNode/ClusterVNodeHostedService.cs
  • src/EventStore.Core/Authentication/AuthenticationMethodNames.cs
  • src/EventStore.Core.Tests/EventStore.Core.Tests.csproj
  • src/EventStore.ClusterNode/Program.cs
  • src/EventStore.Core/Configuration/ClusterVNodeOptions.cs
  • src/EventStore.Core/Authentication/OAuth/OAuthAuthenticationProvider.cs
  • src/EventStore.ClusterNode/ui-assets/js/ui-auth.js

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment thread src/EventStore.Core/ClusterVNode.cs Outdated
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment thread src/EventStore.ClusterNode/Program.cs Outdated
@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
putComment timed out

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/EventStore.Core/Configuration/ClusterVNodeOptionsValidator.cs (1)

153-164: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Validate default passwords based on password authentication, not the built-in user store.

IncludesBuiltInUserStore is also true for OAuth-only configurations, so custom default admin/ops passwords are accepted even though password authentication is disabled and those passwords cannot be used. Use IncludesPassword here; retain IncludesBuiltInUserStore for user-management visibility.

Proposed fix
-		var needsDefaultUsers = AuthenticationMethodNames.IncludesBuiltInUserStore(options.Auth);
-		if (options.Application.AuthDisabled() || !needsDefaultUsers)
+		var passwordAuthenticationEnabled = AuthenticationMethodNames.IncludesPassword(options.Auth);
+		if (options.Application.AuthDisabled() || !passwordAuthenticationEnabled)
🤖 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 `@src/EventStore.Core/Configuration/ClusterVNodeOptionsValidator.cs` around
lines 153 - 164, Update the default admin/ops password validation in
ClusterVNodeOptionsValidator to determine needsDefaultUsers with
AuthenticationMethodNames.IncludesPassword(options.Auth) instead of
IncludesBuiltInUserStore. Preserve IncludesBuiltInUserStore for user-management
visibility elsewhere.
🤖 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.

Outside diff comments:
In `@src/EventStore.Core/Configuration/ClusterVNodeOptionsValidator.cs`:
- Around line 153-164: Update the default admin/ops password validation in
ClusterVNodeOptionsValidator to determine needsDefaultUsers with
AuthenticationMethodNames.IncludesPassword(options.Auth) instead of
IncludesBuiltInUserStore. Preserve IncludesBuiltInUserStore for user-management
visibility elsewhere.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1128c4fa-63ca-470c-89c9-51fae0ec9436

📥 Commits

Reviewing files that changed from the base of the PR and between 23c663e and cc978b1.

📒 Files selected for processing (11)
  • src/EventStore.ClusterNode/Components/Services/ConfigurationBrowserService.cs
  • src/EventStore.ClusterNode/Components/Services/SecurityBrowserService.cs
  • src/EventStore.ClusterNode/Program.cs
  • src/EventStore.Core.Tests/Authentication/CompositeAuthenticationProviderTests.cs
  • src/EventStore.Core.Tests/Authentication/SecurityBrowserServiceTests.cs
  • src/EventStore.Core.XUnit.Tests/Authentication/AuthenticationMethodNamesTests.cs
  • src/EventStore.Core.XUnit.Tests/Configuration/ClusterVNodeOptionsValidatorTests.cs
  • src/EventStore.Core/Authentication/AuthenticationMethodNames.cs
  • src/EventStore.Core/Authentication/UserCertificateAuthenticationProvider.cs
  • src/EventStore.Core/ClusterVNode.cs
  • src/EventStore.Core/Configuration/ClusterVNodeOptionsValidator.cs
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/EventStore.Core/Authentication/UserCertificateAuthenticationProvider.cs
  • src/EventStore.Core/Authentication/AuthenticationMethodNames.cs
  • src/EventStore.ClusterNode/Program.cs

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment thread src/EventStore.ClusterNode/Components/Pages/SignIn.razor Outdated
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment thread src/EventStore.ClusterNode/Components/Pages/SignIn.razor Outdated
@yordis yordis force-pushed the yordis/feat-built-in-oauth-authentication branch from e404de6 to 675962f Compare July 15, 2026 10:47

@cursor cursor 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.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 675962f. Configure here.

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@yordis yordis force-pushed the yordis/feat-built-in-oauth-authentication branch from 675962f to 0a09f35 Compare July 15, 2026 10:53
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