# CBIO agent login (`https://c.bio/llms.txt`) CBIO is a public identity and authentication layer for subjects such as humans and agents. Use this file to obtain a short-lived CBIO `session_jwt` and authenticate to a target site API. ## Goal Get a valid CBIO `session_jwt` and send the target site API request with: `Authorization: Bearer ` ## Inputs you need before starting | Name | Where it comes from | Notes | | --- | --- | --- | | `aud` | The target site | Must be an `http`/`https` origin only, with no path/query/fragment. Example: `https://shop.example.com` | | `subject_public_key` | Your local Ed25519 keypair | SPKI DER, base64url | | `private_key` | Your local Ed25519 keypair | PKCS#8 DER, base64url | | `subject_ref` | Derived locally from `subject_public_key` | Format: `cbio:v1:sub:ed25519:spki-b64u:` | ## Offline prerequisites (generate keys, no network) If you already have `subject_public_key` and `private_key`, skip this section. ### Generate an Ed25519 keypair and derive `subject_ref` Run this locally: ```node const crypto = require('node:crypto'); function createSubjectRef(subjectPublicKey) { return `cbio:v1:sub:ed25519:spki-b64u:${subjectPublicKey}`; } const { publicKey, privateKey } = crypto.generateKeyPairSync('ed25519', { publicKeyEncoding: { type: 'spki', format: 'der' }, privateKeyEncoding: { type: 'pkcs8', format: 'der' } }); const subject_public_key = publicKey.toString('base64url'); const private_key = privateKey.toString('base64url'); const subject_ref = createSubjectRef(subject_public_key); console.log(JSON.stringify({ subject_public_key, private_key, subject_ref }, null, 2)); ``` ## Do this now 1. Get `aud` from the target site. 2. Derive `subject_ref` locally from `subject_public_key`. 3. Request a challenge: - `POST https://c.bio/identity/v1/challenge` - Body: ```json { "subject_ref": "cbio:v1:sub:ed25519:spki-b64u:..." } ``` 4. Read `nonce` from the response. 5. Sign `nonce` locally: - `signature = signPayload(private_key, nonce)` Example local script: ```node const crypto = require('node:crypto'); const private_key = 'PASTE_PRIVATE_KEY_HERE'; const nonce = 'PASTE_NONCE_HERE'; const privateKeyDer = Buffer.from(private_key, 'base64url'); const signature = crypto.sign(null, Buffer.from(nonce), { key: privateKeyDer, format: 'der', type: 'pkcs8' }).toString('base64url'); console.log(JSON.stringify({ signature }, null, 2)); ``` 6. Verify and get a session JWT: - `POST https://c.bio/identity/v1/verify` - Body must include: ```json { "subject_ref": "cbio:v1:sub:ed25519:spki-b64u:...", "subject_public_key": "base64url-spki-der", "nonce": "nonce-from-challenge", "signature": "base64url-signature", "aud": "https://target-site.example" } ``` Notes: - `subject_public_key` is required the first time this subject is seen by CBIO. - After registration, `subject_ref` is the canonical protocol identifier. - Read `session_jwt` from the response. 7. Send the target site API request with: `Authorization: Bearer ` ## If it fails - Missing `aud`: request it from the target site. - Verify fails: check exact `aud` origin, nonce freshness, and key/signature format. - Target site returns `401`: fetch a fresh `session_jwt` and retry once. ## Optional SDK path SDK is optional. If used, it must perform the same flow above: `challenge -> sign -> verify -> session_jwt` ## What the target site verifies The target site verifies the JWT with: - JWKS: `https://c.bio/.well-known/jwks.json` - `iss === "https://c.bio"` - `aud` equals the site-provided `aud` - `sub` equals the subject identifier presented by CBIO, usually `subject_ref`