Testing Your Integration with curl
Six checks against your own deployment that prove the wiring — run them, don't trust this page.
Don't take our word for any of this. Every claim below is something you can observe with your own token and curl, against your own deployment, in ten minutes. If a check behaves differently, your wiring is wrong — fix it before you publish auth.md, because an agent will find the same behavior and act on it.
Mint a 5-minute test token directly with curl (or via Remote MCP):
TOKEN=$(curl -s -X POST https://agentonboard.xyz/api/v1/token/exchange \
-H "Authorization: Bearer aon_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"audience": "notes.com"}' | jq -r .token)Use your own email's token throughout: before your service knows it, your own address is the stranger. That is the whole test fixture.
1. An unknown email gets 403, not 401
curl -i -H "Authorization: Bearer $TOKEN" https://notes.com/api/notesExpect 403 with code: "ACCOUNT_REQUIRED". A 401 here means your status mapping is wrong — and it matters, because an agent answers 401 by re-authenticating, which can never create an account, while it answers 403 by following your auth.md row.
2. Signup creates once, then signs in
curl -i -X POST -H "Authorization: Bearer $TOKEN" https://notes.com/api/signup
# → 201, created: true
curl -i -H "Authorization: Bearer $TOKEN" https://notes.com/api/notes
# → served: the retry after signup works
curl -i -X POST -H "Authorization: Bearer $TOKEN" https://notes.com/api/signup
# → created: false, the SAME user — a double registration signs in, no duplicateThen look at your own users table: exactly one row for your email. Two rows means your creator ran on a hit — the replay case, and the one your audit log cannot see without created.
3. A forged token reaches neither callback
Flip one character in the token's third segment (the signature) and send it:
BROKEN="${TOKEN%?}A"
curl -i -H "Authorization: Bearer $BROKEN" https://notes.com/api/notes
curl -i -X POST -H "Authorization: Bearer $BROKEN" https://notes.com/api/signupExpect 401 INVALID_SIGNATURE from both — and, if you log callback invocations in development, zero invocations. A forged token that reaches your database layer is the failure this whole design exists to prevent: an account created from an email nobody proved.
Two more forgeries while you are here: no header at all (expect 401 MALFORMED_TOKEN), and a token minted for a different domain — e.g. { "audience": "someone-else.com" } — against yours (expect 401 AUDIENCE_MISMATCH).
4. An old token stays old
Tokens live 5 minutes. Wait six, replay the original $TOKEN, and expect 401 EXPIRED. If it still verifies, your clock tolerance is misconfigured — or you are verifying against a different issuer than the one that minted it, and the check you think ran did not run.
Note what this also proves: the same token presented twice inside its window verifies both times. That is bearer semantics, not a bug — but it means you must never treat "this token verified" as "this request is fresh". Serve it over TLS, never log it.
5. Your own fault reports as yours
Temporarily make your resolver throw with a fake secret in the message — something greppable like hunter2-test-marker — and call any protected route. Expect 500 RESOLVER_ERROR, and confirm the marker appears nowhere: not in the response body, not in the status line, not in any log your error aggregator ships to. The thrown value is untrusted text that usually carries a connection string. Then revert the thrower.
6. Your auth.md matches your responses
Read your published file line by line against what you just observed:
- Every
codein its table is one your responses actually return. A table naming codes you never send is worse than no table. - The
403row points at the flow that actually exists: your signup endpoint, or your human connect flow — whichever you built. A row pointing at the other one sends an agent somewhere useless. - No key, token, private endpoint, or internal hostname anywhere in the file. It is public and machines read it.
Re-run this pass after every auth change
These six checks take ten minutes and cover the entire contract: who you are, whether you have an account, and what happens when either answer is no. Re-run them whenever you touch a resolver, a creator, a status mapping, or auth.md — the failure they catch is always cheaper here than in an agent's transcript.