← Debugging Guides

阅读中文版本

crypto.subtle Is Undefined — Secure Context Required

Fix crypto.subtle being undefined by serving over HTTPS or localhost, since the Web Crypto API is restricted to secure contexts.

intermediatedebuggingbrowsercryptosecure-context

Symptoms

  • TypeError: Cannot read properties of undefined (reading 'digest')
  • Web Crypto works locally but not on the staging server
  • An app served over plain http:// cannot hash or encrypt

Possible causes

  • The page is not a secure context (HTTP origin other than localhost)
  • The code accesses window.crypto.subtle without a feature check
  • An old or embedded browser lacks Web Crypto support

Diagnosis steps

Check the secure-context flag

console.log(window.isSecureContext, window.crypto?.subtle)

Interpretation

isSecureContext false or subtle undefined confirms the environment, not your code.

Serve over HTTPS or localhost

openssl req -x509 -newkey rsa:2048 -nodes -keyout key.pem -out cert.pem -days 1

Interpretation

A quick self-signed cert makes the origin secure so subtle becomes available.

Root cause

The Web Crypto API exposes crypto.subtle only in secure contexts (HTTPS, localhost, or file). On an insecure origin, window.crypto exists for getRandomValues but subtle is undefined, so calls throw.

Fix

Serve the app over HTTPS in all non-local environments, feature-detect crypto.subtle before use, and provide a server-side fallback when the API is unavailable.

Risk note

Falling back to a non-cryptographic hash for security purposes is dangerous; only fall back for non-security uses.

Verify the fix

Load the page over HTTPS and confirm isSecureContext is true and crypto.subtle.digest resolves; test that HTTP origins still show a clear fallback message.

Symptoms

This guide profiles the failure behind “crypto.subtle Is Undefined — Secure Context Required”. It walks through the observable symptoms, a reproducible diagnosis path, the underlying root cause, the concrete fix, and how to verify the change and prevent a regression.

Observed symptoms include:

  • TypeError: Cannot read properties of undefined (reading ‘digest’)
  • Web Crypto works locally but not on the staging server
  • An app served over plain http:// cannot hash or encrypt

Reproduce and Diagnose

Reproduce the failure in isolation before changing any code. Work through the checks below in order; each one narrows the search space.

Step 1: Check the secure-context flag

console.log(window.isSecureContext, window.crypto?.subtle)

isSecureContext false or subtle undefined confirms the environment, not your code.

Step 2: Serve over HTTPS or localhost

openssl req -x509 -newkey rsa:2048 -nodes -keyout key.pem -out cert.pem -days 1

A quick self-signed cert makes the origin secure so subtle becomes available.

Likely contributors, in order of frequency:

  • The page is not a secure context (HTTP origin other than localhost)
  • The code accesses window.crypto.subtle without a feature check
  • An old or embedded browser lacks Web Crypto support

Root Cause

The Web Crypto API exposes crypto.subtle only in secure contexts (HTTPS, localhost, or file). On an insecure origin, window.crypto exists for getRandomValues but subtle is undefined, so calls throw.

The Fix

Serve the app over HTTPS in all non-local environments, feature-detect crypto.subtle before use, and provide a server-side fallback when the API is unavailable.

Watch out: Falling back to a non-cryptographic hash for security purposes is dangerous; only fall back for non-security uses.

if (window.isSecureContext && window.crypto?.subtle) {
  const enc = new TextEncoder();
  const hash = await crypto.subtle.digest('SHA-256', enc.encode('data'));
  console.log([...new Uint8Array(hash)].map((b) => b.toString(16).padStart(2, '0')).join(''));
} else {
  // secure context required; fall back or ask the user to use HTTPS
  console.warn('crypto.subtle unavailable: secure context required');
}

Verify and Prevent

Load the page over HTTPS and confirm isSecureContext is true and crypto.subtle.digest resolves; test that HTTP origins still show a clear fallback message.

Once verified, add a regression test that reproduces the original symptom so the failure cannot silently return.

This class of failure is usually environmental rather than pure logic, so capture the exact command, the environment variables, and the working directory in your bug report. Reproduce it in the smallest possible script, then widen the scope only once the minimal case is understood. A short written checklist for this failure mode saves hours the next time it appears.