This is part 3 of Developing Instagram Clone series, other parts are linked below
In Monolithic applications, a user provides username and password, the security module validates user credentials and create a session for the user. A session Id is returned to the client and the client stores the session Id in cookies and send it with each request as an identifier for the user.
This approach making the service statefull has an impact on the scalability because a session should be stored for each user, the more users you’ll have the more memory you’ll need.
Also if you divide the app into multiple services, you’ll need to find a way to share the session between services.
In the token based authentication, authentication service generates the token and send it to the client but it doesn’t store it. The client has to send the token with every request in the Authorization header. This token holds the user’s identity information.
Here, I’m using JWT token or Json Web Token, from now on when I will refer to JWT token as simply token.
Since the token holds user information, it is encoded and encrypted.
A JWT token would look like below
eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZGFtIiwiYXV0aG9yaXRpZXMiOlsiVVNFUiJdLCJpYXQiOjE1OTE2NDQ2NjMsImV4cCI6MTU5MTczMTA2M30.9pR6sK-kJmG6Zm7aWVqNrQy9MZ8ponYKz3Wc3nfKU7MD4oXkifjAEgkB6Uc-Dswp3yjWIiNLrpMd7S9SZ1_D_A
If you notice there are 3 sections in the token separated by dot “.”, these sections are Header.Payload.Signature
1. Header: contains metadata like type of the token and the hashing algorithm that is used in Signature section.
{
"typ": "JWT",
"alg": "HS512"
}
2. Payload: contains user information and token expiration date.
{
"sub": "adam",
"authorities": [
"USER"
],
"iat": 1591644663,
"exp": 1591731063
}
3. Signature: contains the signature of the token creator, to make sure that the token isn’t changed.
HMACSHA512(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
Secret
)
Let’s dive deep into code.
Clone the Auth service from GitHub and let’s walk through it.
Auth service is using MongoDB as the data store for its users, because of scalability, MongoDB has a better performance since it doesn’t have to deal with the overhead of relational databases and it gives a flexibility to evolve the schema as business needs.
Auth service uses Apache Kafka as a way to notify other services whenever user is created, updated or deleted. We can discuss all the “whys” (why Kafka?, why asynchronous? or why notifying other services?) in the comments.
I will be using docker and docker compose for dependencies like MongoDB, Kafka, neo4j, … etc.
If you don’t know what docker and docker compose are, for now, just think of it as a way to have MongoDB and Kafka on your local machine without having to install them on your machine and follow the below instructions.
The file should look like below
version: '3'
services:
kafka:
image: wurstmeister/kafka
container_name: "kafka"
ports:
- "9092:9092"
environment:
- KAFKA_ADVERTISED_HOST_NAME=127.0.0.1
- KAFKA_ADVERTISED_PORT=9092
- KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181
depends_on:
- zookeeper
zookeeper:
image: wurstmeister/zookeeper
ports:
- "2181:2181"
environment:
- KAFKA_ADVERTISED_HOST_NAME=zookeeper
mongodb:
image: mongo:latest
container_name: "mongodb"
environment:
- MONGO_LOG_DIR=/dev/null
ports:
- 27017:27017
volumes:
- /home/amr/instaMongo:/data/db
# neo4j:
# image: neo4j:latest
# ports:
# - "7474:7474"
# - "7687:7687"
# cassandra:
# image: cassandra:latest
# ports:
# - "7000:7000"
# - "9042:9042"
# volumes:
# - /home/amr/instaCassandra:/var/lib/cassandra
#microservices #jwt #security #cloud #developer