Skip to content

Scaffold & Document: Admin Account Creation via AWS Cognito with Backend Database Sync (Mocked — No Implementation) (Spike) #222

@SamNie2027

Description

@SamNie2027

Please branch off of the authentication branch.

Context

When a new admin needs to be added to the system, we can't just create them in one place — we need to create them in two places at once and keep them in sync:

  1. Our backend database — a new User record and a linked AdminInfo record
  2. AWS Cognito — a new user with the same email, so they can actually log in

If either of these steps fails, we should not partially create the admin. Both need to succeed together.

What is Cognito (quick recap)?

Cognito is AWS's authentication service. It handles login, passwords, and session tokens. Our app uses it to verify "is this person who they say they are?" Our database handles everything else about the user — their role, their info, their permissions.

Who can create a new admin?

New admin accounts should only be created by an existing authenticated admin — not by just anyone. The chosen approach is the Temporary Password flow, which leans on Cognito's built-in behavior and keeps custom code minimal.

Chosen Approach: Temporary Password via Email (Cognito Native Flow)

An existing admin triggers the creation of a new admin account directly. The backend immediately creates the database records and Cognito user, and Cognito auto-emails the new admin a temporary password. On first login, Cognito forces a password change before the user can do anything.

Why it's reasonably secure:

  • Only an existing admin can trigger the creation
  • Temp passwords are short-lived and randomly generated
  • Cognito enforces a password reset on first use

Complexity: Lower. Most of this is handled by Cognito natively. The main work is wiring up the database creation alongside the Cognito creation and making sure both succeed or both roll back.

The Two-System Problem

Because we're writing to both Cognito and our database, we need to think carefully about what happens if one fails. For example:

  • What if the Cognito user is created but the database write fails? → We have a ghost user in Cognito with no database record
  • What if the database write succeeds but Cognito fails? → We have a database record with no way to log in

This ticket should document a strategy for handling these failure cases, even if the actual error handling isn't implemented yet.

Acceptance Criteria

This ticket is scaffolding and documentation only — no real AWS calls, no real database writes. All functions must be mocked and documented.

  • Overall workflow is documented as a clear numbered sequence covering both options, from "admin clicks Create New Admin" to "new admin is fully set up." This should be written in plain English in the module-level README block and cover:

    • Who initiates the flow and how
    • What happens in Cognito
    • What happens in the database
    • What the new admin experiences (email, first login, password reset)
  • createAdminUser(email, temporaryPassword) is scaffolded with a mock and JSDoc that describes:

    • What it does (calls Cognito AdminCreateUser and triggers the temp password email)
    • Parameters and expected types
    • Return value on success (e.g., Cognito username and user status)
    • What errors it might throw (e.g., email already exists in Cognito)
  • createAdminDatabaseRecords(email, cognitoUsername) is scaffolded with a mock and JSDoc that describes:

    • What it does (creates a User record and an AdminInfo record in the database, linked together)
    • Parameters and expected types
    • Return value on success (e.g., the new User and AdminInfo objects)
    • What errors it might throw
  • provisionNewAdmin(email) is scaffolded as the top-level orchestrator function with a mock and JSDoc that describes:

    • What it does (calls createAdminUser and createAdminDatabaseRecords in sequence)
    • That it should only be callable by an authenticated admin (note this as a TODO for auth middleware)
    • How it handles partial failure — document the strategy even if not yet implemented (e.g., "if database write fails after Cognito succeeds, we should delete the Cognito user and throw an error")
    • Return value and error cases
  • handleNewPasswordChallenge(username, tempPassword, newPassword) is scaffolded with a mock and JSDoc that describes:

    • What it does (calls Cognito RespondToAuthChallenge with NEW_PASSWORD_REQUIRED)
    • When it is triggered (frontend calls this after the new admin submits their new password on first login)
    • Parameters, return value (auth tokens), and error cases
  • resendAdminInvite(email) is scaffolded with a mock and JSDoc that describes:

    • What it does (re-triggers the Cognito temp password email via MessageAction: RESEND)
    • When it would be used (e.g., new admin never received the email or the temp password expired)
    • Parameters, return value, and error cases
  • All mocks return realistic-looking fake data mirroring actual Cognito and database response shapes. No real AWS or database calls should be made.

  • A module-level README block exists that covers:

    • The full flow in plain English
    • Which AWS SDK package will be used (@aws-sdk/client-cognito-identity-provider)
    • What environment variables will be needed (e.g., COGNITO_USER_POOL_ID, COGNITO_CLIENT_ID, AWS_REGION) — values can be TODO for now
    • The two database records that need to be created (User, AdminInfo) and how they relate to each other
    • A note on the partial failure problem and the intended strategy to handle it
  • No real AWS credentials, API calls, or database writes appear anywhere in this ticket.

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

Status

Changes Requested

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions