Skip to main content
AI Generated Content
πŸ€– This documentation was generated with AI assistance. Please report any issues you find.

Credentials

Credentials let you define typed, per-user or platform-level secrets that your functions and AI agents need at runtime β€” API keys, OAuth2 tokens, or any structured config that varies by user or tenant.

The CLI picks up wireCredential() calls, generates typed wrappers, and makes them available through the credential service. When an AI agent calls a tool that needs a credential the user hasn't connected yet, Pikku automatically suspends the agent run and signals the client to collect it.

Defining a Credential​

Use wireCredential from @pikku/core/credential. The call itself is a no-op at runtime β€” the CLI reads it via AST and generates metadata.

import { wireCredential } from '@pikku/core/credential'
import { z } from 'zod'

wireCredential({
name: 'stripe',
displayName: 'Stripe API Key',
description: 'API key for Stripe payment processing',
type: 'wire',
schema: z.object({ apiKey: z.string() }),
})

Configuration​

PropertyTypeRequiredDescription
namestringβœ…Unique identifier for the credential
displayNamestringβœ…Human-readable name (shown in Console and auth flows)
descriptionstring❌Explains what this credential is for
type'singleton' | 'wire'βœ…Scope β€” see below
schemaZod schemaβœ…Shape of the credential data
oauth2object❌OAuth2 flow configuration β€” see OAuth2 Credentials

Credential Types​

wire β€” per-user credentials. Each user (or session) has their own value. Use this for things like personal API keys or per-user OAuth tokens.

singleton β€” platform-level credentials. One value shared across the entire app. Use this for credentials your platform owns, like your Slack bot token.

OAuth2 Credentials​

For services that use OAuth2, add an oauth2 block. Pikku handles the authorization flow, token exchange, and refresh.

wireCredential({
name: 'google-sheets',
displayName: 'Google Sheets',
type: 'wire',
schema: z.object({
accessToken: z.string(),
refreshToken: z.string().optional(),
}),
oauth2: {
appCredentialSecretId: 'GOOGLE_OAUTH_APP',
tokenSecretId: 'GOOGLE_OAUTH_TOKENS',
authorizationUrl: 'https://accounts.google.com/o/oauth2/v2/auth',
tokenUrl: 'https://oauth2.googleapis.com/token',
scopes: ['https://www.googleapis.com/auth/spreadsheets'],
},
})

OAuth2 Configuration​

PropertyTypeRequiredDescription
appCredentialSecretIdstringβœ…Secret ID where the OAuth app's client ID and client secret are stored
tokenSecretIdstringβœ…Secret ID where exchanged tokens are persisted
authorizationUrlstringβœ…OAuth2 authorization endpoint
tokenUrlstringβœ…OAuth2 token exchange endpoint
scopesstring[]βœ…Requested OAuth scopes
pkceboolean❌Enable PKCE (Proof Key for Code Exchange)
additionalParamsRecord<string, string>❌Extra query params for the authorization URL

The appCredentialSecretId points to a secret that holds your OAuth app's clientId and clientSecret.

Singleton Example​

A platform-level Slack credential shared by the entire app:

wireCredential({
name: 'slack',
displayName: 'Slack',
type: 'singleton',
schema: z.object({
accessToken: z.string(),
refreshToken: z.string().optional(),
}),
oauth2: {
appCredentialSecretId: 'SLACK_OAUTH_APP',
tokenSecretId: 'SLACK_OAUTH_TOKENS',
authorizationUrl: 'https://slack.com/oauth/v2/authorize',
tokenUrl: 'https://slack.com/api/oauth.v2.access',
scopes: ['chat:write', 'channels:read'],
},
})

Simple API Key Example​

Not everything needs OAuth. For plain API keys or bearer tokens:

wireCredential({
name: 'hmac-key',
displayName: 'HMAC Signing Key',
type: 'wire',
schema: z.object({ secretKey: z.string() }),
})

AI Agent Integration​

When an AI agent calls a tool that belongs to an addon requiring a credential, Pikku checks whether the current user has that credential connected. If not, the agent run suspends with a ToolCredentialRequired error, and the client receives a signal to prompt the user to connect the credential.

This happens automatically β€” you don't need to write any credential-checking logic in your tools. The agent resumes once the credential is provided.

// The agent just lists its tools β€” credential checks happen at runtime
export const assistant = pikkuAIAgent({
name: 'assistant',
description: 'A helpful assistant with integrations',
instructions: 'Help the user with their integrations.',
model: 'fast',
tools: [listSheets, createSheet, sendSlackMessage],
// If listSheets requires 'google-sheets' credential and the user
// hasn't connected it, the agent pauses and asks the client to collect it.
})

Generated Files​

After running pikku, the CLI generates credential metadata in .pikku/credentials/:

  • pikku-credentials.gen.ts β€” typed credential wrappers
  • pikku-credentials-meta.gen.json β€” credential definitions metadata

These are consumed by the Console, deploy pipeline, and AI agent runtime.

File Convention​

Name your credential files *.credential.ts (e.g., stripe.credential.ts). This isn't required β€” the CLI finds wireCredential() calls anywhere in your source directories β€” but it keeps things organized.