Updating to the latest version

Updating to the latest version

Mise à jour vers la dernière version

Actualizando a la última versión

Aktualisierung auf die neueste Version

API Authentication

External Client Authentication

Use session-v2 wallet authentication when building scripts, services, and other external clients against the 6529 API.

What to use

New external clients should authenticate through session-v2 endpoints. The standard external-client mode is client_type=native, even when the client is a command-line script or backend service controlled by the wallet owner.

The older nonce, login, and redeem-refresh-token endpoints remain compatibility endpoints for older clients. New integrations should not start on those legacy endpoints.

Login flow

  1. Request a signable message with signer_address, client_type=native, and chain_id=1 from GET /api/auth/session-nonce.
  2. Sign the returned message exactly as returned in signable_message.
  3. Send client_type, client_address, client_signature, server_signature, and optional role to POST /api/auth/session-login.
  4. Use the returned access_token on protected API calls as Authorization: Bearer <access_token>.

Refresh and logout

Native/script login returns an access_token for bearer auth plus a native_refresh_token and refresh_token_expires_at for long-running clients.

Refresh through POST /api/auth/session-refresh with client_type=native, client_address, and the current native_refresh_token. A successful refresh rotates the native refresh token, so replace the stored token with the new one immediately.

Logout through POST /api/auth/session-logout with client_type=native, client_address, the current native_refresh_token, and all_sessions=false unless you intend to revoke every session for that wallet.

Browser clients

This guide is for external clients. First-party browser sessions also use session-v2, but browser refresh state is handled with backend-owned HttpOnly cookies, credentials-included requests, and origin checks. Follow the app implementation rather than adapting the native/script examples directly for browser sessions.

Security rules

  • Sign only signable_message exactly as returned. Do not trim, normalize, rebuild, JSON-stringify, or sign a nonce field.
  • Do not log private keys, access tokens, refresh tokens, signatures, or raw authentication responses. Store refresh tokens in a secret store appropriate for the client environment.
  • Check response status codes before trusting JSON payloads, and treat authentication errors as requiring a fresh wallet signature or a clean re-login.

Node.js examples

This example requests a native session-v2 challenge, signs it, calls a protected endpoint with bearer auth, refreshes the session, and logs out.

import { Wallet } from "ethers";
import fetch from "node-fetch";

const API_BASE = "https://api.6529.io/api";

async function assertOk(response, label) {
  if (!response.ok) {
    throw new Error(`${label} failed with HTTP ${response.status}`);
  }
}

export async function loginAndFetchFeed() {
  const clientAddress = "0x...";
  const clientPrivateKey = "0x..."; // Never hardcode private keys in production.
  const wallet = new Wallet(clientPrivateKey);

  const nonceResp = await fetch(
    `${API_BASE}/auth/session-nonce?signer_address=${clientAddress}&client_type=native&chain_id=1`,
    { headers: { accept: "application/json" } }
  );
  await assertOk(nonceResp, "session nonce");

  const { signable_message, server_signature } = await nonceResp.json();
  const clientSignature = await wallet.signMessage(signable_message);

  const loginResp = await fetch(`${API_BASE}/auth/session-login`, {
    method: "POST",
    headers: {
      accept: "application/json",
      "content-type": "application/json",
    },
    body: JSON.stringify({
      client_type: "native",
      client_address: clientAddress,
      client_signature: clientSignature,
      server_signature,
    }),
  });
  await assertOk(loginResp, "session login");

  const session = await loginResp.json();

  const feedResp = await fetch(`${API_BASE}/feed`, {
    headers: {
      accept: "application/json",
      authorization: `Bearer ${session.access_token}`,
    },
  });
  await assertOk(feedResp, "feed");

  return {
    session,
    feed: await feedResp.json(),
  };
}

export async function refreshNativeSession({ address, nativeRefreshToken }) {
  const response = await fetch(`${API_BASE}/auth/session-refresh`, {
    method: "POST",
    headers: {
      accept: "application/json",
      "content-type": "application/json",
    },
    body: JSON.stringify({
      client_type: "native",
      client_address: address,
      native_refresh_token: nativeRefreshToken,
    }),
  });
  await assertOk(response, "session refresh");

  const refreshedSession = await response.json();

  // Store refreshedSession.native_refresh_token over the previous refresh token.
  return refreshedSession;
}

export async function logoutNativeSession({ address, nativeRefreshToken }) {
  const response = await fetch(`${API_BASE}/auth/session-logout`, {
    method: "POST",
    headers: {
      accept: "application/json",
      "content-type": "application/json",
    },
    body: JSON.stringify({
      client_type: "native",
      client_address: address,
      native_refresh_token: nativeRefreshToken,
      all_sessions: false,
    }),
  });
  await assertOk(response, "session logout");
}