DEV Community

Preecha
Preecha

Posted on

How Do You Build a HIPAA-Compliant API in 2026 for Secure Healthcare Applications?

TL;DR

HIPAA compliance for APIs requires strict safeguards for Protected Health Information (PHI): encryption in transit and at rest, audit logging, access controls, and Business Associate Agreements (BAAs). This guide shows how to implement a HIPAA-focused API architecture, authentication, authorization, audit trails, and compliance verification.

Try Apidog today

Introduction

Healthcare data breaches cost an average of $10.93 million per incident. If you build healthcare applications, API security is not optional: it is part of meeting HIPAA (Health Insurance Portability and Accountability Act) requirements.

Unauthorized API and application access is involved in 79% of healthcare data breaches. A properly designed HIPAA-compliant API architecture helps prevent unauthorized access, creates an auditable record of PHI activity, and protects patient privacy.

This guide covers:

  • PHI classification and the minimum necessary standard
  • BAAs and vendor review
  • MFA, JWTs, and role-based authorization
  • TLS and encryption at rest
  • Audit logging and retention
  • Input validation, rate limiting, and error handling
  • Deployment and risk-assessment checklists

πŸ’‘ Design secure endpoints, validate encryption requirements, audit access patterns, and document compliance controls in one workspace with Apidog. Share API specifications with your compliance team and maintain audit-ready documentation.

What Is HIPAA and Why Does It Matter for APIs?

HIPAA is a US federal law that establishes standards for protecting sensitive patient health information. For APIs, the HIPAA Security Rule applies to electronic Protected Health Information (ePHI) created, received, maintained, or transmitted by your application.

Who Must Comply

Entity type Examples API implications
Covered entities Healthcare providers, health plans, clearinghouses Direct HIPAA liability
Business associates API providers, cloud services, software vendors BAA required; direct liability
Subcontractors Subprocessors, downstream API services BAA required

Key HIPAA Rules for APIs

Privacy Rule

  • Governs the use and disclosure of PHI
  • Requires the minimum necessary standard
  • Provides patient access rights
  • Defines authorization requirements

Security Rule

  • Requires safeguards for ePHI
  • Access controls
  • Audit controls
  • Integrity controls
  • Transmission security

Breach Notification Rule

  • Defines incident-response requirements
  • Requires risk-assessment documentation
  • Includes a 60-day notification window
  • Requires mitigation procedures

API Architecture Overview

A HIPAA-oriented API stack should place controls at every layer:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    HIPAA-COMPLIANT API STACK                     β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                  β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”          β”‚
β”‚  β”‚   CLIENT    │───▢│ API GATEWAY │───▢│  DATABASE   β”‚          β”‚
β”‚  β”‚   (App)     β”‚    β”‚             β”‚    β”‚ (Encrypted) β”‚          β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜          β”‚
β”‚        β”‚                  β”‚                  β”‚                   β”‚
β”‚        β–Ό                  β–Ό                  β–Ό                   β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”          β”‚
β”‚  β”‚ OAuth 2.0   β”‚    β”‚ WAF + Rate  β”‚    β”‚ Audit       β”‚          β”‚
β”‚  β”‚ + MFA       β”‚    β”‚ Limiting    β”‚    β”‚ Logging     β”‚          β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜          β”‚
β”‚                                                                  β”‚
β”‚  Encrypt data in transit with TLS 1.3+ and at rest with AES-256 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
Enter fullscreen mode Exit fullscreen mode

Getting Started: Build the Compliance Foundation

Step 1: Execute Business Associate Agreements

Before your API handles PHI:

  1. Identify every vendor that can access, process, store, transmit, back up, or log PHI.
  2. Execute a BAA with each applicable vendor.
  3. Document downstream subprocessors.
  4. Review BAAs annually and whenever your architecture changes.

Common vendors that may require BAAs:

  • Cloud hosting providers such as AWS, GCP, and Azure
  • Database providers
  • Logging and SIEM services
  • Backup providers
  • API gateways
  • Monitoring and alerting tools

Do not use the following for PHI unless an appropriate BAA and configuration are in place:

  • Standard Google Analytics
  • Free-tier cloud services
  • Personal email accounts
  • Non-healthcare Slack channels

Step 2: Classify API Data

Create a data inventory before implementing endpoints. Mark each field as PHI, then apply the appropriate controls.

Data type Classification Protection level
Patient name + date of birth PHI Full HIPAA controls
Medical record number PHI Full HIPAA controls
Diagnosis codes (ICD-10) PHI Full HIPAA controls
Treatment notes PHI Full HIPAA controls
Appointment times without patient identifiers Not PHI Standard controls
Aggregated, de-identified data Not PHI Standard controls

Step 3: Apply the Minimum Necessary Standard

Avoid endpoints that return an entire patient object by default. Use a server-side allowlist and return only the fields required for the request.

// BAD: Returns all patient data
app.get('/api/patients/:id', async (req, res) => {
  const patient = await db.patients.findById(req.params.id);
  res.json(patient);
});
Enter fullscreen mode Exit fullscreen mode
// GOOD: Return only allowlisted fields
app.get('/api/patients/:id', async (req, res) => {
  const requestedFields = req.query.fields?.split(',') || ['id', 'name'];
  const allowedFields = ['id', 'name', 'dateOfBirth'];

  const fields = requestedFields.filter(field => allowedFields.includes(field));
  const patient = await db.patients.findById(req.params.id);

  const filtered = Object.fromEntries(
    Object.entries(patient).filter(([key]) => fields.includes(key))
  );

  res.json(filtered);
});
Enter fullscreen mode Exit fullscreen mode

Do not let a client choose arbitrary database fields. Validate requested fields against an endpoint-specific allowlist.

Technical Safeguards Implementation

Access Control: Authentication

Use strong authentication for every user who can access PHI. This example verifies a password, verifies an MFA code, issues a short-lived JWT, and records the event.

const crypto = require('crypto');
const jwt = require('jsonwebtoken');
const bcrypt = require('bcrypt');

class HIPAAAuthService {
  async authenticate(username, password, mfaCode, requestContext) {
    // 1. Verify credentials
    const user = await this.getUserByUsername(username);
    if (!user) throw new Error('Invalid credentials');

    const validPassword = await bcrypt.compare(password, user.passwordHash);
    if (!validPassword) throw new Error('Invalid credentials');

    // 2. Verify MFA using TOTP
    const validMFA = this.verifyTOTP(user.mfaSecret, mfaCode);
    if (!validMFA) throw new Error('Invalid MFA code');

    // 3. Issue a short-lived token for PHI access
    const token = jwt.sign(
      {
        sub: user.id,
        role: user.role,
        mfa_verified: true
      },
      process.env.JWT_SECRET,
      { expiresIn: '15m' }
    );

    // 4. Record the authentication event
    await this.auditLog('AUTH_SUCCESS', {
      userId: user.id,
      ip: requestContext.ip
    });

    return { token, expiresIn: 900 };
  }

  verifyTOTP(secret, token) {
    const period = 30;
    const digits = 6;
    const now = Math.floor(Date.now() / 1000);
    const counter = Math.floor(now / period);

    const buffer = Buffer.alloc(8);
    buffer.writeUInt32BE(0, 0);
    buffer.writeUInt32BE(counter, 4);

    const hmac = crypto.createHmac('sha1', secret).update(buffer).digest();
    const offset = hmac[hmac.length - 1] & 0x0f;

    const code = (
      ((hmac[offset] & 0x7f) << 24) |
      ((hmac[offset + 1] & 0xff) << 16) |
      ((hmac[offset + 2] & 0xff) << 8) |
      (hmac[offset + 3] & 0xff)
    ) % Math.pow(10, digits);

    return code.toString().padStart(digits, '0') === token;
  }
}
Enter fullscreen mode Exit fullscreen mode

Implementation checklist:

  • Require MFA for PHI-capable accounts.
  • Keep PHI access tokens short-lived.
  • Store signing keys securely.
  • Record successful and failed authentication attempts.
  • Add refresh-token rotation if your architecture uses refresh tokens.

Access Control: Authorization

Authentication identifies the caller. Authorization determines whether that caller can access a specific resource.

Start with role-based access control (RBAC):

const ROLES = {
  ADMIN: 'admin',
  PROVIDER: 'provider',
  NURSE: 'nurse',
  BILLING: 'billing',
  PATIENT: 'patient'
};

const PERMISSIONS = {
  [ROLES.ADMIN]: ['read:all', 'write:all', 'delete:all'],
  [ROLES.PROVIDER]: [
    'read:patients',
    'write:patients',
    'read:labs',
    'write:orders'
  ],
  [ROLES.NURSE]: ['read:patients', 'write:vitals', 'read:labs'],
  [ROLES.BILLING]: ['read:billing', 'read:patients:limited'],
  [ROLES.PATIENT]: ['read:self', 'write:self']
};
Enter fullscreen mode Exit fullscreen mode

Enforce permissions with middleware:

const authorize = (...requiredPermissions) => {
  return async (req, res, next) => {
    const user = req.user;
    const userPermissions = PERMISSIONS[user.role] || [];

    const hasPermission = requiredPermissions.every(permission =>
      userPermissions.includes(permission)
    );

    if (!hasPermission) {
      await auditLog('AUTHZ_DENIED', {
        userId: user.id,
        action: req.method,
        path: req.path,
        required: requiredPermissions
      });

      return res.status(403).json({
        error: 'Insufficient permissions'
      });
    }

    next();
  };
};
Enter fullscreen mode Exit fullscreen mode

Apply authentication and authorization before the route handler:

app.get(
  '/api/patients/:id/records',
  authenticate,
  authorize('read:patients'),
  getPatientRecords
);
Enter fullscreen mode Exit fullscreen mode

RBAC alone is not enough for patient records. Also verify the provider-to-patient relationship or whether the patient owns the requested record.

Encryption in Transit

Require HTTPS for all API communication and configure TLS 1.3.

const https = require('https');
const fs = require('fs');

const options = {
  key: fs.readFileSync('server-key.pem'),
  cert: fs.readFileSync('server-cert.pem'),
  ca: fs.readFileSync('ca-cert.pem'),
  minVersion: 'TLSv1.3',
  ciphers: [
    'TLS_AES_256_GCM_SHA384',
    'TLS_CHACHA20_POLY1305_SHA256',
    'TLS_AES_128_GCM_SHA256'
  ].join(':'),
  honorCipherOrder: true
};

const server = https.createServer(options, app);
Enter fullscreen mode Exit fullscreen mode

Redirect HTTP traffic to HTTPS:

app.use((req, res, next) => {
  if (!req.secure) {
    return res.redirect(`https://${req.headers.host}${req.url}`);
  }

  next();
});
Enter fullscreen mode Exit fullscreen mode

Add HTTP Strict Transport Security (HSTS):

app.use((req, res, next) => {
  res.setHeader(
    'Strict-Transport-Security',
    'max-age=31536000; includeSubDomains; preload'
  );

  next();
});
Enter fullscreen mode Exit fullscreen mode

Encryption at Rest

Encrypt stored PHI and manage encryption keys with a managed key service such as AWS KMS, GCP KMS, or Azure Key Vault.

The following example uses AES-256-GCM, which provides encryption and integrity protection:

const crypto = require('crypto');

class EncryptionService {
  constructor(key) {
    // In production, use a managed KMS or vault for key management.
    this.key = crypto.scryptSync(key, 'salt', 32);
    this.algorithm = 'aes-256-gcm';
  }

  encrypt(plaintext) {
    const iv = crypto.randomBytes(16);
    const cipher = crypto.createCipheriv(this.algorithm, this.key, iv);

    let encrypted = cipher.update(plaintext, 'utf8', 'hex');
    encrypted += cipher.final('hex');

    return {
      encryptedData: encrypted,
      iv: iv.toString('hex'),
      authTag: cipher.getAuthTag().toString('hex')
    };
  }

  decrypt(encryptedData, iv, authTag) {
    const decipher = crypto.createDecipheriv(
      this.algorithm,
      this.key,
      Buffer.from(iv, 'hex')
    );

    decipher.setAuthTag(Buffer.from(authTag, 'hex'));

    let decrypted = decipher.update(encryptedData, 'hex', 'utf8');
    decrypted += decipher.final('utf8');

    return decrypted;
  }
}
Enter fullscreen mode Exit fullscreen mode

Encrypt PHI fields before persistence and decrypt only when an authorized request needs them:

class PatientRecord {
  constructor(db, encryptionService) {
    this.db = db;
    this.encryption = encryptionService;
  }

  async create(data) {
    const encryptedData = {
      ...data,
      ssn: this.encryption.encrypt(data.ssn),
      diagnosis: this.encryption.encrypt(data.diagnosis),
      treatmentNotes: this.encryption.encrypt(data.treatmentNotes)
    };

    await this.db.patients.insert(encryptedData);
    await auditLog('PHI_CREATED', { recordType: 'patient' });
  }

  async findById(id) {
    const record = await this.db.patients.findById(id);

    return {
      ...record,
      ssn: this.encryption.decrypt(
        record.ssn.encryptedData,
        record.ssn.iv,
        record.ssn.authTag
      ),
      diagnosis: this.encryption.decrypt(
        record.diagnosis.encryptedData,
        record.diagnosis.iv,
        record.diagnosis.authTag
      ),
      treatmentNotes: this.encryption.decrypt(
        record.treatmentNotes.encryptedData,
        record.treatmentNotes.iv,
        record.treatmentNotes.authTag
      )
    };
  }
}
Enter fullscreen mode Exit fullscreen mode

Audit Controls Implementation

Comprehensive Audit Logging

Your API needs a record of who accessed PHI, what they did, when it occurred, and whether the action succeeded.

const winston = require('winston');

const auditLogger = winston.createLogger({
  level: 'info',
  format: winston.format.combine(
    winston.format.timestamp(),
    winston.format.json()
  ),
  transports: [
    new winston.transports.File({
      filename: '/var/log/hipaa-audit/audit.log',
      maxsize: 52428800,
      maxFiles: 365
    }),
    new winston.transports.Http({
      host: 'siem.internal',
      path: '/api/logs',
      ssl: true
    })
  ]
});
Enter fullscreen mode Exit fullscreen mode

Use a single audit-log function so every route produces consistent events:

const auditLog = async (event, details) => {
  const logEntry = {
    timestamp: new Date().toISOString(),
    event,
    actor: details.userId,
    action: details.action,
    resource: details.resource,
    outcome: details.outcome || 'SUCCESS',
    ipAddress: details.ip,
    userAgent: details.userAgent,
    details: details.metadata
  };

  auditLogger.info(logEntry);
  await db.auditLogs.insert(logEntry);
};
Enter fullscreen mode Exit fullscreen mode

Add middleware that captures PHI-related endpoint activity:

app.use((req, res, next) => {
  const start = Date.now();

  res.on('finish', async () => {
    const duration = Date.now() - start;
    const isPHIEndpoint =
      req.path.includes('/patients') || req.path.includes('/records');

    if (!isPHIEndpoint) return;

    await auditLog('API_ACCESS', {
      userId: req.user?.id || 'anonymous',
      action: req.method,
      resource: req.path,
      outcome: res.statusCode < 400 ? 'SUCCESS' : 'FAILURE',
      ip: req.ip,
      userAgent: req.headers['user-agent'],
      metadata: {
        duration,
        statusCode: res.statusCode,
        queryParams: Object.keys(req.query)
      }
    });
  });

  next();
});
Enter fullscreen mode Exit fullscreen mode

Avoid putting unnecessary PHI in logs. Log identifiers and event metadata needed for investigation, but do not log complete patient records, access tokens, passwords, or sensitive request bodies.

Required Audit Events

Event type What to log Retention
Authentication Success/failure, MFA status, IP 6 years
Authorization Denied access attempts 6 years
PHI access Who accessed what and when 6 years
PHI modification Before/after values 6 years
PHI deletion What was deleted and by whom 6 years
System changes Configuration changes, new users 6 years
Security events Failed requests, rate limits 6 years

Audit Report Generation

Generate reports that compliance teams can review without manually querying raw logs.

const generateAuditReport = async (startDate, endDate, options = {}) => {
  const query = {
    timestamp: {
      $gte: new Date(startDate),
      $lte: new Date(endDate)
    }
  };

  if (options.userId) {
    query.actor = options.userId;
  }

  if (options.eventType) {
    query.event = options.eventType;
  }

  const logs = await db.auditLogs.find(query).sort({ timestamp: 1 });

  return {
    reportPeriod: { start: startDate, end: endDate },
    generatedAt: new Date().toISOString(),
    summary: {
      totalEvents: logs.length,
      uniqueUsers: new Set(logs.map(log => log.actor)).size,
      failures: logs.filter(log => log.outcome === 'FAILURE').length,
      phiAccess: logs.filter(log => log.event === 'PHI_ACCESS').length
    },
    events: logs
  };
};
Enter fullscreen mode Exit fullscreen mode

Schedule weekly reporting:

cron.schedule('0 0 * * 1', async () => {
  const end = new Date();
  const start = new Date(end.getTime() - 7 * 24 * 60 * 60 * 1000);

  const report = await generateAuditReport(start, end);
  await sendToComplianceTeam(report);
});
Enter fullscreen mode Exit fullscreen mode

API Security Best Practices

Input Validation

Validate every path parameter, query parameter, header, and request body field. Do not pass client input directly into database queries.

const {
  body,
  param,
  validationResult
} = require('express-validator');

const validatePatientRequest = [
  body('firstName')
    .trim()
    .notEmpty()
    .matches(/^[a-zA-Z\s'-]+$/)
    .withMessage('Invalid first name format')
    .isLength({ max: 50 }),

  body('dateOfBirth')
    .isISO8601()
    .withMessage('Invalid date format')
    .custom(value => new Date(value) < new Date())
    .withMessage('Date of birth must be in the past'),

  body('ssn')
    .optional()
    .matches(/^\d{3}-\d{2}-\d{4}$/)
    .withMessage('Invalid SSN format'),

  body('email')
    .optional()
    .isEmail()
    .normalizeEmail(),

  param('id')
    .isUUID()
    .withMessage('Invalid patient ID format'),

  (req, res, next) => {
    const errors = validationResult(req);

    if (!errors.isEmpty()) {
      return res.status(400).json({
        error: 'Validation failed',
        details: errors.array()
      });
    }

    next();
  }
];
Enter fullscreen mode Exit fullscreen mode

Rate Limiting

Apply stricter limits to authentication endpoints and broader limits to general API routes.

const rateLimit = require('express-rate-limit');

const authLimiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 5,
  message: { error: 'Too many authentication attempts' },
  standardHeaders: true,
  legacyHeaders: false,
  handler: async (req, res) => {
    await auditLog('RATE_LIMIT_EXCEEDED', {
      userId: req.body.username,
      ip: req.ip,
      endpoint: 'auth'
    });

    res.status(429).json({ error: 'Too many attempts' });
  }
});

const apiLimiter = rateLimit({
  windowMs: 60 * 1000,
  max: 100,
  message: { error: 'Rate limit exceeded' }
});

app.use('/api/auth', authLimiter);
app.use('/api', apiLimiter);
Enter fullscreen mode Exit fullscreen mode

Error Handling

Return generic client errors and log diagnostic details internally. Never include PHI or implementation details in error responses.

app.use((err, req, res, next) => {
  console.error('Error:', {
    message: err.message,
    stack: err.stack,
    path: req.path,
    user: req.user?.id
  });

  res.status(err.status || 500).json({
    error: 'An error occurred processing your request',
    requestId: req.id
  });
});
Enter fullscreen mode Exit fullscreen mode

Never expose the following in API errors:

  • Stack traces
  • Database schema details
  • Internal IP addresses
  • User counts
  • PHI
  • Access tokens or secrets

Common HIPAA API Violations and How to Avoid Them

Violation: Inadequate Access Controls

Scenario: Any authenticated user can retrieve any patient record.

// BAD: Authentication alone does not authorize access
app.get('/api/patients/:id', async (req, res) => {
  const patient = await db.patients.findById(req.params.id);
  res.json(patient);
});
Enter fullscreen mode Exit fullscreen mode

Fix: Verify that the requester owns the record or has a documented provider relationship with the patient.

app.get('/api/patients/:id', async (req, res) => {
  const patient = await db.patients.findById(req.params.id);

  // Patient accesses their own record
  if (req.user.id === patient.userId) {
    return res.json(patient);
  }

  // Provider accesses an assigned patient's record
  const assignment = await db.providerAssignments.findOne({
    providerId: req.user.id,
    patientId: patient.id
  });

  if (assignment) {
    return res.json(patient);
  }

  await auditLog('UNAUTHORIZED_ACCESS_ATTEMPT', {
    userId: req.user.id,
    patientId: patient.id
  });

  res.status(403).json({ error: 'Access denied' });
});
Enter fullscreen mode Exit fullscreen mode

Violation: Missing Audit Logs

Scenario: There is no record of who accessed patient data.

Fix: Record all PHI access, authorization failures, changes, deletions, and security events. Store logs in append-only storage and retain them for six years.

Violation: Unencrypted Data Transmission

Scenario: The API accepts plain HTTP connections.

Fix: Require HTTPS and add HSTS.

app.use((req, res, next) => {
  if (!req.secure && process.env.NODE_ENV === 'production') {
    return res.status(403).json({
      error: `HTTPS required. Connect via https://${req.headers.host}`
    });
  }

  res.setHeader(
    'Strict-Transport-Security',
    'max-age=31536000; includeSubDomains'
  );

  next();
});
Enter fullscreen mode Exit fullscreen mode

Violation: Excessive Data Exposure

Scenario: An endpoint returns a complete patient record when the client only needs a name.

Fix: Use field-level filtering and a safe projection.

app.get('/api/patients/:id', async (req, res) => {
  const fields = req.query.fields?.split(',') || ['id', 'name'];
  const projection = Object.fromEntries(fields.map(field => [field, 1]));

  const patient = await db.patients.findById(req.params.id, projection);
  res.json(patient);
});
Enter fullscreen mode Exit fullscreen mode

In production, validate fields against an allowlist before building the projection.

Production Deployment Checklist

Before handling live PHI:

  • [ ] Execute BAAs with all vendors
  • [ ] Implement MFA for all users
  • [ ] Enable TLS 1.3 for all endpoints
  • [ ] Encrypt PHI at rest with AES-256
  • [ ] Implement comprehensive audit logging
  • [ ] Configure audit-log retention for 6+ years
  • [ ] Configure RBAC and resource-level authorization
  • [ ] Implement rate limiting
  • [ ] Create an incident-response plan
  • [ ] Document all security controls
  • [ ] Conduct a security risk assessment
  • [ ] Train staff on HIPAA requirements
  • [ ] Schedule regular security audits

HIPAA Security Risk Assessment Template

System Overview

  • System name: [API Name]
  • PHI types handled: [List]
  • Data flow: [Diagram]

Threat Assessment

Threat Likelihood Impact Mitigation
Unauthorized access Medium High MFA, RBAC
Data breach Low Critical Encryption
Insider threat Medium High Audit logs

Control Testing

  • [ ] Authentication bypass test
  • [ ] Authorization bypass test
  • [ ] SQL injection test
  • [ ] XSS test
  • [ ] Encryption verification

Sign-off

Security Officer: _______________  Date: _______
CTO:              _______________  Date: _______
Enter fullscreen mode Exit fullscreen mode

Real-World Use Cases

Telemedicine Platform API

A telehealth startup builds HIPAA-compliant video consultations.

  • Challenge: Secure transmission of patient-provider video calls
  • Solution: End-to-end encrypted WebRTC with a HIPAA-compliant signaling API
  • Result: SOC 2 Type II certified, 500K+ consultations without breach

Key implementation details:

  • JWT authentication with MFA
  • Ephemeral room tokens that expire after a consultation
  • No PHI stored in logs
  • BAA with Twilio for video infrastructure

Patient Portal API

A hospital system modernizes patient access.

  • Challenge: More than 20 legacy systems with inconsistent security
  • Solution: A unified API gateway with centralized authentication and auditing
  • Result: A single source of truth and simplified compliance reporting

Key implementation details:

  • OAuth 2.0 with SMART on FHIR
  • Centralized audit logging
  • Field-level access control
  • Automated breach detection

Health Data Integration Platform

A health technology company aggregates data from multiple EHRs.

  • Challenge: Different security models across EHR vendors
  • Solution: An abstraction layer with uniform HIPAA controls
  • Result: More than 100 hospital integrations and zero compliance findings

Key implementation details:

  • Data normalization with consistent encryption
  • Per-tenant audit trails
  • Automated BAA tracking
  • Real-time compliance dashboards

Conclusion

HIPAA compliance for APIs requires deliberate architecture decisions around authentication, encryption, authorization, and audit logging.

Use this implementation checklist as your baseline:

  • Execute BAAs with all vendors before handling PHI.
  • Require MFA and implement role-based access control.
  • Verify resource-level authorization for every PHI request.
  • Encrypt data in transit with TLS 1.3 and at rest with AES-256.
  • Log PHI access and retain audit records for six years.
  • Apply the minimum necessary standard to every endpoint.
  • Use Apidog to streamline API documentation and compliance workflows.

FAQ

What makes an API HIPAA-compliant?

An API is HIPAA-compliant when it implements the technical safeguards required to protect ePHI, including encryption, access controls, and audit logging. It must also support required administrative safeguards such as policies, staff training, and BAAs, plus applicable physical safeguards.

Do I need a BAA for my API?

Yes. If your API handles, processes, or stores PHI on behalf of a covered entity, you are a Business Associate and must sign a BAA. This also applies to cloud providers, API services, and subprocessors that handle PHI.

What encryption is required for HIPAA?

HIPAA requires encryption in transit and at rest. Use TLS 1.3 for API communication and AES-256 for stored data. Although encryption is technically addressable in the Security Rule, it is effectively required for compliance.

How long must HIPAA audit logs be retained?

HIPAA requires audit logs to be retained for six years from the date they were created or when the record was last in effect, whichever is later.

Can I use JWT for HIPAA-compliant authentication?

Yes. JWTs can be used when implemented securely: use short expiration periods, secure token storage, and refresh-token rotation. Combine JWT-based authentication with MFA for production systems that access PHI.

What is the minimum necessary standard?

The minimum necessary standard requires an API to expose only the PHI required for the intended purpose. Implement field-level filtering and purpose-based access controls to enforce it.

Do audit logs need to be encrypted?

Yes. Audit logs containing PHI should be encrypted at rest. Store them in append-only storage to help prevent tampering.

How do I handle breach notification?

If unauthorized PHI access occurs:

  1. Contain the breach.
  2. Assess risk using the four-factor test.
  3. Notify affected individuals within 60 days.
  4. Notify HHS immediately for breaches affecting 500 or more individuals.
  5. Document the incident, assessment, and mitigation steps.

Can I use cloud services for HIPAA workloads?

Yes, if the provider signs a BAA. AWS, GCP, and Azure offer HIPAA-eligible services. Configure each service according to the provider's HIPAA implementation guidance.

What penalties exist for HIPAA violations?

Civil penalties range from $100 to $50,000 per violation, with annual maximums of $1.5 million per violation category. Criminal penalties can include fines up to $250,000 and imprisonment for up to 10 years.

Top comments (0)