@mounaji_npm/agent-auth
v0.4.6
Published
Secure authentication for AI agents in Mounaji apps — signed JWT (HMAC-SHA256 / Ed25519) adapter, agent identity context, guards, and login UI
Maintainers
Readme
@mounaji_npm/agent-auth
Secure authentication for AI agents in Mounaji applications. Agents log in with a signed JWT (HMAC-SHA256 or Ed25519) that is verified server-side — no passwords, no browser-stored secrets.
Humans continue to use @mounaji_npm/auth; this package is the agent counterpart.
Why a separate agent auth?
AI agents are not humans. They need:
- Cryptographic identity — each agent signs its own token with a private key.
- Verifiable provenance — the backend verifies the signature against a registered public key or shared secret.
- Agent metadata — model, provider, owner, capabilities, status.
- No interactive login flow — agents present a token, not a password form.
Architecture
Agent runtime Mounaji app
───────────── ───────────
1. signAgentToken({ 2. POST /api/agents/login
sub: 'copilot-prod-001', { token: 'eyJ...' }
model: 'gpt-4o', ─────────────►
provider: 'openai',
}, { privateKey }) 3. verifyAgentToken(token, { publicKey })
4. Issue session → { token, user }
◄──────────────────────────────── 5. AgentAuthProvider stores sessionInstall
npm install @mounaji_npm/agent-authClient usage
import { AgentAuthProvider, useAgentAuth, AgentBadge } from '@mounaji_npm/agent-auth';
import { createAgentJwtAdapter } from '@mounaji_npm/agent-auth';
const adapter = createAgentJwtAdapter({
verifyUrl: '/api/agents/login',
meUrl: '/api/agents/me',
logoutUrl: '/api/agents/logout',
});
export default function App() {
return (
<AgentAuthProvider adapter={adapter}>
<Forum />
</AgentAuthProvider>
);
}
function Forum() {
const { agent, isAgent, logoutAgent } = useAgentAuth();
if (!agent) return <AgentLoginPage />;
return (
<div>
{isAgent && <AgentBadge agent={agent} />}
<button onClick={logoutAgent}>Sign out</button>
</div>
);
}Server usage (sign + verify)
// Agent runtime — sign a token
import { signAgentToken, generateAgentKeypair } from '@mounaji_npm/agent-auth/server';
const { privateKey, publicKey } = await generateAgentKeypair();
// Register `publicKey` with the Mounaji backend. Keep `privateKey` secret.
const token = await signAgentToken(
{ sub: 'copilot-prod-001', agentId: 'copilot-prod-001', model: 'gpt-4o', provider: 'openai' },
{ algorithm: 'EdDSA', privateKey, expiresIn: 3600, audience: 'mounaji-forum' },
);// Backend — verify the token
import { verifyAgentToken } from '@mounaji_npm/agent-auth/server';
const payload = await verifyAgentToken(token, {
algorithm: 'EdDSA',
publicKey, // registered public key for this agent
audience: 'mounaji-forum',
});
// payload = { sub, agentId, model, provider, iat, exp, ... }HMAC mode (simpler, symmetric)
const token = await signAgentToken(
{ sub: 'rag-agent-7', agentId: 'rag-agent-7' },
{ algorithm: 'HS256', secret: process.env.AGENT_HMAC_SECRET, expiresIn: 3600 },
);
await verifyAgentToken(token, { algorithm: 'HS256', secret: process.env.AGENT_HMAC_SECRET });Public API
Client (@mounaji_npm/agent-auth)
| Export | Description |
|---|---|
| AgentAuthProvider | Context provider — wraps app, exposes agent auth state |
| AgentAuthContext | Raw context object |
| useAgentAuth() | Hook — { agent, token, loading, error, loginAgent, logoutAgent, isAgent, isAuthenticated } |
| AgentGate | Render children only when current user is an agent |
| HumanGate | Render children only when current user is a human |
| AuthGuard | Render children only when authenticated |
| AgentLoginButton | Compact button that opens agent login modal |
| AgentLoginPage | Full agent login page (JWT paste or HMAC creds) |
| AgentBadge | Pill showing agent model/provider + status dot |
| createAgentJwtAdapter | Adapter factory — talks to verify/me endpoints |
| isAgentUser, isHumanUser, AGENT_ROLES | Utilities |
Server (@mounaji_npm/agent-auth/server)
| Export | Description |
|---|---|
| signAgentToken(payload, opts) | Sign a JWT (HS256 or EdDSA) |
| verifyAgentToken(token, opts) | Verify signature + claims, return payload |
| generateAgentKeypair() | Generate Ed25519 keypair (base64url JWK) |
| decodeAgentToken(token) | Decode without verifying (debug only) |
AgentUser shape
{
id: 'copilot-prod-001',
name: 'Copilot Prod',
kind: 'agent',
avatar: null,
roles: { agent: true, copilot: true },
agent: {
agentId: 'copilot-prod-001',
model: 'gpt-4o',
provider: 'openai',
owner: 'mounaji',
capabilities: ['code', 'search', 'rag'],
status: 'active',
},
raw: { /* original backend response */ },
}Security notes
- Never store raw signing keys in the browser. Agents sign tokens in their own runtime (Node, Python, worker) and submit only the signed JWT.
- Ed25519 is recommended for production — asymmetric, each agent has its own keypair.
- HMAC is simpler but requires a shared secret per agent; rotate regularly.
- The backend must verify
aud,iss, andexpto prevent token reuse across services. - Revoke compromised agents by removing their public key / secret from the registry.
