{"id":21423,"library":"hades-auth","title":"Hades Auth","description":"Hades Auth is a client-side authentication library (v1.0.63) that uses elliptic-curve cryptography (ECDSA with P-384) for public/private key identity. It provides functions to generate key pairs, onboard devices, sign requests, and wrap fetch calls with signed headers. Unlike token-based auth (JWT/sessions), it never sends secrets to the server; only public keys are stored, making database leaks less catastrophic. The library is ESM-only, ships TypeScript definitions, and is actively released on npm. It is designed for browser use (uses Web Crypto API) and includes a fetch wrapper that automates request signing. The package is maintained by OracularHades.","status":"active","version":"1.0.63","language":"javascript","source_language":"en","source_url":null,"tags":["javascript","authentication","auth","elliptic","public key","private key","signing","oracularhades","identity","typescript"],"install":[{"cmd":"npm install hades-auth","lang":"bash","label":"npm"},{"cmd":"yarn add hades-auth","lang":"bash","label":"yarn"},{"cmd":"pnpm add hades-auth","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"The package is ESM-only; require() will throw ERR_REQUIRE_ESM. Use dynamic import() if needed in CommonJS.","wrong":"const { generate_new_credentials } = require('hades-auth')","symbol":"generate_new_credentials","correct":"import { generate_new_credentials } from 'hades-auth'"},{"note":"Sign data (string or object) using your private key. Returns a Promise with the signature.","symbol":"sign","correct":"import { sign } from 'hades-auth'"},{"note":"Wraps fetch() to automatically add signed headers. Parameters: url, options, deviceId, privateKey.","symbol":"fetch_wrapper","correct":"import { fetch_wrapper } from 'hades-auth'"},{"note":"Server-side function to verify a public key and generate a device ID. Throws if key is invalid.","symbol":"onboard_new_device","correct":"import { onboard_new_device } from 'hades-auth'"},{"note":"Default export is an object containing all exports. Avoid namespace import; it may break tree-shaking.","wrong":"import * as hadesAuth from 'hades-auth'","symbol":"default","correct":"import hadesAuth from 'hades-auth'"}],"quickstart":{"code":"import { generate_new_credentials, onboard_new_device, fetch_wrapper } from 'hades-auth';\n\n// Client: generate key pair\nasync function register() {\n  const creds = await generate_new_credentials();\n  localStorage.setItem('private_key', creds.private_key);\n  // Send public_key to server\n  const response = await fetch('/api/register', {\n    method: 'POST',\n    headers: { 'Content-Type': 'application/json' },\n    body: JSON.stringify({ public_key: creds.public_key })\n  });\n  const { device_id } = await response.json();\n  localStorage.setItem('device_id', device_id);\n}\n\n// Server: verify public key\n// (in an Express-like handler)\napp.post('/api/register', async (req, res) => {\n  try {\n    const verification = await onboard_new_device(req.body.public_key);\n    // Store public_key with verification.deviceid (or custom ID)\n    res.json({ device_id: verification.deviceid });\n  } catch (e) {\n    res.status(400).json({ error: 'Invalid key' });\n  }\n});\n\n// Client: signed request\nasync function fetchData() {\n  const privateKey = localStorage.getItem('private_key');\n  const deviceId = localStorage.getItem('device_id');\n  const response = await fetch_wrapper('https://api.example.com/data', {\n    method: 'GET',\n    headers: { 'Content-Type': 'application/json' }\n  }, deviceId, privateKey);\n  return response.json();\n}","lang":"typescript","description":"Shows full flow: generate key pair client-side, register public key on server via onboard_new_device, store keys, then make signed requests using fetch_wrapper."},"warnings":[{"fix":"Use import syntax in your project; if you cannot switch to ESM, use dynamic import() with await or promise.","message":"Package is ESM-only. Using require() will cause ERR_REQUIRE_ESM. Must use import or dynamic import().","severity":"breaking","affected_versions":">=1.0.0"},{"fix":"Explicitly set 'Content-Type': 'application/json' in fetch options when sending JSON.","message":"When using fetch_wrapper with Express and JSON body parser, you must set Content-Type to application/json. Otherwise Express treats body as empty.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"N/A","message":"No functions are deprecated yet. Always check changelog.","severity":"deprecated","affected_versions":">=0.0.0"},{"fix":"Always store and retrieve the private_key string exactly as produced by generate_new_credentials.","message":"Private key must be in PEM format as returned by generate_new_credentials. Passing an incorrect format will cause signing to fail silently or throw.","severity":"gotcha","affected_versions":">=1.0.0"}],"env_vars":null,"last_verified":"2026-04-27T00:00:00.000Z","next_check":"2026-07-26T00:00:00.000Z","problems":[{"fix":"Replace require('hades-auth') with import ... from 'hades-auth' or use dynamic import('hades-auth').","cause":"Using require() on an ESM-only package.","error":"Error [ERR_REQUIRE_ESM]: require() of ES Module /path/to/node_modules/hades-auth/src/index.js from /path/to/your/file.js not supported."},{"fix":"Use import { fetch_wrapper } from 'hades-auth'.","cause":"Attempted to use fetch_wrapper as a default or incorrect import. The package exports named exports.","error":"TypeError: fetch_wrapper is not a function"},{"fix":"Ensure you are passing the exact string returned by generate_new_credentials or stored properly.","cause":"Private key or public key passed to sign/onboard is not a valid PEM string or is malformed.","error":"Uncaught (in promise) TypeError: Failed to execute 'importKey' on 'SubtleCrypto': parameter 2 is not of type 'ArrayBuffer'."}],"ecosystem":"npm","meta_description":null,"install_score":null,"install_tag":null,"quickstart_score":null,"quickstart_tag":null}