Below is a production-style Auth Service for your Local Marketplace Microservices Platform using:
- Node.js
- Express
- PostgreSQL
- Prisma ORM
- JWT Authentication
- Docker-ready structure
- Layered architecture (Controller β Service β Repository)
This structure is similar to what engineers use in production systems at companies like Stripe and Shopify.
π Auth Service Folder Structure
auth-service
β
βββ src
β βββ config
β β βββ db.js
β β
β βββ controllers
β β βββ auth.controller.js
β β
β βββ services
β β βββ auth.service.js
β β
β βββ repositories
β β βββ user.repository.js
β β
β βββ routes
β β βββ auth.routes.js
β β
β βββ middlewares
β β βββ auth.middleware.js
β β
β βββ utils
β β βββ hash.js
β β βββ jwt.js
β β
β βββ app.js
β βββ server.js
β
βββ prisma
β βββ schema.prisma
β βββ seed.js
β
βββ .env
βββ package.json
βββ Dockerfile
1οΈβ£ package.json
{
"name": "auth-service",
"version": "1.0.0",
"main": "src/server.js",
"scripts": {
"dev": "nodemon src/server.js",
"start": "node src/server.js",
"prisma": "prisma migrate dev"
},
"dependencies": {
"@prisma/client": "^5.0.0",
"bcryptjs": "^2.4.3",
"dotenv": "^16.0.0",
"express": "^4.18.2",
"jsonwebtoken": "^9.0.0"
},
"devDependencies": {
"nodemon": "^3.0.0",
"prisma": "^5.0.0"
}
}
2οΈβ£ .env
PORT=4000
DATABASE_URL="postgresql://postgres:password@localhost:5432/auth_db"
JWT_SECRET=supersecret
3οΈβ£ Prisma Schema
π prisma/schema.prisma
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id String @id @default(uuid())
name String
email String @unique
password String
role String @default("CUSTOMER")
createdAt DateTime @default(now())
}
Run:
npx prisma generate
npx prisma migrate dev --name init
4οΈβ£ DB Config
π src/config/db.js
const { PrismaClient } = require('@prisma/client')
const prisma = new PrismaClient()
module.exports = prisma
5οΈβ£ Hash Utility
π src/utils/hash.js
const bcrypt = require('bcryptjs')
exports.hashPassword = async (password) => {
return bcrypt.hash(password, 10)
}
exports.comparePassword = async (password, hash) => {
return bcrypt.compare(password, hash)
}
6οΈβ£ JWT Utility
π src/utils/jwt.js
const jwt = require('jsonwebtoken')
exports.generateToken = (payload) => {
return jwt.sign(payload, process.env.JWT_SECRET, {
expiresIn: "1d"
})
}
7οΈβ£ Repository Layer
π src/repositories/user.repository.js
const prisma = require('../config/db')
exports.createUser = (data) => {
return prisma.user.create({ data })
}
exports.findUserByEmail = (email) => {
return prisma.user.findUnique({
where: { email }
})
}
8οΈβ£ Service Layer
π src/services/auth.service.js
const userRepo = require('../repositories/user.repository')
const { hashPassword, comparePassword } = require('../utils/hash')
const { generateToken } = require('../utils/jwt')
exports.register = async (data) => {
const existingUser = await userRepo.findUserByEmail(data.email)
if (existingUser) {
throw new Error("User already exists")
}
const hashedPassword = await hashPassword(data.password)
const user = await userRepo.createUser({
...data,
password: hashedPassword
})
return user
}
exports.login = async ({ email, password }) => {
const user = await userRepo.findUserByEmail(email)
if (!user) {
throw new Error("Invalid credentials")
}
const valid = await comparePassword(password, user.password)
if (!valid) {
throw new Error("Invalid credentials")
}
const token = generateToken({
id: user.id,
email: user.email
})
return { token }
}
9οΈβ£ Controller
π src/controllers/auth.controller.js
const authService = require('../services/auth.service')
exports.register = async (req, res) => {
try {
const user = await authService.register(req.body)
res.status(201).json(user)
} catch (error) {
res.status(400).json({
message: error.message
})
}
}
exports.login = async (req, res) => {
try {
const result = await authService.login(req.body)
res.json(result)
} catch (error) {
res.status(401).json({
message: error.message
})
}
}
π Routes
π src/routes/auth.routes.js
const express = require('express')
const router = express.Router()
const authController = require('../controllers/auth.controller')
router.post('/register', authController.register)
router.post('/login', authController.login)
module.exports = router
1οΈβ£1οΈβ£ Express App
π src/app.js
const express = require('express')
const authRoutes = require('./routes/auth.routes')
const app = express()
app.use(express.json())
app.use('/auth', authRoutes)
module.exports = app
1οΈβ£2οΈβ£ Server
π src/server.js
require('dotenv').config()
const app = require('./app')
const PORT = process.env.PORT || 4000
app.listen(PORT, () => {
console.log(`Auth service running on port ${PORT}`)
})
1οΈβ£3οΈβ£ Dockerfile
FROM node:20
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 4000
CMD ["npm","start"]
π API Endpoints
Register User
POST /auth/register
Body
{
"name": "John",
"email": "john@example.com",
"password": "123456"
}
Login
POST /auth/login
Body
{
"email": "john@example.com",
"password": "123456"
}
β What Makes This Production-Ready
β Layered architecture
β Repository pattern
β Prisma ORM
β JWT authentication
β Microservice-ready
β Docker-ready
β Scalable structure
Top comments (0)