Prakirth Govardhanam
Posted on May 24, 2024
Background
I am trying to learn MERN stack in 150 Days, about which I posted a while ago. In this series posts, I will be sharing What and How I have been learning.
I am open to feedback to make this post better for readability/content quality.
DAY 17/150 ⏳
- Today, I have brief summaries of concepts which were either unclear/unknown to me, until now. 🏄
- In the below sections, I share the challenges I faced with Context, Reason and Solution wherever relevant.
Challenge 1 - Backend Testing fundamentals
-
Context : Backend-testing using
node:test
,node:assert
andsupertest
. - Reason : Completely new topic and zero-experience from previous projects
-
Solution :
- After every topic in each section of Part 4, practice tests for 'Notes App' in a different context. For example on the current project in Part 4 exercises, 'Blogs App'
- Seek coding assistance from GitHub CoPilot
- Read through example tests from documentations
Challenge 2 - HTTP status codes
- Context : HTTP Methods use similar status codes
-
Reason :
HTTP Method Response Status Codes GET 200, 304, 400, 404, 500 POST 200, 201, 400, 403, 404, 500 PUT 200, 204, 400, 404, 409, 500 PATCH 200, 204, 400, 404, 409, 500 DELETE 200, 202, 204, 400, 404, 500 -
Common status codes happen because HTTP method can have multiple response status codes because the outcome of a request can vary based on different factors.
-
200 OK
: The request has succeeded. -
400 Bad Request
: The server could not understand the request due to invalid syntax. -
404 Not Found
: The server could not find the requested resource. -
500 Internal Server Error
: The server encountered an unexpected condition which prevented it from fulfilling the request.
-
Challenge 3 - Data re-initialization in test DB using beforeEach
-
Context :
- For Testing purposes, Test-database needs to be re-initialized before each test for executing assertions successfully.
- However, due to differences in the order of execution of the
Promise
the data can be initialized in different ways.
-
Reason : Depends on the sequence preferences, if any, of execution of
Promise
s - Solution :
-
Using
for
loop for control over execution order ofPromise
beforeEach(async() => { // executed in no specific order for(let blog of helper.initialBlogs){ let blogObject = new Blog(blog) await blogObject.save() } }) // tests to verify HTTP methods ...
-
using
Promise.all
method to allow the completion of everyPromise
in the registered order
beforeEach(async() => { // executed in specific order promises registred await Promise.all(helper.initialBlogs.map(async (blog) => { let blogObject = new Blog(blog) blogObject.save() })) }) // tests to verify HTTP methods ...
-
most ideal method, using
mongoose
built-in methods forinsert
anddelete
beforeEach(async() => { await Blog.deleteMany({}) await Blog.insertMany(helper.initialBlogs) }) // tests to verify HTTP methods ...
Challenge 4 - Password Hashing fundamentals
- Context : Hashing passwords (manually) using external libraries
- Reason : Obviously, user data such as passwords must be encrypted, hence an enhanced level of encryption ensures user security
-
Solution : In the current context (FullStackOpen-core-part4), for user administration in saving blog posts, we are using
bcrypt
to ensure password hashing through Salt Rounds, as simplified below.- Purpose : Salt rounds are used to 'thwart brute force attacks' by making the hashing process slower.
-
How It Works :
- Number of salt rounds is the exponent in the calculation of how many times the hashing algorithm is executed.
- More rounds = more hashing iterations,
- Brute force attacks slowed down and more secure.
- Example : If you choose 10 salt rounds, the algorithm will run 2^10 (or 1024) times.
-
Balance between Security and Performance :
- Higher salt rounds increase security but also make the hashing process take longer.
- The cost of increasing rounds on 2 GHz core :
rounds=8 : ~40 hashes/sec rounds=9 : ~20 hashes/sec rounds=10: ~10 hashes/sec rounds=11: ~5 hashes/sec rounds=12: 2-3 hashes/sec rounds=13: ~1 sec/hash rounds=14: ~1.5 sec/hash rounds=15: ~3 sec/hash rounds=25: ~1 hour/hash rounds=31: 2-3 days/hash
Challenge 5 - Process Flow between Backend-Database to Implement new Feature
-
Context :
- In MERN, if every new concept is implemented from the granular level, unlike Django, the sequence of operations to know are essential.
- In current context, we use
MongoDB-mongoose
for establishing backend-database communications - If a new table/
collection
is introduced to implement a new feature, such as user administration, then the sequence of actions for an efficient process flow is as shown below.
Challenge 6 - Generating JSON Web Token
- Context : What is included in 'process.env.SECRET'?
-
Reason : For user authentication, a
jsonwebtoken
(JWT
) must be generated -
Solution :
- Any string, preferably auto-generated as a cryptic string
- Using
node
built-in library for auto-generating a cryptic string as follows:
const crypto = require('crypto') crypto.randomBytes(32).toString('hex') // SECRET
-
NEVER save it in the source code. Generate in the terminal. Save it in
.env
Challenge 7 - Authorization Header and Authentication Scheme fundamentals
- Context : How to retrieve the 'Authentication Header' value for implementing tests with backend API using Postman/REST Client ?
-
Reason : To authenticate the user when a
POST
request is generated -
Solution :
-
HTTP request
hasAuthorization
headers in the format -<auth-schemes> <auth-parameters>
- There are multiple
<auth-schemes>
(Authentication Schemes) available in aHTTP request
Authorization
header. - Most common ones are -
Basic
,Bearer
,Digest
Feature Basic
Bearer
*Digest
SECURITY Credentials sent as base64
encoded (plain text)Credentials tokenized on server-side and stored on client side. Can be set to expire. Password saved on server as plain-text/reversibly-encrypted format for verification with hashed-version. USAGE Simple, credentials sent with each request Simple & safe, token sent with each request Complex due to hashing process STATE Stateful, since credentials required for each request Stateless, request contains credentials-encrypted token to authenticate user for each request Stateful, random new hashed value different for each request API Suitability Only simple authentication, Not suitable for modern APIs Suitable, specifically for APIs with JWT
s and Single Sign-On (SSO)Not Suitable, due to server-side storage - Based on the project (Reading list - Blogs App), the
Bearer <auth-scheme>
would be suitable for our User Authentication considering its beginner-friendly secure state of tokenizing user access.
-
Until next time! ✍️
Live Long and Prosper 🖖
Posted on May 24, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.