Nexus: Credential Management¶
Nexus is JarvisCore's credential management system and an open-source framework in its own right. It solves the N+1 authentication problem by providing a single nexus_call interface that works for all 46 service integrations. Nexus handles credential resolution, token refresh, and auth strategy selection so that agents never deal with credentials directly.
[!NOTE] This page is the operational reference covering CLI commands, encryption details, and the Gateway API contract. For the conceptual model explaining why Nexus exists, how
NexusCallProxyworks, and the security design, see Nexus: Credential Federation.
How It Works¶
- You register a provider's credentials once using
jarviscore nexus register. - Credentials are written to
~/.jarviscore/nexus.enc— an AES-256-GCM encrypted file keyed to your machine. - When an agent calls a registered provider, the
NexusLocalStoreretrieves and decrypts the credentials at call time and passes them to the provider's atom function. - Agent code never sees the raw credentials.
Registering Credentials¶
OAuth2 providers¶
jarviscore nexus register github \
--client-id=YOUR_GITHUB_CLIENT_ID \
--client-secret=YOUR_GITHUB_CLIENT_SECRET
Supported OAuth2 providers: github, slack, notion, hubspot, linear, google-sheets, google-drive.
API-key providers¶
jarviscore nexus register stripe --api-key=sk_live_...
jarviscore nexus register airtable --api-key=patXXXXXXXX
Supported API-key providers: stripe, airtable, brevo, mailchimp, apollo.
Verify registration¶
Output shows a masked credential summary (no secrets):
Provider Auth type Client ID Registered
──────────────────────────────────────────────
github oauth2 ghXX**** 2026-05-01
stripe api_key sk_l**** 2026-05-01
Encryption Details¶
Credentials are stored in ~/.jarviscore/nexus.enc:
- Encryption: AES-256-GCM (authenticated encryption — integrity + confidentiality)
- Key derivation: PBKDF2-HMAC-SHA256, 260,000 iterations (OWASP 2024 recommendation)
- Salt: Per-machine, generated once and stored at
~/.jarviscore/.salt. Never changes. - Secret input:
NEXUS_SECRETenv var if set; falls back to machine UUID (MAC address). - Nonce: 12-byte random, unique per write.
Set NEXUS_SECRET in your .env for stronger key derivation:
Without NEXUS_SECRET, the key is derived from the machine's hardware UUID. Credentials encrypted on one machine cannot be decrypted on another.
Using Nexus in Agent Code¶
The NexusLocalStore is accessed via jarviscore.nexus.store.get_store(). In normal usage you do not call it directly — provider atom functions receive auth_info automatically. For custom integrations, you can retrieve credentials as follows:
from jarviscore.nexus.store import get_store
store = get_store()
# Check if a provider is registered
creds = store.get("github")
if not creds:
item_id = self.hitl.request(
title="GitHub credentials not registered",
content="Register GitHub OAuth credentials with: jarviscore nexus register github",
urgency="high",
category="auth_required",
)
return {"status": "waiting_for_auth", "hitl_id": item_id}
# Get auth_info for calling the provider
auth_info = store.build_auth_info("github")
# auth_info = {"access_token": "...", "client_id": "...", "client_secret": "..."}
build_auth_info shapes the credential dict based on auth_type:
auth_type |
auth_info keys |
|---|---|
oauth2 |
access_token, client_id, client_secret |
api_key |
api_key |
basic_auth |
username, password |
The Nexus Gateway (Optional)¶
The local encrypted store handles credentials for single-developer and small team use. For multi-user deployments where agents act on behalf of individual users (each with their own OAuth tokens), the Nexus Gateway provides full OAuth flow management.
[!NOTE] The two modes are not mutually exclusive — the CLI chooses automatically. When you run
jarviscore nexus register, the CLI checks whetherNEXUS_GATEWAY_URLis set and reachable. If it is, credentials are registered with the gateway. If it is not set, or if the gateway is unreachable, credentials are written to the local store (~/.jarviscore/nexus.enc) and a warning is printed. You can start without a gateway and migrate to one later — the local store keeps working regardless.
The gateway is managed entirely via the jarviscore CLI — no separate install required. It runs as a Docker-composed stack. Set it up once per environment:
This generates encryption keys, adds NEXUS_GATEWAY_URL and NEXUS_RETURN_URL to .env, and starts the Docker stack. After init, subsequent starts use:
Test an OAuth flow end-to-end:
Check gateway health:
Gateway API Contract¶
When NEXUS_GATEWAY_URL is set, the CLI registers providers by calling the Gateway directly. You should not need to call this manually — jarviscore nexus register handles it — but the contract is documented here for completeness.
Register a provider: POST /v1/providers
The payload must wrap all fields in a profile object and use name (not provider) as the identifier:
List registered providers: GET /v1/providers
Check gateway health: GET /health
[!NOTE] All examples assume
http://localhost:8090— the default local Docker stack started byjarviscore nexus init. Substitute your own Gateway URL in production. Do not point developers at a third-party hosted gateway — each team runs their own Nexus stack.
Handling Auth Failures in Agents¶
When a credential is missing or expired, the correct pattern is to escalate via HITL rather than failing silently:
from jarviscore import CustomAgent
from jarviscore.nexus.store import get_store
class GitHubAgent(CustomAgent):
role = "github-integration"
async def on_peer_request(self, msg) -> dict:
store = get_store()
context = msg.data.get("context", {})
if not store.get("github"):
item_id = self.hitl.request(
title="GitHub credentials missing",
content=(
"The GitHub integration requires OAuth credentials.\n\n"
"Run: `jarviscore nexus register github --client-id=X --client-secret=Y`"
),
urgency="high",
category="auth_required",
context={"workflow_id": context.get("workflow_id")},
)
resolution = await self.hitl.wait(item_id, timeout=3600)
if not resolution.is_approved:
return {"status": "cancelled"}
auth_info = store.build_auth_info("github")
# proceed with GitHub API calls using auth_info
...
NexusLocalStore API¶
For advanced use cases, the full NexusLocalStore API:
from jarviscore.nexus.store import get_store
store = get_store()
# Register or update credentials
store.register("github", {
"auth_type": "oauth2",
"client_id": "Iv1.abc123",
"client_secret": "secret",
})
# Retrieve raw credential dict (includes all stored fields)
creds = store.get("github")
# List registered providers
providers = store.list() # ["github", "stripe"]
# Delete credentials
store.delete("stripe")
# Safe summary (no secrets) for display
summary = store.get_summary()
# [{"provider": "github", "auth_type": "oauth2", "client_id": "Iv1.****", "registered_at": "..."}]
# Get auth_info dict for passing to provider functions
auth_info = store.build_auth_info("github")