Ryanhub - file viewer
filename: html/api/services/register/read.md
branch: main
back to repo
registration endpoint using "proof of work"

paths:
GET /api/auth/challenge - request a challenge
POST /api/auth/submit - submit result to receive an API key

Challenge response example:
{
  "challenge": "b7c9e2a1...",
  "difficulty": 5,
  "expires": 1769611200
}

Client flow:
1. GET /api/auth/challenge - receive { challenge, difficulty, expires } 
2. find a nonce such that sha256(challenge + nonce) has difficulty leading hex zeros
3. POST /api/auth/submit:
   {
     "challenge": "...",
     "nonce": "...",
     "hash": "..."
   }
4. On success you'll receive { "api_key": "<key>" }

node.js (18+) client example:

import crypto from 'crypto';
const URL = "" // fill this

async function getChallenge() {
  const res = await fetch('URL/api/auth/challenge');
  return res.json();
}

async function submit(challenge, nonce, hash) {
  const res = await fetch('URL/api/auth/submit', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ challenge, nonce, hash }),
  });
  return res.json();
}

(async () => {
  const c = await getChallenge();
  console.log('challenge', c);

  const prefix = '0'.repeat(c.difficulty);
  let nonce = 0, hash;
  while (true) {
    hash = crypto.createHash('sha256').update(c.challenge + String(nonce)).digest('hex');
    if (hash.startsWith(prefix)) break;
    nonce++;
  }

  console.log('found nonce', nonce, hash.slice(0, 32) + '…');
  const result = await submit(c.challenge, String(nonce), hash);
  console.log('submit result:', result);
})();