A Next.js application to provide user authentication and user management within the new Bichard7 architecture.
First, install the requirements:
npm i --dev
npm run install:assetsThen, run the development server:
npm run devAlternatively, an optimized production build of the application can be built and then served with:
$ npm run build
$ npm run startAWS CodeBuild automatically builds the user-service Docker image and pushes into the AWS container repository (ECR). The image is built upon the nodejs image from our ECR repo.
In order to build the user-service image locally, you'll need to have installed and configured the AWS CLI and aws-vault, so that you can authenticate with AWS and pull down the nodejs image from ECR.
You can then run the build process via aws-vault:
$ aws-vault exec bichard7-sandbox-shared -- make buildIn order to run the user-service, you'll also need to ensure the Bichard PostgreSQL database is running locally (see Running the database below).
Once you've built the Docker image (see Building above) and have the Bichard PostgreSQL database running, you run the Docker image as usual:
$ docker run -p 3443:443 user-service
# Or, a shortcut to run the above:
$ make runEither of these commands will expose the service at https://localhost:3443/.
To spin up a local instance of the database, you can use the run-pg make target in the main bichard repo:
$ cd /path/to/bichard7-next
$ make run-pgThe application makes use of the following environment variables to permit configuration:
| Variable | Default | Description |
|---|---|---|
$AUDIT_LOGGING_URL |
"/audit-logging" |
The URL to redirect to audit logging |
$BASE_URL |
"http://localhost:3000" |
The URL that the user-service is being served from. Used for generating email links. |
$BICHARD_REDIRECT_URL |
"/bichard-ui/InitialRefreshList" |
The URL to redirect to with a token as a GET parameter when authentication is successful |
$COOKIE_SECRET |
"OliverTwist" |
The secret to use for signing the cookies |
$COOKIES_SECURE |
true |
Whether to enable the Secure cookie flag (prevents cookies from being sent in non-https requests) |
$CSRF_COOKIE_SECRET |
"OliverTwist2" |
The secret to use for signing the CSRF cookie token |
$CSRF_FORM_SECRET |
"OliverTwist1" |
The secret to use for signing the CSRF form token |
$CSRF_TOKEN_MAX_AGE |
600 |
The maximum validity of CSRF tokens in seconds |
$DB_HOST |
"localhost" |
The hostname of the database server |
$DB_USER |
"bichard" |
The username to use when connecting to the database |
$DB_PASSWORD |
"password" |
The password to use when connecting to the database |
$DB_DATABASE |
"bichard" |
The name of the database containing the user information |
$DB_PORT |
5432 |
The port number to connect to the database on |
$DB_SSL |
false |
Whether to use SSL when connecting to the database |
$EMAIL_FROM |
"bichard@cjse.org" |
The email address to send emails from |
$EMAIL_VERIFICATION_EXPIRES_IN |
30 |
The number of minutes after which the email verification links will expire |
$INCORRECT_DELAY |
10 |
The amount of time (in seconds) to wait between successive login attemps for the same user |
$REMEMBER_EMAIL_MAX_AGE |
1440 |
The maximum validity of cookie for remembering user's email address in minutes |
$SMTP_HOST |
"console" |
The hostname of the SMTP server. If set to console, emails will be printed to the console instead. |
$SMTP_USER |
"bichard" |
The username to use when connecting to the SMTP server |
$SMTP_PASSWORD |
"password" |
The password to use when connecting to the SMTP server |
$SMTP_PORT |
587 |
The port number to connect to the SMTP server on |
$SMTP_TLS |
false |
Whether to use TLS when connecting to the SMTP server |
$TOKEN_EXPIRES_IN |
"60 seconds" |
The amount of time the tokens should be valid for after issuing |
$TOKEN_ISSUER |
"Bichard" |
The string to use as the token issuer (iss) |
$TOKEN_SECRET |
"OliverTwist" |
The HMAC secret to use for signing the tokens |
These can be passed through to the docker container with the -e flag, for example:
$ docker run \
-p 3443:443 \
-e TOKEN_SECRET="SECRET" \
-e TOKEN_EXPIRES_IN="10 seconds" \
user-serviceThe user-service requires a connection to the Bichard PostgreSQL database. The defaults for the database connection parameters are set up to work when the user-service is running locally (see Running the app locally below).
However, this means that if you're running the user-service inside Docker, you'll need to pass through the $DB_HOST environment variable to configure the database connection:
$ cd /path/to/bichard7-next-user-service
$ docker run \
-p 3443:443 \
-e DB_HOST=172.17.0.1 \
user-service
# Or, a shortcut to run the above:
$ make runTo customise other database connection parameters, see the $DB_* parameters in the table above. The other database configuration defaults should be sufficient for connceting to a local instance of the database.
The Docker image is configured to run NGINX in front of the Next.js application, to allow us to do SSL termination.
A self-signed certificate is generated and included in the Docker image, but this can be overridden by mounting a different certificate and key at /certs/server.{crt,key}:
$ docker run \
-p 3443:443 \
-v /path/to/your/certificates:/certs \
user-serviceSee how build core and common here.
| Directory | Purpose |
|---|---|
| components | Generic reusable components which can be used anywhere within our application |
| pages | Each top-level next.js page which can be visited |
| types | Shared types for typescripting |
| middleware | Code run by our next.js while rendering our pages |
| useCases | Data access and transformations |
There are a number of different types of test that form part of the user-service testing suite:
-
Unit tests: tests for validating the logic of individual functions and components of the service, written using Jest.
$ npm run test:unit
-
Integration tests: tests for validating the higher-level behaviour, or use cases, of the service. These are again written using Jest, and require a database connection.
$ npm run test:integration
-
UI tests: tests that drive the service interface within a web browser using Cypress, to validate the interface and interactions from a user perspective. Also requires a database connection.
# Build a production copy of the app and run all of the UI tests against it $ npm run test:ui # Build a production copy of the app and run one or more of the UI tests against it $ npm run test:ui cypress/e2e/login.cy.js $ npm run test:ui login.cy.js users.cy.js # Run the UI tests against a version of the app that is already running $ npm run cypress:run # Open the cypress UI for better test debugging $ npm run cypress:open
-
Docker image tests: tests to validate the user-service docker container, using Goss. Requires
gossanddgossto be installed (see instructions in their READMEs, here and here).# Build the user-service docker container $ aws-vault exec bichard7-sandbox-shared -- make build # Run the goss tests $ make goss
Snapshot testing of React components is implemented as part of the unit tests for the app. Snapshot testing is where the markup generated by a React component is compared to a static snapshot of the expected markup. It's a very useful tool for validating that your UI does not change unexpectedly.
When you make changes in a React component that results in changes to the DOM nodes, the following might have happened:
- Changes you made have changed the behavior of the component that you didn't expect: Update the code until test passes
- Changes you made have changed the behavior of the component that is as expected: Update the snapshot
To update snapshots run the following command:
npm run test:unit:updateCheck the snapshot before pushing it to the repository to ensure that the generated markup is as you expect.
For more details, check Jest documentation and React testing library.
This project utilises ESLint and Prettier to code linting and auto-formatting. They are run as part of a pre-commit git hook, as well as in the CI.
To run them manually without making any auto-corrections, you can use:
$ npm run lintAnd similarly, to run them and make any possible auto-corrections, use:
$ npm run lint:fix