intentkit-auth
v1.0.1
Published
JWT authentication adapter for IntentKit via jose
Maintainers
Readme
intentkit-auth
JWT authentication adapter for IntentKit — token signing, verification, and decoding via jose.
Supports symmetric secrets (HMAC) for full sign+verify, and JWKS endpoints (Auth0, Okta, etc.) for verify-only flows.
Install
npm install intentkit-authQuick Start
import { defineFunction, IntentRegistry, createContext, serve, z } from 'intentkit';
import { createAuthProvider, type AuthClient } from 'intentkit-auth';
// Register your functions
const registry = new IntentRegistry().register(createToken, verifyToken, decodeToken);
// Create context (no database needed for auth-only projects)
const context = await createContext({ events: true });
// Boot MCP server with auth provider
await serve({
name: 'my-auth-agent',
registry,
context,
providers: [
createAuthProvider({
secret: process.env.JWT_SECRET!,
issuer: 'my-service',
audience: 'my-api',
}),
],
});Configuration
| Option | Default | Description |
|--------|---------|-------------|
| secret | -- | Symmetric secret for HMAC signing + verification |
| jwksUrl | -- | JWKS endpoint URL for asymmetric verification (e.g., Auth0) |
| issuer | -- | Expected iss claim (validated on verify) |
| audience | -- | Expected aud claim (validated on verify) |
| algorithm | 'HS256' / auto | Signing algorithm (HS256 for secret, auto-detected for JWKS) |
| defaultExpiry | '1h' | Default token expiry (jose duration format) |
| name | 'auth' | Provider name in ctx.providers |
You must provide at least one of secret or jwksUrl. Provide both to sign with a symmetric secret and also accept tokens signed by an asymmetric key (JWKS).
Common Provider Configs
Symmetric Secret (simple):
createAuthProvider({
secret: process.env.JWT_SECRET!,
defaultExpiry: '24h',
})JWKS Endpoint (Auth0):
createAuthProvider({
jwksUrl: 'https://your-tenant.auth0.com/.well-known/jwks.json',
issuer: 'https://your-tenant.auth0.com/',
audience: 'https://your-api.example.com',
})JWKS Endpoint (Okta):
createAuthProvider({
jwksUrl: 'https://your-org.okta.com/oauth2/default/v1/keys',
issuer: 'https://your-org.okta.com/oauth2/default',
audience: 'api://default',
})Issuer + Audience Validation:
createAuthProvider({
secret: process.env.JWT_SECRET!,
issuer: 'my-service',
audience: 'my-api',
algorithm: 'HS384',
defaultExpiry: '8h',
})Using in Functions
Access the auth client via ctx.providers.auth:
import { defineFunction, z } from 'intentkit';
import type { AuthClient } from 'intentkit-auth';
export const loginUser = defineFunction({
name: 'login_user',
intent: 'Authenticate a user and return a signed JWT token',
permissions: ['auth:sign'],
requires: ['auth'], // Validates provider exists at startup
input: z.object({
user_id: z.string(),
role: z.string(),
}),
output: z.object({
token: z.string(),
}),
execute: async (input, ctx) => {
const auth = ctx.providers.auth as AuthClient;
const token = await auth.sign(
{ role: input.role },
{ subject: input.user_id, expiresIn: '24h' },
);
return { token };
},
});Example Functions
The package includes 3 ready-to-use functions in functions/tokens.ts:
| Function | Intent | Permission |
|----------|--------|------------|
| create_token | Create a signed JWT token with custom claims | auth:sign |
| verify_token | Verify a token's signature and expiration | auth:verify |
| decode_token | Decode a token without verification | auth:read |
Import and register them:
import { createToken, verifyToken, decodeToken } from 'intentkit-auth/functions';
const registry = new IntentRegistry()
.register(createToken, verifyToken, decodeToken);AuthClient API
The full client interface for custom function implementations:
interface AuthClient {
// Sign a payload into a JWT token (requires symmetric secret)
sign(payload: Record<string, unknown>, options?: SignOptions): Promise<string>;
// Verify a token's signature and claims
verify(token: string): Promise<VerifyResult>;
// Decode without verification (never trust unverified data)
decode(token: string): TokenPayload;
// Health check
ping(): Promise<boolean>;
}
interface SignOptions {
subject?: string; // sub claim
expiresIn?: string; // override default expiry (e.g., '2h', '7d')
claims?: Record<string, unknown>; // additional claims
}
interface VerifyResult {
valid: boolean; // signature + claims valid
payload: TokenPayload; // decoded payload
expired: boolean; // failed specifically due to expiration
}
interface TokenPayload {
sub?: string;
iss?: string;
aud?: string;
exp?: number;
iat?: number;
[key: string]: unknown;
}Claude Desktop Config
Add to ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"auth": {
"command": "node",
"args": ["path/to/your/serve.js"],
"env": {
"JWT_SECRET": "your-secret-key"
}
}
}
}Architecture
Claude (Dispatch / Desktop)
| MCP tool call
IntentKit (serve + permissions + hooks)
| ctx.providers.auth
intentkit-auth (AuthClientImpl)
|
jose
(JWT)
|
Tokens (signed / verified / decoded)The AuthClient is stateless -- created once at server startup. healthCheck() performs a sign+verify round-trip (symmetric) or fetches the JWKS endpoint (asymmetric). No connections to close on shutdown.
License
MIT
