13  Lab: Access Control Setup

Components and Circuit Design for IoT Security

authentication
auth
lab
basic

13.1 Start With the Story

Imagine standing beside a prototype door controller on a workbench. One button chooses a test credential, another asks for access, and the LEDs and buzzer have to make the decision obvious before any cloud dashboard is available. This setup chapter is about building that small, inspectable loop: components, GPIO pins, access levels, credential records, lockout timing, and audit state.

The IoT reason is practical. A field device often has to explain “granted”, “denied”, “locked”, or “admin mode” through local hardware while still leaving a software record. Start simple: wire the indicators safely, confirm one credential path, and only then treat the code as a security control instead of just a demo sketch.

Chapter Roadmap

This lab turns a door-controller sketch into a checked access-control setup:

  1. First identify the ESP32 components, pin assignments, and safe wiring paths.
  2. Then organize the credential records, access levels, lockout policy, and zone rules.
  3. Next connect security state, audit events, and constant-time comparison to the local feedback loop.
  4. Finally compare password-verifier choices, lab shortcuts, quizzes, and production caveats before the implementation chapter.

Checkpoints recap the setup decisions you have just made. Deep-dive sections are useful for security review, but you can skim them on a first pass through the lab.

13.2 Learning Objectives

By completing this lab setup, you will be able to:

  • Identify the hardware components needed for an IoT access control system
  • Wire the circuit correctly for LEDs, buzzer, and buttons
  • Understand the code structure for authentication and authorization
  • Configure access levels for different user roles
  • Implement security features like account lockout and constant-time comparison

Access control determines what each user or device is allowed to do in an IoT system. Think of a hospital where doctors, nurses, and visitors each have different access levels – doctors can prescribe medication, nurses can administer it, and visitors can only visit patients. Similarly, IoT access control ensures each device and user can only perform actions appropriate to their role.

Prerequisites

Before starting this lab, you should:


Concept Relationships
Concept Related To Relationship Type
Access Levels RBAC, Hierarchy Implements - Guest < User < Admin follows role-based access control
Credential Database Authentication, Storage Stores - User identities and access levels for verification
Security State Session Management Tracks - Failed attempts, lockout status, current authentication state
Constant-Time Compare Side-Channel Defense Prevents - Timing attacks that leak password information via execution time
Audit Log Compliance, Forensics Records - All access events for security investigation and regulatory requirements
Debouncing Hardware Reliability Ensures - Single button press registers once, preventing double-authentication
See Also

Foundation Concepts:

Related Labs:

Security Foundations:


13.3 Components

Component Purpose Optional Simulator Element
ESP32 DevKit Main controller with access control logic esp32:devkit-v1
Green LED Access granted indicator led:green
Red LED Access denied indicator led:red
Yellow LED System status / rate limit warning led:yellow
Blue LED Admin mode indicator led:blue
Buzzer Audio feedback for access events buzzer
Push Button 1 Simulate RFID card tap (cycle through cards) button
Push Button 2 Request access with current card button
Resistors (4x 220 ohm) Current limiting for LEDs resistor
Try It: GPIO Pin Assignment Explorer

Explore how each ESP32 GPIO pin connects to a specific component. Select a component to see its pin, purpose, and wiring details.


13.4 Circuit Build Workspace

Use this local workspace to plan and verify the access-control circuit before writing code. An external simulator such as Wokwi, or a real ESP32 breadboard, can still be used after this check, but the lesson does not depend on a third-party embedded iframe.

Try It: Circuit Build Checklist

Choose a build step and check what you should connect, why it matters, and what a safe result looks like.


13.5 Circuit Connections

Before entering the code, wire the circuit in your optional simulator or on the ESP32 breadboard:

ESP32 Pin Connections:
---------------------
GPIO 2  --> Green LED (+)  --> 220 ohm Resistor --> GND  (Access Granted)
GPIO 4  --> Red LED (+)    --> 220 ohm Resistor --> GND  (Access Denied)
GPIO 5  --> Yellow LED (+) --> 220 ohm Resistor --> GND  (System Status)
GPIO 18 --> Blue LED (+)   --> 220 ohm Resistor --> GND  (Admin Mode)
GPIO 19 --> Buzzer (+)     --> GND
GPIO 15 --> Button 1       --> GND  (Select RFID Card)
GPIO 16 --> Button 2       --> GND  (Request Access)
Circuit wiring diagram for an ESP32-based IoT access control system showing GPIO pin connections to four colored LEDs (green for access granted, red for access denied, yellow for system status, blue for admin mode) through 220 ohm current-limiting resistors, a buzzer for audio feedback, and two push buttons for RFID card selection and access requests
Figure 13.1: Circuit diagram showing ESP32 connections to LEDs, buzzer, and buttons

Shield ShellyCheckpoint: Hardware Feedback Loop

You now know how the physical setup explains access decisions:

  • Four LEDs, one buzzer, two buttons, and four 220 ohm resistors give the ESP32 separate visual, audio, and input paths.
  • The lab uses 7 of the ESP32 DevKit’s 34 available GPIO pins, leaving room for later sensors or lock hardware.
  • The all-on LED estimate is about 85mA, so the setup stays within the USB-powered lab envelope.

With the wiring mapped, the next question is what software state those signals should represent.

13.6 Code Structure Overview

The access control system is organized into several key sections:

13.6.1 1. Pin Definitions and Access Levels

/*
 * Secure IoT Access Control System
 * Demonstrates: RFID-style authentication, role-based access control,
 *               lockout policies, and comprehensive audit logging
 *
 * Security Concepts Implemented:
 * 1. Token-based authentication (simulating RFID cards)
 * 2. Role-based access control (RBAC) with three access levels
 * 3. Account lockout after failed attempts
 * 4. Comprehensive audit logging with timestamps
 * 5. Visual and audio feedback for security events
 * 6. Constant-time comparison to prevent timing attacks
 */

#include <Arduino.h>

// ============== PIN DEFINITIONS ==============
const int LED_ACCESS_GRANTED = 2;   // Green LED
const int LED_ACCESS_DENIED = 4;    // Red LED
const int LED_SYSTEM_STATUS = 5;    // Yellow LED
const int LED_ADMIN_MODE = 18;      // Blue LED
const int BUZZER_PIN = 19;          // Buzzer for audio feedback
const int BUTTON_SELECT = 15;       // Select RFID card
const int BUTTON_ACCESS = 16;       // Request access

// ============== ACCESS LEVELS ==============
enum AccessLevel {
    ACCESS_NONE = 0,
    ACCESS_GUEST = 1,
    ACCESS_USER = 2,
    ACCESS_ADMIN = 3
};

13.6.2 2. User Credential Structure

// ============== USER CREDENTIAL STRUCTURE ==============
struct UserCredential {
    const char* cardId;       // Simulated RFID card ID
    const char* userName;     // User name for logging
    AccessLevel accessLevel;  // Permission level
    bool isActive;            // Account status
};

// ============== CREDENTIAL DATABASE ==============
// In production: Store in secure element, never in code!
const int NUM_USERS = 6;
UserCredential userDatabase[NUM_USERS] = {
    {"RFID_ADMIN_001", "Alice Admin", ACCESS_ADMIN, true},
    {"RFID_ADMIN_002", "Bob Admin", ACCESS_ADMIN, true},
    {"RFID_USER_001", "Charlie User", ACCESS_USER, true},
    {"RFID_USER_002", "Diana User", ACCESS_USER, true},
    {"RFID_GUEST_001", "Eve Guest", ACCESS_GUEST, true},
    {"RFID_DISABLED", "Frank Former", ACCESS_USER, false}  // Disabled account
};

// Test cards for simulation (includes invalid cards)
const int NUM_TEST_CARDS = 8;
const char* testCards[NUM_TEST_CARDS] = {
    "RFID_ADMIN_001",   // Valid admin
    "RFID_USER_001",    // Valid user
    "RFID_GUEST_001",   // Valid guest
    "RFID_DISABLED",    // Disabled account
    "RFID_UNKNOWN_1",   // Unknown card
    "RFID_UNKNOWN_2",   // Unknown card
    "RFID_ADMIN_002",   // Valid admin
    "RFID_USER_002"     // Valid user
};

13.6.3 3. Security Configuration

// ============== SECURITY CONFIGURATION ==============
const int MAX_FAILED_ATTEMPTS = 3;
const unsigned long LOCKOUT_DURATION_MS = 60000;  // 1 minute lockout
const unsigned long LOCKOUT_ESCALATION_MS = 30000; // Add 30s per additional failure
const int MAX_LOCKOUT_DURATION_MS = 300000;  // Max 5 minutes

Brute Force Attack Prevention with Lockout Policies:

Consider an ESP32 access control system where an attacker attempts to present forged RFID tokens. The system has 6 valid tokens, and the attacker is trying unknown card IDs at random.

Without Lockout Protection: \[ \text{Token attempt rate} = 1 \text{ attempt per 2 seconds} = 0.5 \text{ Hz} \]

If the attacker can make unlimited guesses without penalty, they could systematically try card IDs indefinitely until finding a valid one.

With Linear Escalating Lockout (as configured in this lab):

The lab’s lockout policy works as follows:

  • After 3 consecutive failures: locked for 60 seconds (base)
  • Each additional failure adds 30 seconds
  • Maximum lockout: 300 seconds (5 minutes)

After every 3 failed attempts, the attacker must wait: \[ \text{Lockout}(n) = \min(60{,}000 + (n - 3) \times 30{,}000,\ 300{,}000) \text{ ms} \]

where \(n\) is the total number of consecutive failures.

Failures Lockout Duration Cumulative Wait
3 60 s 60 s
4 90 s 150 s
5 120 s 270 s
6 150 s 420 s
10 270 s 1,320 s
12+ 300 s (max) grows by 300 s per attempt

Once the lockout reaches the 300-second cap, the attacker can only make roughly 1 attempt every 5 minutes. Over 24 hours, that limits them to about 288 attempts – a dramatic reduction from the 43,200 attempts possible without lockout (at 0.5 Hz).

Defense Factor: \[ \frac{43{,}200 \text{ attempts/day (no lockout)}}{288 \text{ attempts/day (with lockout)}} = 150\times \text{ slower attack} \]

This makes brute force against unknown RFID token IDs impractical for any reasonably sized token space.

Shield ShellyCheckpoint: Credentials and Lockout

You now know the first security model encoded in the sketch:

  • The credential database contains 6 users, while the simulator cycles through 8 test cards so valid, disabled, and unknown cases all appear.
  • Access levels move from ACCESS_NONE = 0 through ACCESS_ADMIN = 3, which makes the zone comparison explicit.
  • The lockout policy starts after 3 failures at 60 seconds, adds 30 seconds per extra failure, and caps at 300 seconds.

The lockout numbers reduce guessing pressure; the next section asks where each successful user is allowed to go.

13.6.4 4. Access Control Zones

// ============== ACCESS CONTROL ZONES ==============
// Different areas with different access requirements
struct AccessZone {
    const char* zoneName;
    AccessLevel requiredLevel;
};

const int NUM_ZONES = 4;
AccessZone accessZones[NUM_ZONES] = {
    {"Public Lobby", ACCESS_GUEST},
    {"Office Area", ACCESS_USER},
    {"Server Room", ACCESS_ADMIN},
    {"Control Center", ACCESS_ADMIN}
};
Try It: Role-Based Access Control Zone Checker

Select a user from the credential database and a zone to check whether access is granted or denied based on the RBAC hierarchy (Guest < User < Admin).

13.6.5 5. Security State and Audit Log

// ============== SECURITY STATE ==============
struct SecurityState {
    int failedAttempts;
    unsigned long lockoutEndTime;
    bool isLocked;
    int currentCardIndex;
    String lastAuthenticatedUser;
    AccessLevel currentAccessLevel;
    unsigned long sessionStartTime;
} secState;

// ============== AUDIT LOG ==============
struct AuditEntry {
    unsigned long timestamp;
    const char* cardId;
    const char* userName;
    const char* eventType;
    const char* zoneName;
    bool success;
    AccessLevel attemptedLevel;
};

const int MAX_AUDIT_ENTRIES = 50;
AuditEntry auditLog[MAX_AUDIT_ENTRIES];
int auditIndex = 0;

Shield ShellyCheckpoint: State and Evidence

You now know what the controller must remember between button presses:

  • The security state tracks failed attempts, lockout end time, current card index, current access level, and session start time.
  • The audit log keeps up to 50 entries with timestamp, card ID, user name, event type, zone name, success, and attempted level.
  • A denied LED or buzzer event is only useful if the software record also explains why the decision happened.

Once the state is recorded, comparison logic has to avoid leaking which part of a secret matched.

13.7 Constant-Time Comparison

A critical security feature is constant-time string comparison, which prevents timing attacks:

// Constant-time string comparison prevents timing side-channel attacks
bool constantTimeCompare(const char* a, const char* b) {
    size_t lenA = strlen(a);
    size_t lenB = strlen(b);

    // Always compare full length to prevent length-based timing
    size_t maxLen = (lenA > lenB) ? lenA : lenB;

    volatile int result = 0;
    for (size_t i = 0; i < maxLen; i++) {
        char charA = (i < lenA) ? a[i] : 0;
        char charB = (i < lenB) ? b[i] : 0;
        result |= charA ^ charB;
    }

    // Also check lengths match
    result |= (lenA != lenB);

    return (result == 0);
}
Try It: Timing Attack Simulator

See how standard string comparison leaks information through timing, and how constant-time comparison prevents it. Enter a guess to compare against a hidden password and observe the execution time difference.


13.8 Password Hashing Concepts

While this lab uses simple string comparison for demonstration, production systems use cryptographic hashing:

Try It: Password Hash Brute Force Calculator

Explore how password length, character set, and hashing algorithm cost affect the time required for a brute force attack on stolen password hashes.

Scenario: You’re deploying an access control system for a 500-person office building. Calculate appropriate lockout settings to minimize help desk calls while maintaining security.

Current baseline (no lockout implemented):

  • 12,000 login attempts/month
  • 600 failed logins/month (5% failure rate)
  • 23 suspected brute force attacks/month
  • $18,000/year in help desk costs (password resets)

Proposed lockout policy:

const int MAX_FAILED_ATTEMPTS = 3;
const unsigned long LOCKOUT_DURATION_MS = 60000;  // 1 minute

Impact calculation:

Failed login distribution (analyzed from logs):
  1 failure:  420 users (70% - simple typo, corrected immediately)
  2 failures: 120 users (20% - forgotten password, second attempt works)
  3 failures:  45 users (7.5% - will trigger lockout)
  4+ failures: 15 users (2.5% - brute force or major user confusion)

Lockout events per month:
  3-attempt lockout = 45 + 15 = 60 users/month

Cost analysis:
  Help desk calls: 60 x $25/call = $1,500/month
  Productivity loss: 60 users x 5 min avg = 300 min = $750/month (@ $150/hr avg wage)
  Total cost: $2,250/month = $27,000/year

Security benefit:
  Brute force attempts stopped after 3 tries (was unlimited)
  Estimated prevented breaches: 2/year x $50,000 avg = $100,000 saved

Net benefit: $100,000 - $27,000 = $73,000/year ROI

Optimized with escalating lockout:

// Escalating lockout: base + (extra failures * escalation), capped at max
unsigned long calculateLockout(int attempts) {
    return min(LOCKOUT_DURATION_MS + (attempts - MAX_FAILED_ATTEMPTS) * LOCKOUT_ESCALATION_MS,
               (unsigned long)MAX_LOCKOUT_DURATION_MS);
}

// Results with MAX_FAILED_ATTEMPTS=3, base=60s, escalation=30s, max=300s:
//   3 attempts: 60s lockout (most users recover quickly)
//   4 attempts: 90s lockout
//   5 attempts: 120s lockout
//   11+ attempts: 300s lockout (max cap reached)

// New help desk calls: 45 (down 25% - faster recovery for short lockouts)
// Annual cost: $20,250 (vs $27,000)
// Additional savings: $6,750/year
Component Option A (Basic) Option B (Enhanced) Option C (Production)
LEDs 4 single-color LEDs RGB LED module Addressable LED strip
Cost $2 $5 $15
Complexity 4 GPIO pins 3 GPIO pins (R/G/B) 1 GPIO pin (data line)
Use Case Lab learning Prototype Production deploy
Feedback Options 4 states (G/R/Y/B) 16M colors Animations, patterns
Buzzer Passive (tone) Active (fixed freq) Piezo + amplifier
Cost $0.50 $1 $8
Audio Quality Beeps only Single tone Musical notes
Buttons Basic tactile Debounced hardware Capacitive touch
Cost $0.20 each $0.50 each $3 each
Reliability Bouncing (software fix) No bouncing No mechanical wear

Recommendation for this lab: Option A (Basic). Total cost: $4.40. Focus is on learning authentication concepts, not hardware polish.

For production: Upgrade to Option C for reliability. Cost: $32 per unit, but eliminates 90% of hardware support issues.

Common Mistake: Insufficient Debouncing Causes Double-Login Attempts

Problem: Button mechanical bouncing can trigger multiple authentication attempts from a single press.

Impact:

User presses button once
ESP32 detects: Press -> Release -> Press -> Release (in 50ms)
System processes: 2 authentication attempts
Account locked out after 2 button presses (instead of 3)

Lab code correctly handles this:

const unsigned long DEBOUNCE_DELAY = 250;  // 250ms minimum between presses

if (digitalRead(BUTTON_ACCESS) == LOW &&
    (currentTime - lastButtonAccessTime) > DEBOUNCE_DELAY) {
    lastButtonAccessTime = currentTime;
    requestAccess(2);  // Only processes once
}

Testing: Press button rapidly 10 times. Should process exactly 10 requests (not 20-30).


Shield ShellyCheckpoint: Production Boundaries

You now know which setup shortcuts must not escape the lab:

  • Password storage needs a per-user salt and a slow verifier, such as bcrypt cost 12 or PBKDF2 with 100000 iterations in the code challenge.
  • Button handling uses a 250ms debounce delay so one press does not accidentally consume multiple authentication attempts.
  • Hardcoded credentials, plaintext card IDs, and RAM-only audit logs are teaching aids, not production controls.

The remaining quizzes check whether you can connect the hardware setup, library choices, and credential-storage rules without exposing answers in the prose.

Matching Quiz: Match Lab Setup Concepts to Details

Ordering Quiz: Order Lab Environment Setup Steps

Label the Diagram

Code Challenge

13.9 Deep Dive: Password Verifiers and Offline Cracking

The first rule of setting up an access-control system is that the system should not store reusable plaintext passwords. It should store a verifier: a one-way value that can check a later login attempt but cannot be reversed into the original password. If the credential database leaks, the attacker should not receive everyone’s usable credentials.

The verifier must be purpose-built for passwords. General-purpose hashes such as SHA-256 are fast by design, which is useful for files and protocols but harmful for password storage. An attacker with a stolen database can test guesses offline without touching the device UI, waiting for a lockout timer, or triggering the buzzer. A password key-derivation function (KDF) adds a unique salt and a deliberate work factor so every guess costs meaningful time, and memory-hard options also make GPU or ASIC parallelism more expensive.

Access control system diagram showing a security hub receiving RFID, biometric, PIN, and mobile credentials, then driving granted, denied, alarm, and log outputs.
The setup lab connects credential inputs, an access-control decision point, local status outputs, alarms, and audit logging; password storage is only one control inside that wider security loop.

The lab makes each access-control decision visible in hardware: a credential is presented, the controller compares it with stored account state, and the result drives an LED, buzzer, lock output, and audit record. That visible loop separates three questions students often blur together. Authentication asks who is requesting access. Authorization asks what that subject is allowed to do. Monitoring asks what evidence proves the decision happened. Password hashing only helps with authentication, so it has to be combined with access levels, lockout behavior, feedback, and records.

Storage Choice Production Meaning
Password Never store it after enrollment or reset. Discard the entered secret after deriving the verifier.
Salt Generate a fresh random value per user and store it beside the verifier. This prevents one precomputed table from applying to every account.
KDF output Store the result of KDF(password, salt, parameters), not a fast hash. Argon2id, scrypt, bcrypt, or PBKDF2 with appropriate parameters are common choices depending on policy and platform support.
Work parameters Record algorithm, version, iteration count, memory cost, and parallelism so old accounts can be upgraded after successful login.
Pepper Optionally keep a shared secret outside the database, such as in a secret manager or HSM. Use only with a rotation and recovery plan.
Enrollment:
  salt = random bytes unique to this account
  verifier = KDF(password, salt, work_parameters)
  store { algorithm, version, salt, work_parameters, verifier }
  discard password

Login:
  fetch stored parameters
  candidate = KDF(entered_password, stored_salt, stored_parameters)
  compare candidate and verifier in constant time
  apply lockout, authorization, session, and audit rules

The engineering job is to make this rule repeatable. Enrollment generates a new salt, records the KDF algorithm and work factor, stores the derived verifier, and discards the password. Login recomputes the verifier from the entered password and stored parameters, compares in constant time, and then applies lockout and audit rules. Reset flows should create a new verifier instead of trying to recover the old password, because the system should not possess recoverable passwords in the first place.

Choose the KDF and work factor by measurement. A classroom laptop, ESP32 lab sketch, Raspberry Pi gateway, and cloud identity service have different latency budgets. For production web or cloud identity, Argon2id is a strong default when available; scrypt, bcrypt, or PBKDF2 may be selected for compatibility or policy reasons. Measure honest-login delay under expected load, leave margin for bursts and lockout checks, and record the chosen parameters so they can be raised later as hardware improves.

Control Attacker Capability It Targets
Unique salt Defeats rainbow tables and makes identical passwords produce different verifiers.
Slow work factor Makes high-volume offline guessing expensive. A 100 ms KDF is barely noticeable for one login but costly across millions of guesses.
Memory-hard KDF Forces each guess to spend memory as well as time, reducing the advantage of massively parallel cracking hardware.
Pepper outside the database Reduces the value of a database-only theft, but creates a secret-rotation dependency.
Constant-time compare Avoids leaking partial-match information during verifier comparison.

Keep the lab shortcuts explicit. Hardcoded credentials are acceptable only as a temporary demonstration of control flow; they are not a production storage pattern. Serial debug logs should not print entered passwords, salts, peppers, or derived verifiers. Audit events should record the user identifier, method, outcome, timestamp, and reason code, not the secret itself. When the LED or buzzer announces a denial, the software record should be narrow enough to investigate the event without exposing credentials.

Password hashing protects one stored-secret boundary. It does not replace rate limiting, MFA, authorization checks, secure update, logging, or physical tamper resistance.

13.10 Summary

In this setup chapter, you learned:

  1. Hardware components needed for an IoT access control system
  2. Circuit wiring for LEDs, buzzer, and buttons with ESP32
  3. Code organization with clear separation of concerns
  4. Access level hierarchy from GUEST to ADMIN
  5. Security configurations for lockout policies
  6. Constant-time comparison to prevent timing attacks
Lab Shortcuts vs Production

This lab intentionally shows what NOT to do in production:

Lab Shortcut Production Requirement
Hardcoded credentials Store in secure element (ATECC608B, TPM)
Plain text card IDs Encrypted credential storage
In-memory audit log Persistent, tamper-evident logging
Single-factor auth Multi-factor authentication (MFA)
Local database Centralized identity provider (LDAP, AD)

13.11 Knowledge Check

Quiz: Lab: Basic Access Control Setup

Common Pitfalls

This lab hardcodes card IDs and PINs in the source for simplicity — acceptable on a breadboard, dangerous anywhere else. Firmware committed to git or distributed as a binary can be dumped and searched for credential strings. In production, store secrets in a secure element (ATECC608B, TPM) or encrypted NVS partition, never in the source tree.

bcrypt with 4 rounds (the minimum) hashes in <1 ms — fast enough for an attacker to try millions of passwords per second. The recommended rounds for production is 12 (2^12 iterations), which takes ~250 ms per hash — acceptable for login but infeasible for brute force.

The credential structure uses fixed-size char arrays. Copying a card ID or PIN into them without checking length (e.g., strcpy instead of strncpy with explicit truncation) corrupts adjacent memory — on an ESP32 that can overwrite the access level field sitting next to the buffer. Always bounds-check every input before it touches a fixed-size buffer.

The lab’s audit log lives in RAM: one power cycle and the evidence of a break-in attempt is gone — exactly when you need it most. Production access control writes audit events to persistent, tamper-evident storage (flash with wear leveling, or streamed to a backend) so the log survives reboots and deliberate power pulls.

13.12 What’s Next

Continue to the full implementation:

If you want to… Read this
Implement the access control code Lab: Access Control Implementation
Learn advanced access control concepts Advanced Access Control Concepts
See the full lab overview Authentication and Access Control Overview
Understand zero trust principles Zero Trust Security
Study authentication fundamentals Auth & Authorization Basics

Key Concepts

  • Express.js Middleware: Functions that execute in sequence for every HTTP request; authentication middleware validates tokens before requests reach route handlers
  • bcrypt.hash(): The function call that produces a salted hash of a password; the cost factor (rounds) determines computation time and security margin
  • JWT Sign/Verify: jwt.sign() creates a signed token; jwt.verify() validates the signature and extracts claims; the secret/key must be kept server-side
  • SQLite (Dev Database): A file-based SQL database suitable for development and testing; replaced with PostgreSQL or similar for production deployments
  • Environment Variables: Configuration values (JWT secret, database URL, port) stored outside the codebase; loaded with dotenv to avoid hardcoding secrets
  • Express Router: A mini-application that handles routing for a subset of paths; used to organize authentication routes separately from application routes
  • HTTP Status Codes: 200 (OK), 201 (Created), 401 (Unauthorized — not authenticated), 403 (Forbidden — authenticated but not authorized), 409 (Conflict — resource already exists)
In 60 Seconds

This lab sets up the foundational Node.js/Express environment with bcrypt password hashing, JWT token generation, and database initialization — the infrastructure layer that all subsequent authentication and authorization features are built upon.

13.13 Key Takeaway

A basic authentication lab is successful when the setup makes identity observable and repeatable. Keep credentials isolated, document roles, and verify that unauthorized clients fail before adding application logic.