---
name: laso-finance-auth
description: How an agent registers with Laso Finance and obtains API credentials. Read this before calling any authenticated Laso endpoint.
metadata:
  author: laso-finance
  mintlify-proj: lasofinance
  version: "1.0"
---

# auth.md

{/* LASO-DOCS-VERSION:START (auto-generated by scripts/generate-docs-version.js, do not edit) */}
_Docs version `cecfcbe45738`. This is a content hash of the Laso Finance agent docs. If it differs from the live version at https://laso.finance/.well-known/docs-version.json, your cached copy is stale. Refetch to get the current docs._
{/* LASO-DOCS-VERSION:END */}

You are an agent. This document is the registration recipe for Laso Finance: discover, register, exchange, use, refresh, and hand off to your human. Follow the steps in order.

Base URL: `https://laso.finance`. The full API reference is `https://laso.finance/SKILL.md`.

## Step 1 — Discover

Two metadata documents describe this service:

```http
GET https://laso.finance/.well-known/oauth-protected-resource
GET https://laso.finance/.well-known/oauth-authorization-server
```

The first names the resource and points at the authorization server. The second carries the `agent_auth` block: `register_uri`, `identity_types_supported`, `credential_types_supported`, `claim_endpoint`, and the revocation and human-verification facts. Read the `agent_auth` block in full. It is the machine-readable form of everything below.

**Laso answers `402 Payment Required`, not `401 Unauthorized`.** Endpoints are x402-paywalled, so there is no `WWW-Authenticate: Bearer resource_metadata="…"` header to follow; fetch the two well-known documents at the conventional paths above. On `GET /auth` specifically, a 402 means your wallet signature was missing or rejected, and a fresh challenge is base64-encoded in the `PAYMENT-REQUIRED` response header. Sign that challenge and retry.

## Step 2 — Pick a method

Laso accepts two identity types. It does **not** accept `identity_assertion` / ID-JAG: there is no `POST /agent/identity` endpoint, no assertion trust list, and no JWT-bearer grant. Do not try to present one.

1. **You have a wallet keypair (or your wallet provider can sign for you)** → [anonymous](#anonymous--wallet-signature). No human needed. This is the common path.
2. **A human gave you a Laso agent API key (`lasoak_` prefix)** → [service_auth](#service_auth--laso-agent-api-key). You and that human share one account.
3. **You have neither** → tell your human, in plain words, to open `https://laso.finance/agent/dashboard`, click **"Give your agent a wallet"**, and follow the create-account flow. Its last step reveals a `lasoak_` key and a prompt for them to paste to you. There is no other way for them to obtain a key, so do not ask for one without giving them these instructions.

## Step 3 — Register

### anonymous — wallet signature

```http
GET /auth
SIGN-IN-WITH-X: <base64-encoded CAIP-122 signed message>
```

The signature proves control of the wallet; no user identity is asserted and the account is created on first use. The simplest way to construct the header is `wrapFetchWithSIWx` from `@x402/extensions/sign-in-with-x`, which handles the signature and the challenge round-trip for you:

```typescript
import { wrapFetchWithSIWx } from "@x402/extensions/sign-in-with-x";
import { privateKeyToAccount } from "viem/accounts";

const signer = privateKeyToAccount(process.env.WALLET_PRIVATE_KEY);
const fetchWithSiwx = wrapFetchWithSIWx(fetch, signer);

const res = await fetchWithSiwx("https://laso.finance/auth");
const { auth, user_id } = await res.json();
```

Response (200):

```json
{
  "auth": {
    "id_token": "eyJ...",
    "refresh_token": "AMf...",
    "expires_in": "3600"
  },
  "user_id": "0xabc..."
}
```

This route is free: it is signature-gated, not payment-gated. If you route paid calls through a wallet provider, still call `GET /auth` directly rather than through the provider's x402 proxy.

### service_auth — Laso agent API key

Present the `lasoak_` key as a bearer token:

```bash
curl https://us-central1-kyc-ts.cloudfunctions.net/agentAuth \
  -H "Authorization: Bearer $LASO_API_KEY"
```

Response (200):

```json
{
  "auth": { "id_token": "eyJ...", "refresh_token": "AMf...", "expires_in": "3600" },
  "user_id": "usr_...",
  "auth_url": "https://laso.finance/agent/dashboard/auth?code=K7MPQ-W3XZ9"
}
```

Keep the `lasoak_` key secret, like a password: it is the long-lived credential that mints these sessions, and it is the only credential you need to store. Everything else is derived from it. The examples reference the environment variables `$LASO_API_KEY` (the key) and `$LASO_ID_TOKEN` (the minted `id_token`).

**Then announce yourself, before anything else.** Your human is on a "waiting for your agent" screen that only flips to "connected" when this call lands:

```bash
curl -X POST https://us-central1-kyc-ts.cloudfunctions.net/announceAgentConnection \
  -H "Authorization: Bearer $LASO_ID_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "<a name they will recognize you by>", "greeting": "<a short hello>"}'
```

**Then give `auth_url` to your human**, exactly as received. It signs them into the web dashboard for this same account so they can watch balances, cards, and transfers. The URL carries a short single-use login code (no long token), so it passes through tool-output credential filters intact; do not open or fetch it yourself, since redeeming the code consumes the human's login. It expires after 15 minutes, so call `agentAuth` again for a fresh one.

## Step 4 — Claim: hand the account to a human

There is no six-digit code ceremony here. The equivalent is a login link you mint and pass to your human, so they can take ownership of the account you have been acting on:

```http
GET /get-auth-link
Authorization: Bearer <id_token>
```

Response (200):

```json
{
  "auth_url": "https://laso.finance/agent/dashboard/auth?code=K7MPQ-W3XZ9",
  "user_id": "0xabc...",
  "expires_in": 900
}
```

Surface `auth_url` to your human exactly as received. Opening it signs them into the dashboard for your account, where they can inspect everything you have done. The URL carries a short single-use login code (no long token), so it passes through tool-output credential filters intact; do not open or fetch it yourself, since redeeming the code consumes the human's login. It expires after 15 minutes; mint a fresh one when it does. If you registered via `service_auth`, you already received an `auth_url` in Step 3 and do not need this call.

Nothing about your credentials changes when a human claims the account. There are no pre-claim and post-claim scopes, and your `id_token` keeps working.

## Step 5 — Use the credentials

Present `id_token` as a bearer token on every authenticated endpoint:

```http
GET /get-account-balance
Authorization: Bearer <id_token>
```

Paid endpoints are separate: they are settled with an x402 payment, not with this token. See `https://laso.finance/SKILL.md` for the full route list and pricing.

## Step 6 — Refresh

`id_token` expires in about an hour. Exchange the refresh token for a new one:

```bash
curl -X POST https://laso.finance/auth \
  -H "Content-Type: application/json" \
  -d '{"grant_type": "refresh_token", "refresh_token": "AMf..."}'
```

Response (200):

```json
{
  "id_token": "eyJ...",
  "refresh_token": "AMf...",
  "expires_in": "3600",
  "user_id": "0xabc..."
}
```

Save the returned pair each time. `GET /auth`, `POST /auth`, and `GET /get-card` all return fresh tokens, and the newest pair is the one to keep. If the refresh fails, re-register at [Step 3](#step-3--register): sign a fresh `SIGN-IN-WITH-X` header, or re-present your `lasoak_` key.

## Revocation

There is no agent-callable revocation endpoint (no RFC 7009 `revocation_endpoint`).

- **`id_token`** cannot be revoked ahead of its one-hour expiry. Discard it and stop using it.
- **`lasoak_` api_key** is revoked by the human who owns the account, which invalidates every session minted from it. If you suspect your key leaked, tell your human immediately and stop using it; support is `agents+support@laso.finance`.
- **Wallet-signature registrations** have no separate credential to revoke, because control of the wallet key is the credential.

You discover a revoked key the same way you discover an expired one: `agentAuth` stops issuing sessions. Re-registering with a revoked key will not work; ask your human for a new one.

## Identity verification

Verification is optional and only gates some endpoints. `GET /get-kyc-status` reports whether the account is verified; `GET /get-kyc-link` returns a one-time link. **You must not fill that form in yourself.** Hand the link to your human and poll the status endpoint until it clears. This is the only step of any Laso flow an agent cannot complete; everything around it, including opening bank accounts and reading back their details, is agent-drivable.

## Errors

| Status | Where | What to do |
| --- | --- | --- |
| `402` | `GET /auth` | Signature missing, invalid, expired, or nonce reused. Sign the fresh challenge in the `PAYMENT-REQUIRED` header and retry. Never treat this as a payment failure. |
| `402` with `accepts` | any paid route | A payment challenge. Pay it and replay the request. |
| `402` with `success: false` | any paid route | Settlement failed (usually insufficient funds). Nothing was charged; retry smaller. |
| `401` | `agentAuth` | The `lasoak_` key is wrong, revoked, or malformed. Ask your human for a new one. |
| `401` | any Bearer route | `id_token` expired or invalid. Refresh at [Step 6](#step-6--refresh); if that fails, re-register at [Step 3](#step-3--register). |
| `403` | any Bearer route | The account is not permitted to do this yet. Check `GET /get-kyc-status`. |
| `429` | any | Back off and retry. |
| `5xx` | any | Exponential backoff, retry the same request. |

Do not retry a 4xx with the same payload; act on the table above.

## Staying current

`GET /version` (free, no auth) and `https://laso.finance/.well-known/docs-version.json` both report the current docs version. If it differs from the version stamped at the top of this file, your cached copy is stale, so refetch this document, `SKILL.md`, and the two well-known metadata documents.
