bro-auth 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,33 @@
1
+ ┌──────────────────────────────────────────────────────────────┐
2
+ │ █▄▄ █▀█ █▀█  ▄▀█ █░█ ▀█▀ █░█ bro-auth │
3
+ │ █▄█ █▀▄ █▄█   █▀█ █▀█ ░█░ █▀█ │
4
+ ├──────────────────────────────────────────────────────────────┤
5
+ │ Stateless JWT · Device Fingerprinting · Zero Replay │
6
+ └──────────────────────────────────────────────────────────────┘
7
+
8
+ # bro-auth
9
+ A lightweight, **stateless**, and **high-security** authentication layer using:
10
+
11
+ ✅ JWT access tokens
12
+ ✅ Refresh tokens
13
+ ✅ Device fingerprint binding (prevents stolen-token replay)
14
+ ✅ No database required
15
+
16
+ bro-auth aims to provide **DPoP-inspired protection** without the complexity.
17
+
18
+ ---
19
+
20
+ ## 🚀 Features
21
+
22
+ - 🔐 **Stateless JWT authentication**
23
+ - 🆔 **Device fingerprint binding** (SHA-256 hashed)
24
+ - 🚫 **Replay attack protection** (tokens tied to a specific browser)
25
+ - ⚡ Lightweight, zero dependencies except `jsonwebtoken` + `crypto-es`
26
+ - 🧩 Works with ANY backend (Next.js, Express, Node HTTP)
27
+ - 🌐 Browser module provided for fingerprint extraction
28
+ - 📦 Ready for NPM consumption
29
+
30
+ ---
31
+
32
+ ## 📦 Installation
33
+
package/dist/index.cjs ADDED
@@ -0,0 +1,76 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __export = (target, all) => {
6
+ for (var name in all)
7
+ __defProp(target, name, { get: all[name], enumerable: true });
8
+ };
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
+
19
+ // src/browser/index.js
20
+ var index_exports = {};
21
+ __export(index_exports, {
22
+ getFingerprint: () => getFingerprint
23
+ });
24
+ module.exports = __toCommonJS(index_exports);
25
+
26
+ // src/browser/fingerprint.js
27
+ var import_crypto_es = require("crypto-es");
28
+ async function getCanvasFingerprint() {
29
+ try {
30
+ const canvas = document.createElement("canvas");
31
+ const ctx = canvas.getContext("2d");
32
+ ctx.textBaseline = "top";
33
+ ctx.font = "14px 'Arial'";
34
+ ctx.fillStyle = "#f60";
35
+ ctx.fillRect(0, 0, 100, 20);
36
+ ctx.fillStyle = "#000";
37
+ ctx.fillText("bro-auth-fingerprint", 2, 15);
38
+ return canvas.toDataURL();
39
+ } catch {
40
+ return "no-canvas";
41
+ }
42
+ }
43
+ function getGPUFingerprint() {
44
+ try {
45
+ const canvas = document.createElement("canvas");
46
+ const gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
47
+ if (!gl) return "no-webgl";
48
+ const debugInfo = gl.getExtension("WEBGL_debug_renderer_info");
49
+ return debugInfo ? gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL) : "no-renderer";
50
+ } catch {
51
+ return "no-webgl";
52
+ }
53
+ }
54
+ async function getFingerprint() {
55
+ const components = {
56
+ userAgent: navigator.userAgent,
57
+ platform: navigator.platform,
58
+ language: navigator.language,
59
+ languages: navigator.languages.join(","),
60
+ screen: `${screen.width}x${screen.height}`,
61
+ colorDepth: screen.colorDepth,
62
+ timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
63
+ timezoneOffset: (/* @__PURE__ */ new Date()).getTimezoneOffset(),
64
+ cpuCores: navigator.hardwareConcurrency || "unknown",
65
+ deviceMemory: navigator.deviceMemory || "unknown",
66
+ gpu: getGPUFingerprint(),
67
+ canvas: await getCanvasFingerprint()
68
+ };
69
+ const rawString = Object.values(components).join("|");
70
+ const fpHash = (0, import_crypto_es.SHA256)(rawString).toString();
71
+ return {
72
+ raw: rawString,
73
+ hash: fpHash,
74
+ components
75
+ };
76
+ }
package/dist/index.js ADDED
@@ -0,0 +1,54 @@
1
+ // src/browser/fingerprint.js
2
+ import { SHA256 } from "crypto-es";
3
+ async function getCanvasFingerprint() {
4
+ try {
5
+ const canvas = document.createElement("canvas");
6
+ const ctx = canvas.getContext("2d");
7
+ ctx.textBaseline = "top";
8
+ ctx.font = "14px 'Arial'";
9
+ ctx.fillStyle = "#f60";
10
+ ctx.fillRect(0, 0, 100, 20);
11
+ ctx.fillStyle = "#000";
12
+ ctx.fillText("bro-auth-fingerprint", 2, 15);
13
+ return canvas.toDataURL();
14
+ } catch {
15
+ return "no-canvas";
16
+ }
17
+ }
18
+ function getGPUFingerprint() {
19
+ try {
20
+ const canvas = document.createElement("canvas");
21
+ const gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
22
+ if (!gl) return "no-webgl";
23
+ const debugInfo = gl.getExtension("WEBGL_debug_renderer_info");
24
+ return debugInfo ? gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL) : "no-renderer";
25
+ } catch {
26
+ return "no-webgl";
27
+ }
28
+ }
29
+ async function getFingerprint() {
30
+ const components = {
31
+ userAgent: navigator.userAgent,
32
+ platform: navigator.platform,
33
+ language: navigator.language,
34
+ languages: navigator.languages.join(","),
35
+ screen: `${screen.width}x${screen.height}`,
36
+ colorDepth: screen.colorDepth,
37
+ timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
38
+ timezoneOffset: (/* @__PURE__ */ new Date()).getTimezoneOffset(),
39
+ cpuCores: navigator.hardwareConcurrency || "unknown",
40
+ deviceMemory: navigator.deviceMemory || "unknown",
41
+ gpu: getGPUFingerprint(),
42
+ canvas: await getCanvasFingerprint()
43
+ };
44
+ const rawString = Object.values(components).join("|");
45
+ const fpHash = SHA256(rawString).toString();
46
+ return {
47
+ raw: rawString,
48
+ hash: fpHash,
49
+ components
50
+ };
51
+ }
52
+ export {
53
+ getFingerprint
54
+ };
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "bro-auth",
3
+ "version": "0.1.0",
4
+ "description": "bro-auth — Stateless, fingerprint-bound JWT authentication. Server utilities + browser fingerprinting module.",
5
+ "type": "module",
6
+ "main": "dist/index.cjs",
7
+ "module": "dist/index.mjs",
8
+ "browser": "dist/browser.mjs",
9
+ "exports": {
10
+ ".": {
11
+ "import": "./dist/index.js",
12
+ "require": "./dist/index.cjs"
13
+ },
14
+ "./browser": {
15
+ "import": "./dist/browser.js",
16
+ "require": "./dist/browser.cjs"
17
+ }
18
+ }
19
+ ,
20
+ "files": [
21
+ "dist/",
22
+ "README.md",
23
+ "LICENSE"
24
+ ],
25
+ "scripts": {
26
+ "clean": "rimraf dist",
27
+ "build:server": "tsup src/core/index.js --format cjs,esm --no-dts --out-dir dist",
28
+ "build:browser": "tsup src/browser/index.js --format cjs,esm --no-dts --out-dir dist --platform browser",
29
+ "build": "npm run clean && npm run build:server && npm run build:browser",
30
+ "prepack": "npm run build",
31
+ "test": "node --input-type=module -e \"import * as core from './dist/index.js'; console.log('core exports:', Object.keys(core));\""
32
+ },
33
+ "keywords": [
34
+ "jwt",
35
+ "authentication",
36
+ "browser fingerprint",
37
+ "token binding",
38
+ "security",
39
+ "bro-auth",
40
+ "auth"
41
+ ],
42
+ "author": "Vaishnav",
43
+ "license": "MIT",
44
+ "dependencies": {
45
+ "crypto-es": "^3.1.2",
46
+ "jsonwebtoken": "^9.0.2"
47
+ },
48
+ "devDependencies": {
49
+ "rimraf": "^5.0.10",
50
+ "tsup": "^8.5.1",
51
+ "typescript": "^5.9.3"
52
+ }
53
+ }