discernible-io/api-idc is open source and publicly available. Anyone can fork it and build an API that logs agents in by who they are — Passport key possession on a signed challenge — not by credentials you issued and hope they keep secret.
IdentyClaw home (https://api.identyclaw.com) issues Passport / HOLA identity. It does not authorize arbitrary third-party APIs.
If you want Passport holders as clients of your service, you run a federated peer: same challenge–response login contract, your RODiT service credentials, JWTs valid only for your apiEndpoint. That is the open implementation of federated login this repo ships.
Working pattern (clone and reshape): api-idc — Node/Express peer on @rodit/rodit-auth-be. The included CRUDA comments API is a sample resource. Keep the auth spine; replace CRUDA with your domain.
Series context
| Already published / related | Role |
|---|---|
| No IdentyClaw API key — federated login | Client/operator: challenge→JWT, re-login per host |
| Passport vs static secrets | When Passport beats API keys |
| OpenClaw onboarding | Client-side Passport + plugins |
This article is the server builder launch note: the scaffold is public — stand up a peer that Passport agents can already talk to.
Why federation (not a portable home JWT)
┌─────────────────────┐ ┌──────────────────────────┐
│ IdentyClaw home │ │ Your federated peer │
│ api.identyclaw.com │ │ (api-idc scaffold) │
│ Passport / HOLA │ │ POST /api/login → JWT │
└─────────┬───────────┘ └────────────┬─────────────┘
│ Passport keys │
└──────────────┬───────────────────┘
▼
Agent / app signs challenge
against YOUR apiEndpoint only
Each peer:
- Holds its own RODiT service credentials (NEAR / Vault).
- Exposes the same login contract (
/api/login/timestamp→/api/login). - Mints JWTs scoped to that peer’s
apiEndpoint. - Authorizes verbs with
METHOD_PERMISSION_MAP(or your policy onauthenticate).
Clients remint a JWT per peer. Tokens are not portable across home and peers, or across peers. That is intentional — federation means shared identity family, not session portability.
Normative client wire detail: login-authentication.
Auth contract your peer must implement
| Step | Endpoint | Notes |
|---|---|---|
| 1 | GET /api/login/timestamp |
Fresh timestamp + timestamp_iso from this peer |
| 2 | Sign locally | UTF-8 `roditid\ |
| 3 | {% raw %}POST /api/login
|
Exactly one of timestamp / timestamp_iso + signature → jwt_token
|
| 4 | Protected calls | Authorization: Bearer <jwt_token> |
| 5 | POST /api/logout |
Invalidate this peer’s session |
OpenAPI in the scaffold is authoritative: api-docs/swagger.json (also served at /api-docs).
OpenClaw agents (already know this contract)
identyclaw_ensure_session({ apiEndpoint: "https://your-peer.example:8443" })
identyclaw_request({ method: "GET", path: "/api/your-resource/", apiEndpoint: "https://your-peer.example:8443" })
The OpenClaw IdentyClaw plugin caches the peer JWT and never returns it to the model. If your peer speaks the contract above, agents can target it without custom login glue.
openclaw plugins install clawhub:@identyclaw/openclaw-identyclaw-plugin
openclaw skills install clawhub:identyclaw
Public agent guides on the scaffold (no JWT): GET /api/mcp/resource/doc:skills, GET /.well-known/mcp, GET /.
What ships with the pattern
| Surface | Role |
|---|---|
/api/login/timestamp, /api/login, /api/logout
|
Federated challenge-response JWT mint |
/api/signclient |
Mint/sign client RODiT scoped to this peer’s routes |
/api/token/claims |
Verify peer JWT after login |
/api/cruda/* |
Sample protected resource (authenticate + METHOD_PERMISSION_MAP) |
/api/sessions/* |
Privileged session admin pattern |
/api/mcp/*, /mcp
|
Login docs for agents (not your domain tools) |
/health, /api-docs
|
Ops + contract |
Authorization for sample CRUDA uses METHOD_PERMISSION_MAP in config/*.json (create, list, read, update, destroy, …).
Live peer that already follows this model in production: SLC game API on :8443.
Turn the scaffold into your API
- Fork or clone api-idc; set
SERVICE_NAME, nginxserver_name, and OpenAPIserversto your peer hostname. - Provide RODiT server credentials (
config/custom-environment-variables.json— NEAR / Vault). - Copy
src/protected/cruda.js→ your resource router; mount insrc/app.jswithauthenticate+authorize. - Add verb keys to
METHOD_PERMISSION_MAP(ornpm run update:permissionsafter updating swagger). - Document paths in
api-docs/swagger.jsonso Passport holders and agents integrate against a stable contract. - Tell clients: login against your
apiEndpoint; never send a home JWT here.
Quick start
git clone https://github.com/discernible-io/api-idc.git
cd api-idc
npm install
# NEAR / RODiT server credentials — see config/custom-environment-variables.json
NODE_ENV=development npm start
Listens on SERVERPORT (default 8080). Behind nginx TLS typically 8443.
Shell smoke test (after you can sign with a Passport key):
BASE=http://127.0.0.1:8080
# 1) GET $BASE/api/login/timestamp
# 2) Sign identifier + timestamp_iso with Passport Ed25519 key → base64url
# 3) POST $BASE/api/login → jwt_token
curl -s "$BASE/api/token/claims" -H "Authorization: Bearer $JWT"
curl -s "$BASE/api/cruda/list" -H "Authorization: Bearer $JWT" -H "Content-Type: application/json" -d '{}'
Layout to keep vs replace
src/app.js # keep — bootstrap, authenticate + authorize
src/routes/ # keep — login, discovery, MCP docs, signclient
src/protected/cruda.js # replace — sample; your domain router here
config/ # keep pattern — METHOD_PERMISSION_MAP + secrets mapping
api-docs/swagger.json # update — your OpenAPI contract
Stack: Node.js 20, Express 4, @rodit/rodit-auth-be 9.x, SQLite sessions, Swagger UI, optional Podman + nginx.
Do not conflate layers
| Layer | Your peer’s job |
|---|---|
| Peer JWT | Prove which Passport may call your protected HTTP routes |
| HOLA | Peer-to-peer trust off your API (verify-before-execute) — separate surface |
| Home JWT | Valid only on api.identyclaw.com — reject it on your peer |
LOGIN_MODE on the receiving peer gates who may mint (partner / p2p / promiscuous). See identity-verification-policy.
Bottom line
The federation pattern is no longer a private template — api-idc is public. Passport holders already know how to prove possession. Your job as an API builder is to speak the same login contract on your host, mint host-scoped JWTs, and authorize your own verbs — agents authenticate by identity, not by a shared secret you handed them.
Fork the scaffold → keep auth → swap sample CRUDA for your domain → publish OpenAPI → point OpenClaw / agents at your apiEndpoint.
Get started
- Scaffold (public): https://github.com/discernible-io/api-idc
- Client login companion: https://dev.to/discernible-io/no-identyclaw-api-key-passport-challenge-response-federated-login-and-host-scoped-jwts-888
- Login reference: https://github.com/discernible-io/idclawserver-idc/blob/main/references/login-authentication.md
- Multi-API sessions: https://api.identyclaw.com/api/mcp/resource/doc:skills
- Live peer example (SLC): https://slc.discernible.io:8443/api/game/skill.md
- Purchase Passport (for testing clients): https://purchase.identyclaw.com
What domain API would you put behind a federated peer first?
Top comments (0)