跳到正文
Hacker News (official RSS)(github.com)·· 3 小時前精選AI 評分74

Arken 推出使用 secp256k1 金鑰的無密碼認證中介軟體

Show HN: Arken – Passwordless auth middleware using secp256k1 keys

AI 導讀

Arken 是一套使用 secp256k1 金鑰的無密碼認證中介軟體,讓 Web 伺服器不再儲存密碼或 Session。

  • 核心機制:使用者持有私鑰,伺服器只傳送一次性 nonce,客戶端簽名後回傳,伺服器驗證簽名並比對 DID。
推薦理由

此方案消除傳統密碼與 session,提供無縫且抗釣魚的身份驗證,並以 secp256k1 DID 為核心,開源且可直接整合至 Express 或 FastAPI 應用,降低開發與維運成本,同時保持高安全性與跨平臺可攜性。

正文 · 原文

Arken Auth

Passwordless authentication for web servers. No passwords. No sessions. Nothing to breach.

Live Demo → · npm · PyPI


The problem

Every auth system today asks your server to hold a secret — a password hash, a session token, an API key. That secret is a liability. It gets breached. It gets phished. It gets rotated on a schedule that nobody follows.

Arken Auth flips the model: the user holds the secret, the server holds nothing.


How it works

Client                              Server
  │                                   │
  ├── GET /protected ────────────────▶│
  │                                   │ (no auth header)
  │◀── 401 { challenge: { nonce } } ──┤
  │                                   │
  │   sign(nonce, privateKey)         │
  │                                   │
  ├── GET /protected ────────────────▶│
  │   Authorization: Signature        │
  │     did="did:key:z...",           │
  │     nonce="...",                  │
  │     signature="0x..."             │
  │                                   │ recover signer from sig
  │                                   │ compare to DID pubkey
  │◀── 200 { did: "did:key:z..." } ───┤
  1. Client requests a protected resource — server issues a one-time nonce
  2. Client signs the nonce with their private key (never leaves their device)
  3. Client sends the signature + their DID back to the server
  4. Server recovers the signer address from the signature and checks it matches the DID
  5. No password ever transmitted. No session stored. No database touched.

The cryptographic core is written in Rust and called via FFI from Node.js or Python.


Quickstart — Node.js

npm install arken-auth
const express = require('express');
const { arkenAuth } = require('arken-auth');

const app = express();

app.get('/protected', arkenAuth(), (req, res) => {
  res.json({ message: 'hello', did: req.user.did });
});

That's it. arkenAuth() handles the entire challenge-response cycle.


Quickstart — Python

pip install arken-auth
from fastapi import FastAPI, Depends
from arken_auth import ArkenAuth

app = FastAPI()
arken = ArkenAuth()

@app.get("/protected")
async def protected(did: str = Depends(arken)):
    return {"message": "hello", "did": did}

Client-side (browser or CLI)

Any client that can sign an Ethereum message works. In the browser with ethers.js:

// Generate a DID from a wallet
const wallet = ethers.Wallet.createRandom();
const did = walletToDid(wallet); // did:key:z...

// Step 1: get a challenge
const r1 = await fetch('/protected');
const { challenge: { nonce } } = await r1.json(); // 401

// Step 2: sign the nonce
const signature = await wallet.signMessage(ethers.utils.toUtf8Bytes(nonce));

// Step 3: authenticate
const r2 = await fetch('/protected', {
  headers: {
    Authorization: `Signature did="${did}",nonce="${nonce}",signature="${signature}"`
  }
});

What makes it different

Username/Password JWT / OAuth WebAuthn Arken Auth
Server stores secrets ✗ (hash) ✗ (secret) ✓ ✓
Works without accounts ✗ ✗ ✗ ✓
Portable identity ✗ ✗ ✗ ✓
No JS SDK required ✓ ✓ ✗ ✓
Language agnostic ✓ ✓ ✓ ✓
Phishing resistant ✗ ✗ ✓ ✓

The key difference from WebAuthn: your identity (did:key:z...) is portable. It travels with you across servers, apps, and devices. A WebAuthn credential is bound to a single origin. A DID is bound to nothing but your key.


Architecture

packages/
  arken-auth/          Node.js middleware (Express)
  arken-auth-py/       Python middleware (FastAPI)

arken-phase1-docker/workspace/
  rust-core/           Cryptographic engine (Rust)
    src/lib.rs         Challenge generation + signature verification
  node-wrapper/        Node.js FFI bindings (koffi)
  python-wrapper/      Python FFI bindings (ctypes)
  public/              Interactive demo UI

The Rust core exposes two functions over FFI:

  • generate_challenge_into — generates a random nonce, stores it server-side with a 60s TTL, returns JSON
  • verify_request_into — parses the auth header, validates the nonce, recovers the signer, checks against the DID

DID format

Arken uses did:key with secp256k1 keys (multicodec 0xe7 0x01), encoded as multibase base58btc (z prefix):

did:key:z[base58btc(0xe7 0x01 || compressed_pubkey)]

This is the W3C DID Key Method spec.


Requirements

  • Rust (for building the native library): curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
  • Node.js ≥ 18 (for the npm package)
  • Python ≥ 3.10 (for the pip package)

Status

Phase 1 — working middleware for Express and FastAPI. The cryptographic core is complete and tested.

What's next:

  • Prebuilt binaries (no Rust required to install)
  • Session/token layer (optional, for stateful apps)
  • did:web and did:pkh support
  • Browser extension wallet

License

MIT