bitcoincash-oauth-client 0.2.0 → 0.2.10

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/dist/index.cjs CHANGED
@@ -258,13 +258,14 @@ function getFetch(userProvidedFetch = null) {
258
258
  * @typedef {Object} Keypair
259
259
  * @property {string} privateKey - Hex-encoded private key
260
260
  * @property {string} publicKey - Hex-encoded compressed public key
261
- * @property {string} address - Bitcoin Cash address
261
+ * @property {string} bitcoincash_address - Bitcoin Cash address
262
262
  */
263
263
 
264
264
  /**
265
265
  * @typedef {Object} OAuthClientOptions
266
266
  * @property {string} [serverUrl="http://localhost:8000"] - OAuth server URL
267
267
  * @property {string} [network="mainnet"] - Network type ("mainnet" or "testnet")
268
+ * @property {string} [authBasePath="/auth"] - Base path for auth endpoints (e.g., "/auth" or "/bch-auth")
268
269
  * @property {SecureStorage} [secureStorage] - Storage interface for tokens
269
270
  * @property {Function} [fetch] - Custom fetch implementation (optional)
270
271
  * @property {string} [tokenKey="oauth_token"] - Key for storing access token
@@ -302,6 +303,7 @@ class BitcoinCashOAuthClient {
302
303
  constructor(options = {}) {
303
304
  this.serverUrl = options.serverUrl || "http://localhost:8000";
304
305
  this.network = options.network || "mainnet";
306
+ this.authBasePath = options.authBasePath || "/auth";
305
307
  this.secureStorage = options.secureStorage || null;
306
308
  this.fetchImpl = options.fetch || getFetch(options.fetch);
307
309
  this.secp256k1 = null;
@@ -372,14 +374,14 @@ class BitcoinCashOAuthClient {
372
374
  const publicKeyBytes = this.secp256k1.derivePublicKeyCompressed(privateKeyBytes);
373
375
 
374
376
  // Convert to address
375
- const address = await this.publicKeyToCashAddress(publicKeyBytes);
376
-
377
- this._log('Generated new keypair', { address });
377
+ const bitcoincash_address = await this.publicKeyToCashAddress(publicKeyBytes);
378
+
379
+ this._log('Generated new keypair', { bitcoincash_address });
378
380
 
379
381
  return {
380
382
  privateKey: this.bytesToHex(privateKeyBytes),
381
383
  publicKey: this.bytesToHex(publicKeyBytes),
382
- address,
384
+ bitcoincash_address,
383
385
  };
384
386
  }
385
387
 
@@ -433,40 +435,55 @@ class BitcoinCashOAuthClient {
433
435
  }
434
436
 
435
437
  /**
436
- * Register a new user with the server
437
- * @param {string} address - Bitcoin Cash address
438
- * @param {string} [userId] - Optional user-provided ID
438
+ * Register a new user with the server (signature required)
439
+ * @param {string} bitcoincash_address - Bitcoin Cash address
440
+ * @param {string} privateKeyHex - Private key for signing (hex-encoded)
441
+ * @param {string} publicKeyHex - Public key for signature verification (hex-encoded)
442
+ * @param {string} userId - User-provided ID (required)
443
+ * @param {number} [timestamp] - Optional Unix timestamp (defaults to now)
444
+ * @param {string} [domain] - Optional domain for message binding
439
445
  * @returns {Promise<Object>} Registration result with assigned userId
440
446
  * @throws {NetworkError} If network request fails
441
447
  * @throws {AuthenticationError} If registration fails
442
448
  */
443
- async register(address, userId = null) {
449
+ async register(bitcoincash_address, privateKeyHex, publicKeyHex, userId, timestamp = null, domain = null) {
444
450
  try {
445
- const response = await this.fetchImpl(`${this.serverUrl}/auth/register`, {
451
+ const ts = timestamp || Math.floor(Date.now() / 1000);
452
+ const host = domain || this._getDefaultDomain();
453
+ const message = this.createAuthMessage(userId, ts, host);
454
+ const signature = await this.signAuthMessage(message, privateKeyHex);
455
+
456
+ this._log('Registering user', { bitcoincash_address, userId, domain: host });
457
+
458
+ const response = await this.fetchImpl(`${this.serverUrl}${this.authBasePath}/register`, {
446
459
  method: "POST",
447
460
  headers: {
448
461
  "Content-Type": "application/json",
449
462
  },
450
463
  body: JSON.stringify({
451
- address,
464
+ bitcoincash_address,
452
465
  user_id: userId,
466
+ timestamp: ts,
467
+ domain: host,
468
+ public_key: publicKeyHex,
469
+ signature: signature,
453
470
  }),
454
471
  });
455
472
 
456
473
  if (!response.ok) {
457
474
  const errorData = await response.json().catch(() => ({}));
458
-
475
+
459
476
  if (response.status === 404) {
460
477
  throw new UserNotFoundError(errorData.detail || 'User not found');
461
478
  }
462
-
479
+
463
480
  throw new AuthenticationError(
464
481
  errorData.detail || `Registration failed: ${response.statusText}`,
465
482
  response.status
466
483
  );
467
484
  }
468
485
 
469
- this._log('User registered successfully', { address, userId });
486
+ this._log('User registered successfully', { bitcoincash_address, userId });
470
487
  return await response.json();
471
488
  } catch (error) {
472
489
  if (error instanceof OAuthError) {
@@ -534,7 +551,7 @@ class BitcoinCashOAuthClient {
534
551
  this._log('Message signed successfully');
535
552
 
536
553
  try {
537
- const response = await this.fetchImpl(`${this.serverUrl}/auth/token`, {
554
+ const response = await this.fetchImpl(`${this.serverUrl}${this.authBasePath}/token`, {
538
555
  method: "POST",
539
556
  headers: {
540
557
  "Content-Type": "application/json",
@@ -755,7 +772,7 @@ class BitcoinCashOAuthClient {
755
772
  if (serverCheck) {
756
773
  try {
757
774
  this._log('Token validation: checking with server');
758
- const response = await this.fetchImpl(`${this.serverUrl}/auth/verify`, {
775
+ const response = await this.fetchImpl(`${this.serverUrl}${this.authBasePath}/verify`, {
759
776
  method: "POST",
760
777
  headers: {
761
778
  "Authorization": `Bearer ${token}`,
@@ -835,7 +852,7 @@ class BitcoinCashOAuthClient {
835
852
  */
836
853
  async refreshToken(refreshToken) {
837
854
  try {
838
- const response = await this.fetchImpl(`${this.serverUrl}/auth/refresh`, {
855
+ const response = await this.fetchImpl(`${this.serverUrl}${this.authBasePath}/refresh`, {
839
856
  method: "POST",
840
857
  headers: {
841
858
  "Content-Type": "application/json",
@@ -904,7 +921,7 @@ class BitcoinCashOAuthClient {
904
921
  this.refreshTimer = null;
905
922
  }
906
923
 
907
- const response = await this.fetchImpl(`${this.serverUrl}/auth/revoke`, {
924
+ const response = await this.fetchImpl(`${this.serverUrl}${this.authBasePath}/revoke`, {
908
925
  method: "POST",
909
926
  headers: {
910
927
  "Content-Type": "application/json",
package/dist/index.mjs CHANGED
@@ -254,13 +254,14 @@ function getFetch(userProvidedFetch = null) {
254
254
  * @typedef {Object} Keypair
255
255
  * @property {string} privateKey - Hex-encoded private key
256
256
  * @property {string} publicKey - Hex-encoded compressed public key
257
- * @property {string} address - Bitcoin Cash address
257
+ * @property {string} bitcoincash_address - Bitcoin Cash address
258
258
  */
259
259
 
260
260
  /**
261
261
  * @typedef {Object} OAuthClientOptions
262
262
  * @property {string} [serverUrl="http://localhost:8000"] - OAuth server URL
263
263
  * @property {string} [network="mainnet"] - Network type ("mainnet" or "testnet")
264
+ * @property {string} [authBasePath="/auth"] - Base path for auth endpoints (e.g., "/auth" or "/bch-auth")
264
265
  * @property {SecureStorage} [secureStorage] - Storage interface for tokens
265
266
  * @property {Function} [fetch] - Custom fetch implementation (optional)
266
267
  * @property {string} [tokenKey="oauth_token"] - Key for storing access token
@@ -298,6 +299,7 @@ class BitcoinCashOAuthClient {
298
299
  constructor(options = {}) {
299
300
  this.serverUrl = options.serverUrl || "http://localhost:8000";
300
301
  this.network = options.network || "mainnet";
302
+ this.authBasePath = options.authBasePath || "/auth";
301
303
  this.secureStorage = options.secureStorage || null;
302
304
  this.fetchImpl = options.fetch || getFetch(options.fetch);
303
305
  this.secp256k1 = null;
@@ -368,14 +370,14 @@ class BitcoinCashOAuthClient {
368
370
  const publicKeyBytes = this.secp256k1.derivePublicKeyCompressed(privateKeyBytes);
369
371
 
370
372
  // Convert to address
371
- const address = await this.publicKeyToCashAddress(publicKeyBytes);
372
-
373
- this._log('Generated new keypair', { address });
373
+ const bitcoincash_address = await this.publicKeyToCashAddress(publicKeyBytes);
374
+
375
+ this._log('Generated new keypair', { bitcoincash_address });
374
376
 
375
377
  return {
376
378
  privateKey: this.bytesToHex(privateKeyBytes),
377
379
  publicKey: this.bytesToHex(publicKeyBytes),
378
- address,
380
+ bitcoincash_address,
379
381
  };
380
382
  }
381
383
 
@@ -429,40 +431,55 @@ class BitcoinCashOAuthClient {
429
431
  }
430
432
 
431
433
  /**
432
- * Register a new user with the server
433
- * @param {string} address - Bitcoin Cash address
434
- * @param {string} [userId] - Optional user-provided ID
434
+ * Register a new user with the server (signature required)
435
+ * @param {string} bitcoincash_address - Bitcoin Cash address
436
+ * @param {string} privateKeyHex - Private key for signing (hex-encoded)
437
+ * @param {string} publicKeyHex - Public key for signature verification (hex-encoded)
438
+ * @param {string} userId - User-provided ID (required)
439
+ * @param {number} [timestamp] - Optional Unix timestamp (defaults to now)
440
+ * @param {string} [domain] - Optional domain for message binding
435
441
  * @returns {Promise<Object>} Registration result with assigned userId
436
442
  * @throws {NetworkError} If network request fails
437
443
  * @throws {AuthenticationError} If registration fails
438
444
  */
439
- async register(address, userId = null) {
445
+ async register(bitcoincash_address, privateKeyHex, publicKeyHex, userId, timestamp = null, domain = null) {
440
446
  try {
441
- const response = await this.fetchImpl(`${this.serverUrl}/auth/register`, {
447
+ const ts = timestamp || Math.floor(Date.now() / 1000);
448
+ const host = domain || this._getDefaultDomain();
449
+ const message = this.createAuthMessage(userId, ts, host);
450
+ const signature = await this.signAuthMessage(message, privateKeyHex);
451
+
452
+ this._log('Registering user', { bitcoincash_address, userId, domain: host });
453
+
454
+ const response = await this.fetchImpl(`${this.serverUrl}${this.authBasePath}/register`, {
442
455
  method: "POST",
443
456
  headers: {
444
457
  "Content-Type": "application/json",
445
458
  },
446
459
  body: JSON.stringify({
447
- address,
460
+ bitcoincash_address,
448
461
  user_id: userId,
462
+ timestamp: ts,
463
+ domain: host,
464
+ public_key: publicKeyHex,
465
+ signature: signature,
449
466
  }),
450
467
  });
451
468
 
452
469
  if (!response.ok) {
453
470
  const errorData = await response.json().catch(() => ({}));
454
-
471
+
455
472
  if (response.status === 404) {
456
473
  throw new UserNotFoundError(errorData.detail || 'User not found');
457
474
  }
458
-
475
+
459
476
  throw new AuthenticationError(
460
477
  errorData.detail || `Registration failed: ${response.statusText}`,
461
478
  response.status
462
479
  );
463
480
  }
464
481
 
465
- this._log('User registered successfully', { address, userId });
482
+ this._log('User registered successfully', { bitcoincash_address, userId });
466
483
  return await response.json();
467
484
  } catch (error) {
468
485
  if (error instanceof OAuthError) {
@@ -530,7 +547,7 @@ class BitcoinCashOAuthClient {
530
547
  this._log('Message signed successfully');
531
548
 
532
549
  try {
533
- const response = await this.fetchImpl(`${this.serverUrl}/auth/token`, {
550
+ const response = await this.fetchImpl(`${this.serverUrl}${this.authBasePath}/token`, {
534
551
  method: "POST",
535
552
  headers: {
536
553
  "Content-Type": "application/json",
@@ -751,7 +768,7 @@ class BitcoinCashOAuthClient {
751
768
  if (serverCheck) {
752
769
  try {
753
770
  this._log('Token validation: checking with server');
754
- const response = await this.fetchImpl(`${this.serverUrl}/auth/verify`, {
771
+ const response = await this.fetchImpl(`${this.serverUrl}${this.authBasePath}/verify`, {
755
772
  method: "POST",
756
773
  headers: {
757
774
  "Authorization": `Bearer ${token}`,
@@ -831,7 +848,7 @@ class BitcoinCashOAuthClient {
831
848
  */
832
849
  async refreshToken(refreshToken) {
833
850
  try {
834
- const response = await this.fetchImpl(`${this.serverUrl}/auth/refresh`, {
851
+ const response = await this.fetchImpl(`${this.serverUrl}${this.authBasePath}/refresh`, {
835
852
  method: "POST",
836
853
  headers: {
837
854
  "Content-Type": "application/json",
@@ -900,7 +917,7 @@ class BitcoinCashOAuthClient {
900
917
  this.refreshTimer = null;
901
918
  }
902
919
 
903
- const response = await this.fetchImpl(`${this.serverUrl}/auth/revoke`, {
920
+ const response = await this.fetchImpl(`${this.serverUrl}${this.authBasePath}/revoke`, {
904
921
  method: "POST",
905
922
  headers: {
906
923
  "Content-Type": "application/json",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bitcoincash-oauth-client",
3
- "version": "0.2.0",
3
+ "version": "0.2.10",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/paytaca/bitcoincash-oauth.git"