4  Authentication Methods for IoT

4.1 Learning Objectives

By the end of this chapter, you should be able to:

  • Implement password-based authentication with secure storage
  • Configure certificate-based mutual TLS (mTLS) authentication
  • Design JWT token-based authentication for IoT APIs
  • Implement multi-factor authentication (2FA) using TOTP
  • Select appropriate authentication methods based on security requirements

What is Authentication? Authentication is the process of verifying identity - proving that you (or a device) are who you claim to be. It answers the question: “Who are you?”

Authentication vs Authorization:

  • Authentication: Proves identity (you ARE who you claim)
  • Authorization: Determines permissions (what you’re ALLOWED to do)

Key terms: | Term | Definition | |——|————| | Credentials | Information used to prove identity (passwords, certificates, tokens) | | Single-factor | One type of credential (password only) | | Multi-factor (MFA) | Two or more credential types (password + phone code) | | Certificate | Digital document that cryptographically proves identity | | Token | Time-limited credential issued after authentication |

“How do you prove you are really you?” Max the Microcontroller asked the team. “There are three ways: something you KNOW (like a password), something you HAVE (like a key card), and something you ARE (like a fingerprint).”

Sammy the Sensor held up a tiny certificate. “For IoT devices, certificate-based authentication is the gold standard. Each device gets a unique digital certificate during manufacturing – like a birth certificate. When I connect to the server, we do mutual TLS: I verify the server is real, AND the server verifies I am real. Neither side can be fooled by an impostor!”

“Passwords are the weakest option,” Lila the LED cautioned. “People choose terrible passwords, reuse them across sites, and write them on sticky notes. For IoT dashboards, we add multi-factor authentication – after entering your password, you also need a code from your phone app. Even if someone steals your password, they cannot get in without your phone!”

“JWT tokens – JSON Web Tokens – are how modern IoT APIs work,” Bella the Battery explained. “After you authenticate once, you get a token that expires after a set time. Every subsequent request includes this token, so you do not have to re-authenticate every single time. The token contains your identity and permissions in a tamper-proof package. It is like a boarding pass that proves you already went through security!”

4.2 Prerequisites

Before diving into this chapter, you should be familiar with:

How It Works: Password Authentication with Salted Hashing

Modern password authentication follows a secure storage and verification process:

Registration Phase (storing passwords securely):

  1. User submits password: “MySecureP@ssw0rd”
  2. Generate random salt: Cryptographically random 16-byte value (unique per user)
  3. Combine password + salt: “MySecureP@ssw0rd” + salt bytes
  4. Hash with strong algorithm: PBKDF2/bcrypt/Argon2 (computationally expensive, ~100-250ms)
  5. Store salt + hash: Database stores {salt: "a3f8...", hash: "9c2b..."}
  6. NEVER store plaintext password: Original password discarded after hashing

Login Phase (verifying passwords):

  1. User submits password: “MySecureP@ssw0rd”
  2. Retrieve stored salt + hash: Lookup user’s record from database
  3. Recompute hash: Hash(submitted password + stored salt)
  4. Constant-time compare: Compare computed hash with stored hash (prevents timing attacks)
  5. Outcome: If hashes match → authentication succeeds; if different → authentication fails

Why each step matters:

  • Random salt: Two users with same password get different hashes (prevents rainbow table attacks)
  • Slow hashing (100ms): Slows attacker from billions of guesses/sec to single digits (makes brute force impractical)
  • Constant-time compare: Prevents attackers from measuring timing differences to deduce correct password character-by-character

Attack Scenario Prevented: Without salting, attacker steals password database and uses pre-computed rainbow table: - Hash 5f4dcc3b... → Rainbow table lookup → Password is “password” (instant crack) With salting, same hash requires brute-forcing each individual password: - Hash 5f4dcc3b... + salt a3f8... → No rainbow table match → Must try billions of passwords at ~5 tries/sec → Takes years

4.3 Password-Based Authentication

Password-based authentication is the simplest form but also the most commonly exploited. Proper implementation requires secure password storage and protection against brute-force attacks.

4.3.1 Secure Password Storage

Never store passwords in plaintext! Use salted hashing:

// Simplified password storage demonstration (ESP32)
// NOTE: For production, use PBKDF2/bcrypt/Argon2 with high iteration counts.
// Plain SHA-256 shown here for illustration only -- it is too fast for
// secure password hashing.
#include "mbedtls/sha256.h"

struct PasswordHash {
  uint8_t salt[16];
  uint8_t hash[32];
};

PasswordHash hashPassword(String password) {
  PasswordHash result;

  // Generate random salt
  // NOTE: On ESP32, prefer esp_fill_random() for cryptographic randomness.
  // Arduino random() is a PRNG and not suitable for production security.
  for (int i = 0; i < 16; i++) {
    result.salt[i] = random(256);
  }

  // Combine password + salt
  String combined = password;
  for (int i = 0; i < 16; i++) {
    combined += (char)result.salt[i];
  }

  // Hash with SHA-256 (single iteration -- see note above)
  mbedtls_sha256((uint8_t*)combined.c_str(), combined.length(),
                 result.hash, 0);

  return result;
}

bool verifyPassword(String password, PasswordHash stored) {
  // Recompute hash with stored salt
  String combined = password;
  for (int i = 0; i < 16; i++) {
    combined += (char)stored.salt[i];
  }

  uint8_t computed[32];
  mbedtls_sha256((uint8_t*)combined.c_str(), combined.length(),
                 computed, 0);

  // Constant-time comparison (prevents timing attacks)
  // NOTE: memcmp() is NOT constant-time -- it returns early on first
  // mismatch. Use mbedtls_ct_memcmp() or a manual byte-by-byte XOR
  // accumulator for production code.
  uint8_t diff = 0;
  for (int i = 0; i < 32; i++) {
    diff |= computed[i] ^ stored.hash[i];
  }
  return diff == 0;
}

4.3.2 Why Salted Hashing Matters

Storage Method Attack Time Vulnerability
Plaintext Instant Anyone with database access has all passwords
Unsalted hash (SHA-256) Minutes-hours Rainbow table lookup; GPU can hash ~22 billion/sec
Salted hash (SHA-256) Hours-days Defeats rainbow tables but fast hashing still allows rapid brute force
PBKDF2/bcrypt/Argon2 Years-centuries Computationally expensive (~200ms/hash), defeats GPU parallelism

Best Practice: Use PBKDF2, bcrypt, or Argon2 with high iteration counts (100,000+ for PBKDF2) for production systems. Argon2id is currently recommended by OWASP and RFC 9106.

4.4 Certificate-Based Authentication (X.509)

Certificate-based authentication uses digital certificates to prove identity cryptographically. This is the gold standard for IoT device authentication.

4.4.1 Mutual TLS (mTLS) Implementation

// Mutual TLS authentication with certificates
#include <WiFiClientSecure.h>

WiFiClientSecure client;

// Device certificate (unique per device)
const char* device_cert = \
"-----BEGIN CERTIFICATE-----\n" \
"MIICxjCCAa4CAQEwDQYJKoZIhvcNAQELBQAwIDEeMBwGA1UEAwwVSW9UIERldmlj\n" \
"-----END CERTIFICATE-----\n";

// Device private key
const char* device_key = \
"-----BEGIN PRIVATE KEY-----\n" \
"MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC7VJTUt9Us8cKj\n" \
"-----END PRIVATE KEY-----\n";

// CA certificate (verify server)
const char* ca_cert = \
"-----BEGIN CERTIFICATE-----\n" \
"MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh\n" \
"-----END CERTIFICATE-----\n";

void setup() {
  // Configure mutual TLS
  client.setCACert(ca_cert);           // Verify server
  client.setCertificate(device_cert);  // Present device cert
  client.setPrivateKey(device_key);    // Device private key

  // Connect with mutual authentication
  if (client.connect("mqtt.server.com", 8883)) {
    Serial.println("Mutually authenticated!");
  }
}

4.4.2 How mTLS Works

Device                              Server
  |                                    |
  |------ TLS ClientHello ------------>|
  |<----- TLS ServerHello + Server Cert|
  |                                    |
  | (Device verifies server cert       |
  |  against trusted CA)               |
  |                                    |
  |------ Device Certificate --------->|
  |                                    |
  |      (Server verifies device cert  |
  |       against trusted CA)          |
  |                                    |
  |<----- TLS Finished ----------------|
  |                                    |
  | (Both parties authenticated,       |
  |  encrypted channel established)    |
Tradeoff: Password vs Certificate Authentication

Option A (Password-Based):

  • User/device credentials stored as salted hashes
  • Authentication time: 5-10ms (hash comparison on server)
  • Susceptible to credential stuffing if passwords are weak/reused
  • No PKI infrastructure required
  • Storage: 50-100 bytes per credential

Option B (Certificate-Based):

  • Public/private key pairs with CA signatures
  • Authentication time: 50-200ms (full TLS handshake including signature verification and network latency)
  • Immune to credential stuffing
  • Requires PKI infrastructure (CA, CRL/OCSP)
  • Storage: 1-2KB per device certificate
  • Enables mutual TLS (mTLS)

Decision Factors: Choose passwords for simple deployments with human users. Choose certificates for device-to-device authentication, high-security environments, or when scaling to thousands of devices where password management becomes impractical.

4.5 Token-Based Authentication (JWT)

JWT (JSON Web Token) is a compact, self-contained token for authenticating API requests. Unlike session cookies, JWTs are stateless - the server doesn’t need to store session data.

4.5.1 JWT Structure

header.payload.signature
Part Content Purpose
Header {"alg": "HS256", "typ": "JWT"} Specifies signing algorithm
Payload {"device_id": "sensor-42", "exp": 1735689600} Contains claims (device ID, expiration)
Signature HMACSHA256(base64(header) + "." + base64(payload), SECRET_KEY) Prevents tampering

4.5.2 JWT Authentication Flow

Sequence diagram showing JWT authentication flow: device sends credentials to auth server, receives signed JWT token, then includes token in subsequent API requests to resource server which validates the signature and expiration before granting access
Figure 4.1: JWT authentication flow showing stateless API authentication for IoT devices

4.5.3 JWT Security Best Practices

Practice Why It Matters Example
Short expiration Limits damage if token stolen 15-60 min for IoT devices; 24 hours max for dashboards
Strong secret key Prevents signature forgery 256-bit random key (not “secret123”)
HTTPS only Prevents token interception Never send JWT over HTTP
Don’t store sensitive data Payload is Base64-encoded (not encrypted) Store user ID, not passwords
Validate all claims Prevents replay attacks Check exp, iat, iss, scope

4.6 Multi-Factor Authentication (2FA)

Multi-factor authentication requires two or more independent credentials:

  • Something you know: Password, PIN
  • Something you have: Phone, hardware token, certificate
  • Something you are: Fingerprint, face recognition

4.6.1 TOTP Implementation (Time-based One-Time Password)

// TOTP (Time-based One-Time Password) for 2FA
// Follows RFC 6238 (TOTP) and RFC 4226 (HOTP)
#include <TimeLib.h>

String generateTOTP(const char* secret, uint32_t timestamp) {
  // TOTP = HMAC-SHA1(secret, timestamp / 30)
  uint64_t counter = timestamp / 30;

  uint8_t hmac[20];
  // ... HMAC-SHA1 computation ...

  // Dynamic truncation (RFC 4226 Section 5.4)
  uint32_t offset = hmac[19] & 0x0F;
  uint32_t code = ((hmac[offset] & 0x7F) << 24) |
                  ((hmac[offset + 1] & 0xFF) << 16) |
                  ((hmac[offset + 2] & 0xFF) << 8) |
                  (hmac[offset + 3] & 0xFF);

  code = code % 1000000;
  return String(code);
}

bool verifyTOTP(const char* secret, String userCode) {
  uint32_t timestamp = now();

  // Check current and +/- 1 time window (90 seconds total)
  for (int i = -1; i <= 1; i++) {
    String validCode = generateTOTP(secret, timestamp + (i * 30));
    if (userCode == validCode) {
      return true;
    }
  }

  return false;
}
Tradeoff: Single-Factor vs Multi-Factor Authentication

Option A (Single-Factor - Password Only):

  • One authentication step
  • 100-500ms total auth time
  • 95% of IoT breaches exploit weak/default passwords
  • User friction: Low
  • Cost per device: Negligible

Option B (Multi-Factor - Password + TOTP):

  • Two or more authentication steps
  • 1-3 seconds total auth time
  • Blocks 99.9% of automated credential attacks
  • User friction: Moderate
  • Cost per device: $0-5 (software) or $10-30 (hardware token)

Decision Factors: Choose single-factor for low-risk IoT with no direct internet exposure. Choose MFA for admin interfaces, cloud dashboards, and any system accessible from the internet.

4.7 Worked Example: Industrial MFA Implementation

Scenario: A manufacturing plant operates 50 industrial PLCs controlling assembly line robots. Operators currently use shared passwords (“plc_admin/factory123”). Implement MFA without disrupting 24/7 operations.

Solution Design:

  1. Select MFA factors for industrial environment:

    • Factor 1 (Something you have): RFID badge (already used for building access)
    • Factor 2 (Something you know): 4-digit PIN (quick entry on touchscreen)
  2. Authentication flow:

    Step 1: Operator taps RFID badge on PLC reader
    Step 2: PLC prompts for 4-digit PIN
    Step 3: PLC validates badge ID + PIN hash against auth server
    Step 4: Auth server checks role permissions for this PLC
    Step 5: Access granted for 8-hour shift duration
  3. Role-based permissions: | Role | Start/Stop | Adjust Speed | Change Recipe | Emergency Stop | |——|————|————–|—————|—————-| | Operator | Yes | Yes | No | Yes | | Lead Operator | Yes | Yes | Yes | Yes | | Maintenance | No | No | No | Yes | | Supervisor | Yes | Yes | Yes | Yes |

Result:

  • Authentication time: 3-5 seconds (badge tap + PIN entry)
  • Eliminated shared passwords
  • Full audit trail: WHO did WHAT on WHICH PLC at WHAT TIME
  • Zero production disruption during rollout

4.8 Worked Example: Credential Stuffing Attack Economics

Scenario: An attacker targets an IoT cloud platform managing 50,000 smart home devices. The platform uses password-only authentication. Calculate the attack cost, success probability, and compare defenses.

4.8.1 Attack Economics

# Credential stuffing attack cost analysis

# Attacker resources
stolen_credentials = 1_000_000  # from dark web breach database
credential_cost = 0.005  # $5 per 1,000 credentials (market rate)
proxy_cost_per_1000 = 1.50  # rotating residential proxies
automation_tool = 200  # one-time cost for stuffing tool

# Attack parameters
attempts_per_second = 50  # rate-limited to avoid detection
success_rate = 0.02  # 2% credential reuse rate (industry average)
accounts_compromised = int(stolen_credentials * success_rate)

# Cost calculation
total_credential_cost = stolen_credentials * credential_cost
total_proxy_cost = (stolen_credentials / 1000) * proxy_cost_per_1000
total_cost = total_credential_cost + total_proxy_cost + automation_tool
time_hours = stolen_credentials / (attempts_per_second * 3600)

print(f"Attack parameters:")
print(f"  Credentials tested: {stolen_credentials:,}")
print(f"  Success rate: {success_rate*100}%")
print(f"  Accounts compromised: {accounts_compromised:,}")
print(f"")
print(f"Attack cost:")
print(f"  Credentials: ${total_credential_cost:,.0f}")
print(f"  Proxies: ${total_proxy_cost:,.0f}")
print(f"  Tools: ${automation_tool}")
print(f"  Total: ${total_cost:,.0f}")
print(f"  Time: {time_hours:.1f} hours")
print(f"  Cost per compromised account: ${total_cost/accounts_compromised:.2f}")

Result: For approximately $6,700 and 5.6 hours, an attacker compromises ~20,000 accounts at $0.34 each. With smart home access, each account enables:

  • Physical surveillance: View camera feeds, know when residents are away
  • Physical access: Unlock smart doors
  • Data harvesting: Temperature schedules reveal occupancy patterns

4.8.2 Defense Comparison

Defense Implementation Cost Effectiveness vs. Stuffing User Friction
Password only $0 0% (no defense) None
Rate limiting (10/min/IP) ~$500 (WAF rule) ~60% (proxies bypass) None
CAPTCHA ~$1,000/yr ~85% (CAPTCHA farms exist) Moderate
MFA (TOTP) ~$2,000/yr ~99.9% Moderate
Device certificates (mTLS) ~$5,000 setup ~100% (no password to stuff) None (automated)
Passkeys (FIDO2) ~$3,000 setup ~100% (phishing-resistant) Low

4.8.3 Python: Secure Password Verification with Argon2

# Production-grade password hashing for IoT platforms
# Argon2id is the current recommendation (RFC 9106)
from argon2 import PasswordHasher
from argon2.exceptions import VerifyMismatchError

# Configure for server-side IoT platform
ph = PasswordHasher(
    time_cost=3,        # 3 iterations
    memory_cost=65536,  # 64 MB RAM (server has plenty)
    parallelism=4,      # 4 threads
    hash_len=32,        # 256-bit output
    salt_len=16,        # 128-bit salt
)

# Hash a password (during registration)
password = "user_chosen_password"
hashed = ph.hash(password)
print(f"Stored hash: {hashed}")
# => $argon2id$v=19$m=65536,t=3,p=4$...

# Verify a password (during login)
try:
    ph.verify(hashed, password)
    print("Authentication successful")

    # Check if hash needs rehashing (parameters updated)
    if ph.check_needs_rehash(hashed):
        new_hash = ph.hash(password)
        # Update stored hash in database
        print("Hash upgraded to current parameters")
except VerifyMismatchError:
    print("Authentication failed")

# Benchmark: time to verify one password
import time
start = time.time()
for _ in range(10):
    ph.hash("benchmark_password")
elapsed = (time.time() - start) / 10
print(f"\nHash time: {elapsed*1000:.0f}ms per password")
print(f"Attacker throughput: {1/elapsed:.0f} attempts/sec (vs ~22B/sec for SHA-256)")
# => ~200ms per hash = 5 attempts/sec (vs ~22 billion for plain SHA-256)

Key insight: Argon2id at these settings takes ~200ms per hash on a server CPU. An attacker with a GPU cluster attempting brute force can try ~5 passwords/second instead of ~22 billion/second with plain SHA-256 – a ~4.4 billion times slowdown.

4.9 Authentication Method Comparison

Method Security Complexity IoT Suitability Best For
Password Low-Medium Low Good Human users, simple devices
Certificate (mTLS) High High Excellent Device-to-device, fleet management
JWT Token Medium-High Medium Good APIs, cloud services
MFA (TOTP) High Medium Good Admin access, sensitive operations
Hardware Token Very High High Moderate Critical infrastructure

Flowchart decision tree for selecting IoT authentication methods based on deployment criteria: starts with whether the endpoint is a device or human user, branches through questions about internet exposure, fleet size, and security requirements, leading to recommendations such as mTLS certificates for large device fleets, JWT tokens for API access, MFA for internet-facing admin dashboards, and passwords with rate limiting for simple internal systems

Authentication method decision tree for IoT deployments

Password entropy \(H\) measures the unpredictability of a password in bits, defined as:

\[H = L \times \log_2(N)\]

where \(L\) = password length, \(N\) = character set size.

Brute Force Attack Time:

\[T = \frac{2^H}{R}\]

where \(R\) = attacker’s guess rate (guesses per second).

Working through an example:

Given: IoT dashboard requires password for 200 field technicians. Attacker uses GPU cluster: \(R = 10^{10}\) guesses/sec (bcrypt slows this to \(R = 5\) guesses/sec).

Scenario A: 8-character mixed case + symbols

  • Character set: lowercase (26) + uppercase (26) + digits (10) + symbols (33) = \(N = 95\)
  • Length: \(L = 8\)

Step 1: Calculate entropy \[H = 8 \times \log_2(95) = 8 \times 6.57 = 52.6 \text{ bits}\]

Step 2: Brute force time (plain SHA-256) \[T = \frac{2^{52.6}}{10^{10}} = \frac{6.9 \times 10^{15}}{10^{10}} = 690,000 \text{ seconds} \approx 8 \text{ days}\]

Step 3: Brute force time (bcrypt cost 12) \[T = \frac{2^{52.6}}{5} = 1.38 \times 10^{15} \text{ seconds} \approx 43.8 \text{ million years}\]

Scenario B: 4-word passphrase (Diceware)

  • Dictionary size: \(N = 7{,}776\) words
  • Length: \(L = 4\) words

\[H = 4 \times \log_2(7776) = 4 \times 12.9 = 51.7 \text{ bits}\]

\[T_{bcrypt} = \frac{2^{51.7}}{5} = 6.5 \times 10^{14} \text{ seconds} \approx 20.6 \text{ million years}\]

Result: Both 8-char complex and 4-word passphrase provide ~52 bits entropy. With bcrypt, both resist brute force for decades. Plain SHA-256 allows cracking in days.

In practice: The 2019 Ring breach used credential stuffing (reused passwords). Even with strong entropy, password reuse defeats protection. For IoT systems with human authentication, MFA is essential – password entropy alone is insufficient against modern attacks.

Use this calculator to explore how password length, character set, and hashing algorithm affect brute force resistance.

Concept Relationships
Concept Related To Relationship Type
Password Hashing Cryptography, One-Way Functions Applies - SHA-256/bcrypt transform passwords into irreversible digests
Salting Rainbow Table Defense Prevents - Unique salt per password defeats pre-computed hash lookups
Certificate-Based Auth Public Key Cryptography Implements - X.509 certificates prove identity via asymmetric keys
JWT Tokens Stateless Authentication Enables - Self-contained tokens eliminate server-side session storage
MFA (Multi-Factor) Defense-in-Depth Combines - Multiple proof types (know + have + are) resist credential theft
TOTP (Time-Based OTP) MFA, Shared Secrets Generates - 30-second codes from shared seed synchronized with server
See Also

Foundation Concepts:

Related Security Topics:

Practical Applications:

Build a time-based one-time password (TOTP) generator and verifier to understand how authenticator apps work.

Exercise Steps:

  1. Generate a shared secret (random 32-byte value)
  2. Implement HMAC-SHA1 to compute TOTP code from secret + current Unix timestamp / 30
  3. Extract 6-digit code from HMAC output
  4. Verify user-submitted code matches server-generated code (allow +/-1 time window for clock skew)

Starter Code (Python):

import hmac, hashlib, time, struct

def generate_totp(secret, timestamp=None):
    if timestamp is None:
        timestamp = int(time.time())
    counter = timestamp // 30  # 30-second window
    # Pack counter as big-endian 8-byte integer
    counter_bytes = struct.pack(">Q", counter)
    # Compute HMAC-SHA1
    h = hmac.new(secret, counter_bytes, hashlib.sha1).digest()
    # Dynamic truncation (RFC 4226)
    offset = h[19] & 0x0F
    code = ((h[offset] & 0x7F) << 24 |
            (h[offset+1] & 0xFF) << 16 |
            (h[offset+2] & 0xFF) << 8 |
            (h[offset+3] & 0xFF))
    code = code % 1_000_000
    return code

# Test
secret = b"JBSWY3DPEHPK3PXP"  # Base32 encoded
code = generate_totp(secret)
print(f"Current TOTP code: {code:06d}")

What to Observe:

  • Code changes every 30 seconds (time-synchronized)
  • Same secret on server and client produces same code
  • Attacker intercepting old code cannot reuse it (expires in 30 seconds)
  • Clock skew tolerance (+/-30 seconds) allows minor time differences

Key Concepts

  • Pre-Shared Key (PSK): A symmetric secret known to both parties before communication begins; simple to implement but requires secure distribution and per-device key management
  • X.509 Certificate: A digital document binding a public key to an identity, signed by a Certificate Authority; enables asymmetric authentication without sharing secrets
  • TOTP (Time-based One-Time Password): A 6-digit code generated from a shared secret and the current time (RFC 6238); valid for 30 seconds; prevents replay attacks
  • HMAC-SHA256: A message authentication code combining a secret key with SHA-256 hashing; used to authenticate API requests and verify message integrity
  • Replay Attack: An attack where a captured valid authentication credential is reused by an attacker; prevented with nonces (random values used once) or timestamps
  • Brute Force Protection: Rate limiting, account lockout, and exponential backoff mechanisms that prevent automated enumeration of valid credentials
  • Key Derivation Function (KDF): A function (PBKDF2, bcrypt, scrypt, Argon2) that converts a password into a fixed-size key suitable for cryptographic use; designed to be slow to resist brute force
In 60 Seconds

IoT authentication methods range from pre-shared keys (simple, scalable to constrained devices) through X.509 certificates (strong identity, supports mutual auth) to TOTP one-time passwords (replay-resistant, suitable for human operators) — each with different tradeoffs in computational cost, key management complexity, and resistance to credential theft.

Extension: QR code generation to provision secret into Google Authenticator app

4.10 Chapter Summary

Authentication methods verify identity before granting access to IoT systems. Password-based authentication remains common but requires secure storage (salted hashing with PBKDF2/bcrypt/Argon2) and protection against brute-force attacks. Certificate-based authentication (mTLS) provides the highest security for device authentication, enabling bidirectional identity verification through PKI infrastructure.

Token-based authentication (JWT) offers stateless API access with self-contained claims, while multi-factor authentication adds additional verification factors to protect against credential compromise. The choice of authentication method depends on device capabilities, security requirements, and operational constraints.

4.11 Knowledge Check

Common Pitfalls

Pre-shared keys shared across a fleet mean compromising one device compromises all. Always generate a unique PSK for each device at provisioning time and store them in a key management system that enables per-device revocation.

Accepting any certificate signed by any CA allows an attacker with any CA access to forge device certificates. Pin the root CA or intermediate CA that signed your device certificates, and reject certificates from any other issuer.

TOTP codes are valid only for the 30-second window around the current time. IoT devices without real-time clocks or NTP synchronization generate invalid codes even with correct shared secrets. Always ensure TOTP-using devices have synchronized time and implement clock skew tolerance (±30 seconds).

Configuration files read by multiple processes and often backed up to unsecured locations expose credentials to insider threats and backup breaches. Use dedicated secret stores (HashiCorp Vault, AWS Secrets Manager) and access credentials only through environment variables or vault APIs at runtime.

4.12 What’s Next

With authentication methods established, the next chapter examines Access Control where you’ll learn to implement RBAC and ABAC policies that determine what authenticated users and devices are allowed to do.

If you want to… Read this
Implement access control policies Access Control for IoT
Explore IoT-specific authentication IoT Security Access Control
Study cryptographic authentication methods Encryption Principles and Crypto Basics
Apply zero trust authentication Zero Trust Security
Understand threat modeling for auth systems Threat Modelling and Mitigation