Skip to content

Split LoginByPassword into explicit RegisterByPassword and LoginByPassword#21

Merged
slhmy merged 3 commits into
mainfrom
copilot/refactor-login-by-password-logic
Apr 15, 2026
Merged

Split LoginByPassword into explicit RegisterByPassword and LoginByPassword#21
slhmy merged 3 commits into
mainfrom
copilot/refactor-login-by-password-logic

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 15, 2026

LoginByPassword was doing implicit upsert semantics: creating users on first call and verifying credentials on subsequent calls. This conflates registration and authentication into a single ambiguous endpoint.

Changes

Proto (proto/identra/v1/)

  • Added RegisterByPasswordRequest / RegisterByPasswordResponse messages to types.proto
  • Added RegisterByPassword RPC at POST /password/register in identra_service.proto

Service (internal/application/identra/service.go)

  • RegisterByPassword: creates a new user; returns AlreadyExists if email is taken (including concurrent-registration races — duplicate-key errors from the persistence layer are translated to AlreadyExists)
  • LoginByPassword: authenticates only; returns NotFound if no account, FailedPrecondition if password login isn't configured, Unauthenticated for wrong credentials

Persistence (internal/infrastructure/persistence/)

  • gorm_user_store.go: Create now maps gorm.ErrDuplicatedKeydomain.ErrAlreadyExists
  • mongo_user_store.go: Create now maps mongo.IsDuplicateKeyError()domain.ErrAlreadyExists

Domain (internal/domain/user.go)

  • Added domain.ErrAlreadyExists sentinel error

Generated (gen/)

  • All protobuf/gRPC/gateway/OpenAPI files regenerated to reflect new RPC

Tests (internal/application/identra/service_password_test.go)

  • Added unit tests asserting gRPC status codes for all branches of RegisterByPassword and LoginByPassword, including the concurrent-registration race scenario

Behaviour comparison

Scenario Before After
Unknown email Creates user + issues token RegisterByPassword: creates user; LoginByPassword: NOT_FOUND
Known email, no password Sets password + issues token RegisterByPassword: ALREADY_EXISTS; LoginByPassword: FAILED_PRECONDITION
Known email, correct password Issues token LoginByPassword: issues token
Known email, wrong password UNAUTHENTICATED LoginByPassword: UNAUTHENTICATED
Concurrent registration (race) INTERNAL RegisterByPassword: ALREADY_EXISTS

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR separates implicit “upsert” password login into two explicit flows—RegisterByPassword for account creation and LoginByPassword for authentication—making the API behavior unambiguous across gRPC/HTTP/OpenAPI.

Changes:

  • Added RegisterByPassword request/response messages and a new RegisterByPassword RPC (POST /password/register) to the proto API.
  • Implemented Service.RegisterByPassword and updated Service.LoginByPassword to authenticate-only with clearer status codes.
  • Regenerated Go gRPC/gateway and OpenAPI outputs to reflect the new RPC.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
proto/identra/v1/types.proto Adds RegisterByPasswordRequest/Response message types.
proto/identra/v1/identra_service.proto Adds RegisterByPassword RPC and HTTP mapping.
internal/application/identra/service.go Implements registration and updates password-login semantics.
gen/openapi/identra.swagger.json Exposes /password/register in generated OpenAPI spec.
gen/go/identra/v1/types.pb.go Regenerated Go types for new proto messages.
gen/go/identra/v1/identra_service_grpc.pb.go Regenerated gRPC client/server stubs including new RPC.
gen/go/identra/v1/identra_service.pb.gw.go Regenerated grpc-gateway handlers/routes for /password/register.
gen/go/identra/v1/identra_service.pb.go Regenerated service descriptors and type mappings.

Comment thread internal/application/identra/service.go
Comment on lines +535 to +542
func (s *Service) RegisterByPassword(
ctx context.Context,
req *identra_v1_pb.RegisterByPasswordRequest,
) (*identra_v1_pb.RegisterByPasswordResponse, error) {
email := strings.TrimSpace(req.GetEmail())
password := req.GetPassword()
if email == "" || password == "" {
return nil, status.Error(codes.InvalidArgument, "email and password are required")
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@slhmy
Copy link
Copy Markdown
Contributor

slhmy commented Apr 15, 2026

@copilot apply changes based on the comments in this thread

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 15, 2026

@copilot apply changes based on the comments in this thread

Done in commit 2e9e749.

Duplicate-key race condition (RegisterByPassword):

  • Added domain.ErrAlreadyExists sentinel error to the domain package
  • gorm_user_store.Create now maps gorm.ErrDuplicatedKeydomain.ErrAlreadyExists
  • mongoUserStore.Create now maps mongo.IsDuplicateKeyError()domain.ErrAlreadyExists
  • RegisterByPassword checks errors.Is(createErr, domain.ErrAlreadyExists) and returns codes.AlreadyExists directly — no re-query needed

Unit tests (service_password_test.go):

  • TestRegisterByPassword_MissingFieldsInvalidArgument
  • TestRegisterByPassword_Success — happy path, returns a token
  • TestRegisterByPassword_ExistingEmailAlreadyExists
  • TestRegisterByPassword_DuplicateRaceCreate returns domain.ErrAlreadyExists (simulated race) → AlreadyExists
  • TestLoginByPassword_MissingFieldsInvalidArgument
  • TestLoginByPassword_NotFoundNotFound
  • TestLoginByPassword_NoPasswordFailedPrecondition
  • TestLoginByPassword_WrongPasswordUnauthenticated
  • TestLoginByPassword_Success — happy path, returns a token

Copilot AI requested a review from slhmy April 15, 2026 04:56
@slhmy slhmy merged commit 6a44ed8 into main Apr 15, 2026
2 checks passed
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.

3 participants