Skip to main content

Credential Provisioning

ID Wispera can programmatically create API keys at vendor APIs and wrap them as governed passports in a single operation, ensuring every provisioned credential is tracked with audit trail and policy enforcement.

Overview

The provisioning module provides a unified interface: provision at the vendor, create a passport in the vault, then manage the lifecycle (rotate, revoke, list) through the same API.
Provisioning requires admin-level credentials for the target provider. Use idw auth bootstrap to store them as encrypted admin passports in the vault with privilege visa type — then provisionAndCreatePassport() resolves auth automatically. See the Authentication guide for details.

Supported Providers

ProviderCreateRotateRevokeListScoped KeysExpiry
OpenAIYesYesYesYesYesNo
AWSYesYesYesYesYesYes (STS)
Google CloudYesYesYesYesYesYes (SA keys)
Azure EntraYesYesYesYesYesYes (secrets)
GitHubYesYesNoNoYesYes (1h tokens)
TwilioYesYesYesYesYesNo
SendGridYesYesYesYesYesNo
AnthropicNoNoYesYesNoNo
Anthropic is a management-only provider. API keys must be created manually at console.anthropic.com. This provider can list and disable existing keys.

Provision and Create Passport

The unified workflow: provision a key at the vendor, then create a governed passport in the vault.
import { provisionAndCreatePassport } from '@id-wispera/core';

const { credential, passport } = await provisionAndCreatePassport(vault, {
  provider: 'openai',
  name: 'Coding Agent Key',
  humanOwner: 'alice@company.com',
  config: {
    provider: 'openai',
    organizationId: 'org-abc123',
    projectId: 'proj-xyz',
    keyType: 'service-account',
  },
  tags: ['production', 'coding-agent'],
}, {
  type: 'api-key',
  key: 'sk-admin-...',  // Admin key for provisioning
});

if (passport) {
  console.log('Passport created:', passport.id);
  console.log('Key ID:', credential.providerKeyId);
}

Provider Examples

AWS (STS Temporary Credentials)

const { credential, passport } = await provisionAndCreatePassport(vault, {
  provider: 'aws',
  name: 'Data Pipeline Agent',
  humanOwner: 'bob@company.com',
  config: {
    provider: 'aws',
    roleArn: 'arn:aws:iam::123456789:role/DataPipelineRole',
    sessionName: 'id-wispera-pipeline',
    durationSeconds: 3600,
  },
  permissions: {
    provider: 'aws',
    sessionPolicy: JSON.stringify({
      Version: '2012-10-17',
      Statement: [{ Effect: 'Allow', Action: 's3:GetObject', Resource: 'arn:aws:s3:::data-bucket/*' }],
    }),
  },
  tags: ['data-pipeline', 'temporary'],
}, {
  type: 'aws-sigv4',
  accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
  secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
});

Google Cloud (API Key)

const { credential, passport } = await provisionAndCreatePassport(vault, {
  provider: 'google-cloud',
  name: 'Translation API Key',
  humanOwner: 'alice@company.com',
  config: {
    provider: 'google-cloud',
    projectId: 'my-project-123',
    keyType: 'api-key',
    apiTargets: ['translate.googleapis.com'],
    allowedIps: ['203.0.113.0/24'],
  },
  tags: ['translation', 'restricted'],
}, {
  type: 'service-account',
  keyFile: process.env.GOOGLE_APPLICATION_CREDENTIALS!,
});

Google Cloud (Service Account Key)

const { credential, passport } = await provisionAndCreatePassport(vault, {
  provider: 'google-cloud',
  name: 'ML Pipeline SA Key',
  humanOwner: 'data-team@company.com',
  config: {
    provider: 'google-cloud',
    projectId: 'ml-project',
    keyType: 'service-account-key',
    serviceAccountEmail: 'ml-pipeline@ml-project.iam.gserviceaccount.com',
  },
  permissions: {
    provider: 'google-cloud',
    roles: ['roles/storage.objectViewer', 'roles/bigquery.dataViewer'],
  },
  tags: ['ml-pipeline'],
}, {
  type: 'service-account',
  keyFile: process.env.GOOGLE_APPLICATION_CREDENTIALS!,
});

Azure Entra (App Registration + Secret)

const { credential, passport } = await provisionAndCreatePassport(vault, {
  provider: 'azure-entra',
  name: 'Agent App Secret',
  humanOwner: 'admin@company.com',
  config: {
    provider: 'azure-entra',
    tenantId: 'your-tenant-id',
    mode: 'create-app',
    displayName: 'ID Wispera Agent',
    secretExpiryDays: 180,
  },
  permissions: {
    provider: 'azure-entra',
    graphPermissions: ['User.Read', 'Mail.Send'],
  },
  tags: ['azure', 'agent'],
}, {
  type: 'oauth2',
  clientId: process.env.AZURE_CLIENT_ID!,
  clientSecret: process.env.AZURE_CLIENT_SECRET!,
  tenantId: 'your-tenant-id',
});

GitHub (Installation Access Token)

const { credential, passport } = await provisionAndCreatePassport(vault, {
  provider: 'github',
  name: 'CI/CD Agent Token',
  humanOwner: 'devops@company.com',
  config: {
    provider: 'github',
    installationId: 12345678,
    repositories: ['my-org/my-repo', 'my-org/other-repo'],
  },
  permissions: {
    provider: 'github',
    permissions: {
      contents: 'read',
      pull_requests: 'write',
      issues: 'read',
    },
  },
  tags: ['ci-cd', 'github'],
}, {
  type: 'jwt',
  privateKey: process.env.GITHUB_APP_PRIVATE_KEY!,
  appId: process.env.GITHUB_APP_ID!,
});

// Token expires in 1 hour
console.log('Expires:', credential.expiresAt);

Twilio (API Key)

const { credential, passport } = await provisionAndCreatePassport(vault, {
  provider: 'twilio',
  name: 'SMS Agent Key',
  humanOwner: 'comms@company.com',
  config: {
    provider: 'twilio',
    accountSid: 'ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
    keyType: 'standard',
    friendlyName: 'ID Wispera SMS Agent',
  },
  tags: ['sms', 'twilio'],
}, {
  type: 'basic',
  username: 'ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
  password: process.env.TWILIO_AUTH_TOKEN!,
});

SendGrid (Scoped API Key)

const { credential, passport } = await provisionAndCreatePassport(vault, {
  provider: 'sendgrid',
  name: 'Email Agent Key',
  humanOwner: 'comms@company.com',
  config: { provider: 'sendgrid' },
  permissions: {
    provider: 'sendgrid',
    scopes: ['mail.send', 'mail.batch.read'],
  },
  tags: ['email', 'sendgrid'],
}, {
  type: 'api-key',
  key: process.env.SENDGRID_API_KEY!,
});

Anthropic (Management Only)

import { listProviderKeys, revokeAtSource } from '@id-wispera/core';

// List existing keys
const keys = await listProviderKeys('anthropic', {
  type: 'api-key',
  key: process.env.ANTHROPIC_ADMIN_KEY!,
});

console.log('Existing keys:', keys);

// Disable a key
const result = await revokeAtSource('anthropic', 'key-to-disable', {
  type: 'api-key',
  key: process.env.ANTHROPIC_ADMIN_KEY!,
});

console.log('Disabled:', result.success);

Provider Capabilities

const caps = getProviderCapabilities('openai');  // null if unknown provider
const providers = listProviders();               // [{ provider, capabilities }]

Key Rotation

Rotation creates a new key and returns the old key ID for later revocation.
After rotation, revoke the old key at the source to ensure it can no longer be used. The two-step pattern (rotate then revoke) avoids downtime during the switchover window.
import { rotateCredential, revokeAtSource } from '@id-wispera/core';

const rotation = await rotateCredential('openai', 'old-key-id', {
  provider: 'openai',
  name: 'Coding Agent Key (rotated)',
  humanOwner: 'alice@company.com',
  config: { provider: 'openai', organizationId: 'org-abc123', keyType: 'service-account' },
}, auth);

if (rotation) {
  console.log('New key:', rotation.newCredential.providerKeyId);
  console.log('Revoke old key after', rotation.recommendedRevocationDelay, 'seconds');

  // After propagation delay...
  const revoked = await revokeAtSource('openai', rotation.oldKeyId, auth);
  console.log('Old key revoked:', revoked.success);
}

Revoking at Source

Permanently disable a key at the vendor.
const result = await revokeAtSource('openai', 'key-id-to-revoke', auth);

Authentication

Each provider requires a specific auth type.
Never hard-code admin credentials in source code. Run idw auth bootstrap to store them as privilege passports in the vault. When the auth parameter is omitted, provisionAndCreatePassport() resolves admin credentials from the vault automatically.

OpenAI

Admin API key (sk-admin-...):
const auth = { type: 'api-key', key: 'sk-admin-...' };

AWS

IAM access key with SigV4 signing:
const auth = { type: 'aws-sigv4', accessKeyId: 'AKIA...', secretAccessKey: '...', region: 'us-east-1' };

Google Cloud

Service account key file or OAuth2 client credentials:
// Service account (recommended)
const auth = { type: 'service-account', keyFile: require('./service-account.json') };

// OAuth2 client credentials
const auth = { type: 'oauth2', clientId: '...', clientSecret: '...' };

Azure Entra

OAuth2 client credentials with tenant ID:
const auth = { type: 'oauth2', clientId: '...', clientSecret: '...', tenantId: 'your-tenant-id' };

GitHub

GitHub App private key + App ID:
const auth = { type: 'jwt', privateKey: fs.readFileSync('private-key.pem', 'utf8'), appId: '12345' };

Twilio

Account SID + Auth Token (Basic auth):
const auth = { type: 'basic', username: 'ACxxxx...', password: 'your-auth-token' };

SendGrid

Full-access API key (Bearer):
const auth = { type: 'api-key', key: 'SG.xxxx...' };

Anthropic

Admin API key (management only):
const auth = { type: 'api-key', key: 'sk-ant-admin-...' };

CLI Provisioning

The idw provision command provides CLI access to the provisioning module, enabling you to create, rotate, and list scoped credentials directly from the terminal.

Create a credential

idw provision <provider> --project <name> [--scope <scopes>] [--ttl <duration>]

Rotate an existing credential

idw provision rotate <provider> --passport <id>

List provisioned credentials

idw provision list <provider>

CLI Reference

CommandDescription
idw provision <provider>Provision a new scoped credential at the specified provider
idw provision rotate <provider> --passport <id>Rotate an existing provisioned credential
idw provision list <provider>List all provisioned credentials at the specified provider
Prerequisites: Run idw auth bootstrap <provider> first to store your admin credentials in the vault. The idw provision command requires the latest version of the CLI.

Best Practices

  1. Use provisionAndCreatePassport for the unified workflow. This ensures every provisioned key immediately gets a passport with audit trail and policy enforcement.
  2. Store admin keys in the vault too. Run idw auth bootstrap to store provider admin credentials as privilege passports. Provisioning then resolves auth automatically.
  3. Rotate regularly. Use rotateCredential on a schedule. The function handles create-before-revoke to avoid downtime.
  4. Set expiry where supported. For AWS STS credentials, use expiresIn to create short-lived tokens. For Azure Entra, set secretExpiryDays to limit secret lifetime.
  5. Tag provisioned passports. Use tags like provisioned, production, or the provider name to make it easy to find and audit provisioned credentials.
  6. Prefer scoped credentials. Use project-scoped keys (OpenAI), STS temporary credentials (AWS), API restrictions (Google Cloud), and fine-grained permissions (GitHub) to follow the principle of least privilege.
  7. GitHub tokens are short-lived. Installation access tokens expire in 1 hour. Use rotateCredential to refresh them before expiry.
  8. Anthropic is management-only. Create keys manually at console.anthropic.com, then use ID Wispera to list, track, and disable them.

Next Steps

Scan & import

Discover existing credentials on disk and import them into the vault.

Policy engine

Enforce governance rules on provisioned passports automatically.

Audit log

Review the full lifecycle of every provisioned credential.