User management microservice (Part 1): Defining domain model and REST API
In this first part we define the requirements against the application, its initial domain model and that REST API which its front-end will be using. We start off by defining the user stories for registering and managing users.
When designing a new system, it’s worth thinking about that result users are expecting to achieve with it. Below you can found a list of those very basic features a user registration system should have.
- As a user, I want to register, so that I can get access to content which requires registration
- As a user, I want to confirm my email address after registration
- As a user, I want to login and log out
- As a user, I want to change my password
- As a user, I want to change my email address
- As a user, I want to be able to reset my password, so that I can login after I lost my password
- As a user, I want to update my profile, so that I can provide my correct contact data
- As a user, I want to close my account, so that I can close my relationship with that service I signed up for
- As an admin, I want to manage (create/delete/update) users manually, so that staff members wouldn’t have to go over the registration process
- As an admin, I want to create users manually, so that staff members wouldn’t have to go over the registration process
- As an admin, I want to list all users, even those once who closed their account
- As an admin, I want to be able to see users’ activity (login, logout, password reset, confirmation, profile update), so that I can comply with external audit requirements
Let’s take a look at the workflows what system is going to support. First of all, people should be able to register and login, these are fairly obvious functionalities.
However, we need to be cautious when it comes to the handling of confirmation tokens. As they can be used to perform privileged actions, we use disposable random tokens to handle password reset and email confirmation.
When a new token got generated by the user for whatever reason all the previous ones are invalidated. When some remembers their password, formerly issued and valid password reset tokens must be made expired.
Don’t want to miss a thing?
If you like technology as much as I do, you might consider signing up for a few of my newsletters.There are some problems with the configuration of the opt-in shortcode
User stories usually don’t define non-functional requirements, such as security, development principles, technology stack, etc. So let’s list them here separately.
- The domain model is implemented in pure Java using Domain-driven design principles and its independent of the underlying technology stack to be used
- When users log in, a JWT token is generated for them, which is valid for 24 hours. By providing this token for subsequent requests they can perform operation which require authentication
- Password reset tokens are valid for 10 minutes and email address confirmation tokens for a day
- Passwords are encrypted with a cryptographically strong algorithm (Bcrypt) with per-user salt
- A RESTful API is provided for interacting with the user registration service
- The application will have a modular design in order to be able to provide separate deployment artifacts for various scenarios (eg. a 2.5 servlet compliant WAR for Google App Engine and a Spring Boot-based, self contained, executable JAR for other use cases)
- Entity identifiers are generated in a database agnostic way, that is, no database specific mechanism (AUTO_INCREMENT or sequences) will be used to get next ID values. The solution will be similar how Instagram genetes IDs.
For the first round implementation we’ve got only three entities, that is, User, ConfirmationToken and UserEvent.
Accessing most of endpoints below require authentication, otherwise they return an UNAUTHORIZED status code. They also return a client error (FORBIDDEN) if the user tries to query an entity which belong to some other user, unless he has administrative privileges. If the specified entity doesn’t exist the called endpoint returns NOT_FOUND.
Creating a session (POST /sessions) and registering a new user (POST /users) are public and they don’t require authentication.
Returns the details of the given session or NOT_FOUND if there is no such session with the given ID or if that’s already expired.
Create a new session provided that the specified email and password pair belongs to a valid user.
Deletes the given session (logout).
Finds a user with the given ID.
List all users in the system
Registers a new user
Deletes the given user.
Updates the profile of a given user.
Uses the token of the given user and performs the action related to the token’s type.