User Accounts#

Summary#

Boom needs a way for people to create and login to accounts. This allows data generated by each person to be associated with them and not mixed in with everyone else’s data. The user creates an account using an email and password. They receive a confirmation email and confirm their account, then are able to login with the email and password provided. Upon first sign-in, information such as Display Name, Native Language, and Target Langauge are collected.

Motivation#

If we have no user accounts, there’s no way to track data for each user.

With user accounts, there is potential for social interaction between users on the site.

Goals#

  • Users can create accounts

  • Users must activate account via email before using it

  • Users can reset password

Non-Goals#

Out of scope:

  • For now, social login is out of scope (too complex / too much setup)

Proposal#

  • Add a registration page asking for email, password, and password confirmation.

  • When handling form submission, create user in DB and send email with activation code link.

  • On the activation route, check the token for validity.

    • If valid, set account active and redirect.

    • Otherwise, display failure message.

  • User can login using email and password, receiving an auth token.

  • User can logout by deleting the auth token.

Design and implementation details#

User Story#

The user story is summarized by this flow chart.

flowchart TD %% Declarations %% ------------ %% Email Templates %% (none) %% Routes %% Connections %% ------------ HomePage -->|clicks login| LoginPage HomePage -->|clicks sign up| RegisterPage RegisterPage -->|submits invalid form| RegisterPage RegisterPage -->|submits valid form| SendEmail{RegisterRoute} SendEmail -->|user checks email| ActivationEmail ActivationEmail -->|user clicks link| CheckActivation{ActivateRoute} CheckActivation -->|invalid| ActivationFailedPage CheckActivation -->|success| GettingStartedPage LoginPage -->|error| LoginPage LoginPage -->|success| CheckAccount{LoginRoute} LoginPage -->|clicks forgot password| ForgotPasswordPage ForgotPasswordPage -->|submits| ForgotPasswordRoute{ForgotPasswordRoute} ForgotPasswordRoute --> ForgotPasswordEmail ForgotPasswordEmail --> ResetPasswordPage ResetPasswordPage --> ResetPasswordRoute{ResetPasswordRoute} ResetPasswordRoute --> LoginPage CheckAccount -->|Already setup| DashboardPage CheckAccount -->|New user| GettingStartedPage GettingStartedPage -->|success| OnboardUserRoute{OnboardUserRoute} OnboardUserRoute -->|success| DashboardPage DashboardPage -->|clicks logout| LogoutRoute{LogoutRoute} LogoutRoute -->|delete session| HomePage GetLanguagesRoute <-->|initial info| GettingStartedPage GetLanguagesRoute{GetLanguagesRoute} GetCurrentUserRoute <-->|request| AuthContext %% Styles %% ------------ %% Email Templates style ActivationEmail fill:LightGoldenRodYellow,color:black style ForgotPasswordEmail fill:LightGoldenRodYellow,color:black %% Routes style SendEmail fill:pink,color:black style CheckActivation fill:pink,color:black style CheckAccount fill:pink,color:black style GetLanguagesRoute fill:pink,color:black style GetUserRoute fill:pink,color:black style LogoutRoute fill:pink,color:black style OnboardUserRoute fill:pink,color:black style ForgotPasswordRoute fill:pink,color:black style ResetPasswordRoute fill:pink,color:black

Components#

None

Contexts#

Auth Context#

This context provides the current user object if the user is logged in. Otherwise, it returns undefined.

It gets this information by making a request to the Get Current User Route

Pages#

Activation Failed Page#

This page displays a simple message telling the user that their account activation failed.

Components

  • Activation message

  • Home button

Requests

None

Dashboard Page#

This page contains a welcome message for the now logged-in user.

Components

  • Welcome text

Requests

None

Forgot Password Page#

On this page, the user types in their email and hits submit to send a request to the Forgot Password Route. After sending the request, it displays a confirmation message and a link to the home page.

Components

  • Email field

  • Submit button

Requests

  • Forgot Password Route

Onboard User Page#

On the page, the user sets up their display name and first LanguagePair. These are saved to their profile upon creation.

Upon submission, this page will submit to the Onboard User route.

Components

  • Display name field

  • Native language multi-select

  • Target language multi-select

Requests

  • Get Languages Route

Home Page#

The home page will contain sign up and login buttons somewhere.

If the user is already logged in, it will redirect to the dashboard.

Components

  • Welcome message

  • Login button (included in Layout)

  • Sign-up button (included in Layout)

Effects

Redirect if user is already logged in.

Requests

None - it uses the Auth Context to get information about the logged-in user and determine whether to redirect.

Login Page#

On this page, the user types in their email and password and presses enter / clicks the submit button. On error, the error message from the server is displayed. On success:

Components

  • Email input

  • Password input

Requests

Register Page#

This page lets the user register. The fewest fields possible are included to get the user signed up as quickly as possible. Additional fields will be filled in after the user activates their account.

Components

  • Email field

  • Password field

  • Password Confirmation field

Requests

Reset Password Page#

This page shows a form for the user to reset their password, including these components:

Components

  • Old password field

  • New password field

  • New password confirmation field

  • Submit button

Requests

Email Templates#

Activation Email#

This email contains a link to the Activate Route with a token as a GET variable.

Forgot Password Email#

This password contains a special link that the user can click to open the ResetPasswordPage and reset their password.

Routes#

Activate Route#

This route handles the link that is in the user’s activation email. It checks the code provided and, if valid, sets the user’s account o active.

Environment Variables

None

Inputs

POST this JSON object:

Field

Type

Description

email

string

Email of user being activated

code

string

The activation code from the email. Corresponds to activationCode field in User.

Example:

{
  "email": "me@email.com",
  "code": "abcdefghijklmnopqrstuvwxyz1234567890"
}

Output

A Route Response object

Side Effects

  • If code matches, user is set to active.

Forgot Password Route#

This route sends an email to reset a user’s password.

Environment Variables

None

Inputs

POST this JSON object:

Field

Type

Description

email

string

email for which account to reset

Example:

{
  "email": "me@email.com"
}

Output

A Route Response object.

Side Effects

  • If the user exists in the DB:

    • The user’s activationCode field has been reset to some new random value.

    • A Forgot Password Email is sent to email with a link to ResetPasswordPage (containing the activationCode). Otherwise, it fails and returns an error.

Get Languages Route#

This route returns the list of currently supported languages from the Boom database.

Environment Variables

None

Inputs

None

Output

List of Language objects

Example:

[
  { "id": 1, ... },
  { "id": 2, ... } // Actual fields are omitted - see Language object below
]

Side Effects

None

Get Current User Route#

This route returns information about the currently logged-in user.

Environment Variables

None

Inputs

The only input is boom_auth, a signed JWT provided to the user as the output of the Login Route.

  • boom_auth: cookie containing JWT auth token

  • boom_auth: Authorization header containing JWT auth token (for mobile clients)

Example header:

Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Output

The User object, with the following fields REMOVED for privacy/security purposes:

  • id

  • email

  • passwordHash

  • passwordSalt

Example:

{
  "id": 1,
  ... // Further fields omitted, see User design
}

Side Effects

None

Login Route#

This route logs the user in if the user exists and the provided password matches the passwordHash field in the User object. Note that the boom_auth token is only provided in the output for mobile devices. Browsers should not store this credential using localStorage, which is not secure.

Environment Variables

None

Inputs

POST this JSON object:

Field

Type

Description

email

string

email for account

password

string

password for account

Example:

{
  "email": "me@email.com",
  "password": "N0tForYourEy3s!!!!!!"
}

Output

JSON object:

Field

Type

Description

status

success or error

Status of request

message

string

Message describing error or “Success”

boom_auth

string?

The authorization JWT to use for making authenticated requests as the logged-in user or undefined on failure.

Example:

{
  "status": "success",
  "message": "Success",
  "boom_auth": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
}

Side Effects

  • HttpOnly Secure Cookie boom_auth is set.

Logout Route#

This route logs the user out by unsetting the boom_auth cookie. The client-side is expected to delete any local auth credentials (for mobile).

Environment Variables

None

Inputs

None

Output

A Route Response object.

Side Effects

The boom_auth cookie is unset.

Onboard User Route#

This route sets basic info for the user.

Environment Variables

None

Inputs

POST this JSON object:

Field

Type

Description

name

string

Display name for user

nativeId

int

ID of Language selected as Native

targetId

int

ID of Language selected to learn

Example:

{
  "name": "George Language",
  "nativeId": 1,
  "targetId": 2
}

Output

A Route Response object.

Side Effects

  • Set the User’s name field

  • Created a LanguagePair with the given native/target languages and set it to active.

Register Route#

This route creates a new user object and sends an activation email.

Environment Variables

None

Inputs

POST this JSON object:

Field

Type

Description

email

string

User’s email

password

string

User’s password

passwordConfirmation

string

User’s password confirmation

Example:

{
  "email": "me@email.com",
  "password": "N0tForYourEy3s!!!!!!",
  "passwordConfirmation": "N0tForYourEy3s!!!!!!"
}

Output

A Route Response object.

Side Effects

  • New User object has been generated.

  • User’s activationCode field is populated with a random string.

  • An Activation Email has been sent to the user-provided email.

Reset Password Route#

This route changes the user’s password to the new one they provide.

Environment Variables

None

Inputs

POST this JSON object:

Field

Type

Description

email

string

User’s email

code

string

Activation code

password

string

New password

passwordConfirmation

string

New password confirmation

Example:

{
  "email": "me@email.com",
  "code": "abcdefghijklmnopqrstuvwxyz1234567890",
  "password": "N0tForYourEy3s!!!!!!",
  "passwordConfirmation": "N0tForYourEy3s!!!!!!"
}

Output

A Route Response object.

Side Effects

  • User’s passwordHash and passwordSalt have been updated to match the new password.

Models#

These are data structures that are not stored in the database.

Route Response#

Generic response object to provide info on status/errors. Any output messages should be understandable enough to be displayed to the user.

Field

Type

Description

status

‘success’ or ‘error’

whether the request succeeded

message

string

User-facing message describing error or “Success”

Example:

{
  "status": "success",
  "message": "Success"
}

DB Design#

Only the basic tables required for user accounts and language selection will be included in this design doc.

User#

User is implemented using a Prisma schema.

Field

Type

Description

id

Int

Auto-incremented unique id

created

DateTime

Time of registration

name

String?

Display name

email

String

Unique email

passwordHash

String

Hashed password

passwordSalt

String

Salt for password

activationCode

String

Randomly generated string for email activation

activeLanguagePairId

number?

The currently selected language pair

Language Pair#

Field

Type

Description

id

Int

Auto-incremented unique id

user

User

User who is learning this LanguagePair

native

Language

Language you already know

target

Language

Language you are learning

Language#

Field

Type

Description

id

Int

Auto-incremented unique id

name

String

Language name (English)

code

String

Three letter ISO code for the language

Alternative Solutions#

Make Boom a local-only application. It’s offline all the time, or a desktop app, and there is no way for users to interact. Kinda lame.