DEV Community

Aisalkyn Aidarova
Aisalkyn Aidarova

Posted on

LAB 3 — JWT + Secrets + CI/CD + Newman (PRODUCTION LEVEL)

🔥 1. ARCHITECTURE (REAL FLOW)

Client → /login → JWT token
       → /protected → validate token
       → Newman tests → CI/CD validation
Enter fullscreen mode Exit fullscreen mode

🔥 2. PROJECT STRUCTURE

jwt-newman-lab/
├── app/
│   └── server.js
├── Dockerfile
├── package.json
├── collection.json
├── environment.json
├── .github/
│   └── workflows/
│       └── api-test.yml
Enter fullscreen mode Exit fullscreen mode

🔥 3. STEP 1 — SECURE API WITH JWT

📄 app/server.js

const express = require("express");
const jwt = require("jsonwebtoken");

const app = express();
app.use(express.json());

// 🔒 Secret from ENV (IMPORTANT)
const SECRET = process.env.JWT_SECRET || "dev-secret";

// LOGIN
app.post("/login", (req, res) => {
    const { username } = req.body;

    if (!username) {
        return res.status(400).json({ error: "Username required" });
    }

    const token = jwt.sign({ username }, SECRET, { expiresIn: "1h" });

    res.json({ token });
});

// PROTECTED ROUTE
app.get("/protected", (req, res) => {
    const auth = req.headers["authorization"];

    if (!auth) {
        return res.status(401).json({ error: "No token" });
    }

    const token = auth.split(" ")[1];

    try {
        const decoded = jwt.verify(token, SECRET);
        res.json({ message: "Access granted", user: decoded.username });
    } catch (err) {
        res.status(403).json({ error: "Invalid token" });
    }
});

app.listen(3000, () => {
    console.log("JWT API running on 3000");
});
Enter fullscreen mode Exit fullscreen mode

🔥 4. STEP 2 — PACKAGE.JSON

{
  "name": "jwt-api",
  "version": "1.0.0",
  "main": "app/server.js",
  "scripts": {
    "start": "node app/server.js"
  },
  "dependencies": {
    "express": "^4.18.2",
    "jsonwebtoken": "^9.0.0"
  }
}
Enter fullscreen mode Exit fullscreen mode

🔥 5. STEP 3 — DOCKERFILE

FROM node:18

WORKDIR /app

COPY package.json .

RUN npm install

COPY . .

EXPOSE 3000

CMD ["npm", "start"]
Enter fullscreen mode Exit fullscreen mode

🔥 6. STEP 4 — POSTMAN COLLECTION (IMPORTANT)

Request 1 — LOGIN

POST {{base_url}}/login
Enter fullscreen mode Exit fullscreen mode

Body:

{
  "username": "aisalkyn"
}
Enter fullscreen mode Exit fullscreen mode

Tests (SAVE TOKEN)

let json = pm.response.json();
pm.environment.set("token", json.token);

pm.test("Token received", function () {
    pm.expect(json.token).to.exist;
});
Enter fullscreen mode Exit fullscreen mode

Request 2 — PROTECTED

GET {{base_url}}/protected
Enter fullscreen mode Exit fullscreen mode

Headers:

Authorization: Bearer {{token}}
Enter fullscreen mode Exit fullscreen mode

Tests

pm.test("Access granted", function () {
    pm.response.to.have.status(200);
});
Enter fullscreen mode Exit fullscreen mode

🔥 7. STEP 5 — ENVIRONMENT FILE

{
  "name": "local",
  "values": [
    { "key": "base_url", "value": "http://localhost:3000" },
    { "key": "token", "value": "" }
  ]
}
Enter fullscreen mode Exit fullscreen mode

🔥 8. STEP 6 — RUN LOCALLY

docker build -t jwt-api .
docker run -d -p 3000:3000 -e JWT_SECRET=mysecret jwt-api

newman run collection.json -e environment.json
Enter fullscreen mode Exit fullscreen mode

🔥 9. STEP 7 — GITHUB ACTIONS (REAL CI/CD)

📄 .github/workflows/api-test.yml

name: JWT API Test

on:
  push:
    branches: [ main ]

jobs:
  test-api:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Build & Run API
        run: |
          docker build -t jwt-api .
          docker run -d -p 3000:3000 -e JWT_SECRET=${{ secrets.JWT_SECRET }} jwt-api

      - name: Wait for API
        run: sleep 10

      - name: Install Newman
        run: npm install -g newman

      - name: Run Tests
        run: newman run collection.json -e environment.json
Enter fullscreen mode Exit fullscreen mode

🔥 10. 🔐 SECRETS (VERY IMPORTANT)

In GitHub:

Settings → Secrets → Actions
Enter fullscreen mode Exit fullscreen mode

Add:

JWT_SECRET = mysupersecret
Enter fullscreen mode Exit fullscreen mode

🔥 11. WHY THIS IS REAL DEVOPS

You are doing:

  • Secure API (JWT)
  • No hardcoding secrets
  • Pipeline validation
  • Auth testing
  • Fail-safe deployment

🔥 12. COMMON FAILURES (INTERVIEW GOLD)

❌ Token not saved

Newman fails because:

{{token}} is empty
Enter fullscreen mode Exit fullscreen mode

❌ Wrong secret

Token created ≠ token verified


❌ Missing Authorization header

401 Unauthorized
Enter fullscreen mode Exit fullscreen mode

❌ Pipeline too fast

API not ready → tests fail


❌ Secrets not configured

GitHub:

JWT_SECRET undefined
Enter fullscreen mode Exit fullscreen mode

🔥 13. WHAT YOU SAY IN INTERVIEW

Strong answer:

"We test authenticated APIs using Postman and Newman. Token is dynamically generated and stored during test execution. In CI/CD, secrets are injected securely using GitHub Actions. This ensures secure and automated API validation before release."


🔥 14. WHAT YOU REPORT TO MANAGER

Example:

  • Auth Test: PASS
  • Protected Endpoint: PASS
  • Token Validation: PASS
  • Security: JWT verified
  • Failures: 0

🔥 15. REAL PRODUCTION PIPELINE

Code Push
   ↓
Build Docker Image
   ↓
Deploy (ECS / Kubernetes)
   ↓
Run Newman (Auth + API tests)
   ↓
IF FAIL → rollback
IF PASS → production
Enter fullscreen mode Exit fullscreen mode

-

Top comments (0)