feat: Improve OAuth account creation flows#306
Closed
hhvrc wants to merge 2 commits into
Closed
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
Improves the OAuth signup/account-creation UX by distinguishing username vs email conflicts and adding a password-based linking endpoint for “email already exists” OAuth signups.
Changes:
- Split OAuth-only account creation conflicts into
UsernameAlreadyTakenvsEmailAlreadyTaken { HasPassword }and surface more specific problems fromsignup-finalize. - Add
POST /{provider}/signup-link-passwordto link an in-flight OAuth signup to an existing password account. - Introduce additional OAuth/account problem codes to support the new flow and error routing.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| Common/Errors/AccountError.cs | Adds new account conflict problems for email-taken cases that do/don’t allow password linking. |
| API/Services/Account/IAccountService.cs | Updates the OAuth-only account creation contract to return distinct conflict markers. |
| API/Services/Account/AccountService.cs | Implements conflict differentiation (username vs email, plus password-present hint). |
| API/OAuth/OAuthError.cs | Adds new OAuth problems for provider-already-linked and link failure. |
| API/Models/Requests/OAuthLinkPasswordRequest.cs | Adds request model for password-based linking endpoint. |
| API/Controller/OAuth/SignupLinkWithPassword.cs | New endpoint to authenticate by password and link OAuth identity to an existing account. |
| API/Controller/OAuth/SignupFinalize.cs | Updates finalize endpoint to return more specific conflict problems and preserve the flow cookie on conflict. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+136
to
+140
| // Reuse existing guards. Blacklist hits are reported as username-taken so we don't leak | ||
| // the existence of the blacklist or the validity of the email domain to anonymous callers. | ||
| if (await IsUserNameBlacklisted(username) || await IsEmailProviderBlacklisted(email)) | ||
| return new AccountWithEmailOrUsernameExists(); | ||
| return new UsernameAlreadyTaken(); | ||
|
|
Comment on lines
216
to
+220
| { | ||
| await tx.RollbackAsync(); | ||
| return new AccountWithEmailOrUsernameExists(); | ||
|
|
||
| // Map known unique indexes to specific outcomes. | ||
| switch (pgEx.ConstraintName) |
Comment on lines
+234
to
+238
| // Ambiguous constraint — re-query both. Prefer the email outcome. | ||
| var emailRow = await _db.Users | ||
| .Where(u => u.Email == email) | ||
| .Select(u => new { HasPassword = u.PasswordHash != null }) | ||
| .FirstOrDefaultAsync(); |
Comment on lines
+42
to
+47
| /// <returns> | ||
| /// Success with the created user, or a conflict marker distinguishing username vs. email collision. | ||
| /// When both collide, prefer <see cref="EmailAlreadyTaken"/> (the email path enables linking via | ||
| /// password login; username conflict can only be retried). | ||
| /// </returns> | ||
| Task<OneOf<Success<User>, UsernameAlreadyTaken, EmailAlreadyTaken>> CreateOAuthOnlyAccountAsync(string email, string username, string provider, string providerAccountId, string? providerAccountName, bool isEmailTrusted); |
|
|
||
| _logger.LogInformation( | ||
| "Linked OAuth provider {Provider} (external id {ExternalId}) to existing user {UserId} via password", | ||
| provider, auth.ExternalAccountId, account.Id); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.