Skip to content

Credentials API Reference

Complete API reference for credential management operations. Understand n8n's security model and implement schema-driven credential creation.


Overview

The Credentials API provides programmatic access to create and manage workflow credentials with strong security restrictions.

Available Operations:

Operation Purpose Status Notes
get_credential_schema Get credential type schema ✅ Available Essential for creation
create_credential Create new credential ✅ Available Schema-driven
delete_credential Remove credential ✅ Available Permanent
list_credentials List credentials ❌ Blocked Security restriction
get_credential Get credential data ❌ Blocked Security restriction
update_credential Update credential ⚠️ Workaround Use DELETE + CREATE

Security Model

n8n Credential Security (Epic 2)

n8n intentionally blocks LIST and GET operations for credentials via REST API to prevent credential exposure and unauthorized access.

Security Architecture:

Credentials in n8n Database
Encrypted with AES-256
REST API Blocks List/Get Operations
Only n8n UI can view credentials
MCP Server References by ID Only

Blocked Operations:

  • list_credentials - Returns security guidance, not credential list
  • get_credential - Returns security guidance, not credential data

Why This Matters:

  1. Prevents Credential Theft: API cannot be used to extract credentials
  2. Reduces Attack Surface: Limits credential access points
  3. Centralized Management: Forces credential management through secure n8n UI
  4. Audit Trail: All credential access logged in n8n

Available Operations:

  • get_credential_schema - Get field requirements for credential types
  • create_credential - Schema-driven creation with encrypted storage
  • delete_credential - Permanent removal
  • ⚠️ update_credential - Use DELETE + CREATE pattern (immutability)

Recommended Approach:

Manage credentials through n8n UI for visibility and control. Use MCP server only for programmatic creation of simple credential types.


get_credential_schema

Retrieve JSON schema for a credential type to understand required fields and validation rules.

Purpose

Get field requirements before creating credentials. Essential for schema-driven creation pattern and validation.

Use Cases

  • Understanding required fields for credential type
  • Validating user input before credential creation
  • Building credential creation UIs
  • Documenting credential requirements

Request

MCP Tool Name: get_credential_schema

Parameters:

Parameter Type Required Description
instance string No Instance identifier
type string Yes Credential type name

TypeScript Interface:

interface GetCredentialSchemaParams {
  instance?: string;
  type: string;
}

Common Credential Types:

// Authentication
'httpBasicAuth'           // Basic HTTP authentication
'httpHeaderAuth'          // HTTP header authentication
'httpDigestAuth'          // Digest authentication
'oAuth1Api'               // OAuth 1.0
'oAuth2Api'               // OAuth 2.0

// Services
'googleSheetsOAuth2Api'   // Google Sheets
'slackApi'                // Slack
'slackOAuth2Api'          // Slack OAuth2
'gmailOAuth2'             // Gmail
'discordApi'              // Discord

// Databases
'postgresDb'              // PostgreSQL
'mysqlDb'                 // MySQL
'mongoDb'                 // MongoDB
'redis'                   // Redis

// And 100+ more types in n8n...

Response

TypeScript Interface:

interface CredentialSchema {
  type: 'object';
  properties: CredentialProperty[];
}

interface CredentialProperty {
  name: string;
  type: 'string' | 'number' | 'boolean' | 'options';
  required: boolean;
  displayName: string;
  description?: string;
  default?: any;
  options?: PropertyOption[];
  placeholder?: string;
  typeOptions?: {
    password?: boolean;
    multipleValues?: boolean;
  };
}

interface PropertyOption {
  name: string;
  value: any;
}

Response Examples

httpBasicAuth Schema:

{
  "type": "object",
  "properties": [
    {
      "name": "user",
      "type": "string",
      "required": true,
      "displayName": "User",
      "description": "Username for basic authentication"
    },
    {
      "name": "password",
      "type": "string",
      "required": true,
      "displayName": "Password",
      "description": "Password for basic authentication",
      "typeOptions": {
        "password": true
      }
    }
  ]
}

postgresDb Schema:

{
  "type": "object",
  "properties": [
    {
      "name": "host",
      "type": "string",
      "required": true,
      "displayName": "Host",
      "default": "localhost"
    },
    {
      "name": "port",
      "type": "number",
      "required": true,
      "displayName": "Database Port",
      "default": 5432
    },
    {
      "name": "database",
      "type": "string",
      "required": true,
      "displayName": "Database Name"
    },
    {
      "name": "user",
      "type": "string",
      "required": true,
      "displayName": "User"
    },
    {
      "name": "password",
      "type": "string",
      "required": true,
      "displayName": "Password",
      "typeOptions": {
        "password": true
      }
    },
    {
      "name": "ssl",
      "type": "options",
      "required": false,
      "displayName": "SSL",
      "options": [
        { "name": "Disable", "value": "disable" },
        { "name": "Allow", "value": "allow" },
        { "name": "Require", "value": "require" }
      ],
      "default": "disable"
    }
  ]
}

Code Example

// Get schema for HTTP Basic Auth
const schema = await callTool('get_credential_schema', {
  instance: 'production',
  type: 'httpBasicAuth'
});

const credSchema = JSON.parse(schema.content[0].text);

console.log('Required fields:');
credSchema.properties
  .filter(p => p.required)
  .forEach(p => {
    console.log(`  - ${p.name}: ${p.displayName}`);
    if (p.description) {
      console.log(`    ${p.description}`);
    }
  });

// Output:
// Required fields:
//   - user: User
//     Username for basic authentication
//   - password: Password
//     Password for basic authentication

create_credential

Create new credential using schema-driven approach with encrypted storage.

Purpose

Programmatically create credentials for workflow nodes. Credentials are encrypted and stored securely in n8n database.

Use Cases

  • CI/CD credential provisioning
  • Bulk credential creation from templates
  • Programmatic credential setup
  • Testing and development environments

Request

MCP Tool Name: create_credential

Parameters:

Parameter Type Required Description
instance string No Instance identifier
name string Yes Credential name (descriptive)
type string Yes Credential type (from schema)
data object Yes Credential data (schema-specific fields)
nodesAccess object[] No Node access restrictions

TypeScript Interface:

interface CreateCredentialParams {
  instance?: string;
  name: string;
  type: string;
  data: Record<string, any>;
  nodesAccess?: NodeAccess[];
}

interface NodeAccess {
  nodeType: string;
}

Schema-Driven Creation Pattern

Step 1: Get Schema

const schemaResponse = await callTool('get_credential_schema', {
  type: 'httpBasicAuth',
  instance: 'production'
});

const schema = JSON.parse(schemaResponse.content[0].text);

Step 2: Validate Data Against Schema

function validateCredentialData(
  data: Record<string, any>,
  schema: CredentialSchema
): void {
  // Check required fields
  const required = schema.properties
    .filter(p => p.required)
    .map(p => p.name);

  const missing = required.filter(field => !data[field]);

  if (missing.length > 0) {
    throw new Error(
      `Missing required fields: ${missing.join(', ')}`
    );
  }

  // Validate field types
  for (const prop of schema.properties) {
    if (data[prop.name] !== undefined) {
      const actualType = typeof data[prop.name];
      const expectedType = prop.type;

      if (expectedType === 'number' && actualType !== 'number') {
        throw new Error(
          `Field '${prop.name}' must be a number, got ${actualType}`
        );
      }

      if (expectedType === 'string' && actualType !== 'string') {
        throw new Error(
          `Field '${prop.name}' must be a string, got ${actualType}`
        );
      }
    }
  }
}

// Usage
validateCredentialData(credentialData, schema);

Step 3: Create Credential

const credential = await callTool('create_credential', {
  instance: 'production',
  name: 'API Basic Auth',
  type: 'httpBasicAuth',
  data: {
    user: process.env.API_USER,
    password: process.env.API_PASSWORD
  }
});

const result = JSON.parse(credential.content[0].text);
console.log(`Created credential: ${result.id}`);

Response

Success Response:

interface CreateCredentialResponse {
  id: string;
  name: string;
  type: string;
  createdAt: string;
  updatedAt: string;
  nodesAccess?: NodeAccess[];
}

Important: data field is NEVER returned for security reasons.

JSON Example:

{
  "id": "cred_abc123",
  "name": "API Basic Auth",
  "type": "httpBasicAuth",
  "createdAt": "2025-01-15T10:00:00Z",
  "updatedAt": "2025-01-15T10:00:00Z"
}

Complete Creation Examples

HTTP Basic Auth:

// Step 1: Get schema
const schema = await callTool('get_credential_schema', {
  type: 'httpBasicAuth'
});

// Step 2: Create credential
const credential = await callTool('create_credential', {
  instance: 'production',
  name: 'External API Credentials',
  type: 'httpBasicAuth',
  data: {
    user: 'api_user',
    password: 'secure_password_here'
  }
});

const result = JSON.parse(credential.content[0].text);
console.log(`Credential ID: ${result.id}`);

PostgreSQL Database:

const postgresCredential = await callTool('create_credential', {
  instance: 'production',
  name: 'Production Database',
  type: 'postgresDb',
  data: {
    host: 'db.example.com',
    port: 5432,
    database: 'production_db',
    user: 'dbuser',
    password: process.env.DB_PASSWORD,
    ssl: 'require'
  }
});

Slack API:

const slackCredential = await callTool('create_credential', {
  instance: 'production',
  name: 'Slack Bot Token',
  type: 'slackApi',
  data: {
    accessToken: process.env.SLACK_BOT_TOKEN
  }
});

UPDATE Pattern (DELETE + CREATE)

n8n does not support direct credential updates due to security and immutability.

Workaround: Delete old credential and create new one.

async function updateCredential(
  credentialId: string,
  newData: CreateCredentialParams,
  instance?: string
): Promise<CreateCredentialResponse> {
  console.log(`Updating credential ${credentialId}...`);

  // Step 1: Delete old credential
  await callTool('delete_credential', {
    id: credentialId,
    instance
  });
  console.log('Old credential deleted');

  // Step 2: Create new credential with updated data
  const newCredential = await callTool('create_credential', {
    ...newData,
    instance
  });

  const result = JSON.parse(newCredential.content[0].text);

  console.log(`Credential updated: ${credentialId}${result.id}`);
  console.log('⚠️  Note: Credential ID changed. Update workflow references!');

  return result;
}

// Usage
const updated = await updateCredential(
  'cred_old123',
  {
    name: 'API Basic Auth',
    type: 'httpBasicAuth',
    data: {
      user: 'new_user',
      password: 'new_password'
    }
  },
  'production'
);

Important: Workflows using old credential ID will break. Update workflow credential references after recreation:

async function updateWorkflowCredentials(
  workflowId: string,
  oldCredentialId: string,
  newCredentialId: string,
  instance?: string
): Promise<void> {
  // Get workflow
  const workflow = await callTool('get_workflow', {
    id: workflowId,
    instance
  });

  const wf = JSON.parse(workflow.content[0].text);

  // Update credential references
  wf.nodes.forEach(node => {
    if (node.credentials) {
      for (const [type, cred] of Object.entries(node.credentials)) {
        if (cred.id === oldCredentialId) {
          cred.id = newCredentialId;
          console.log(`Updated credential in node: ${node.name}`);
        }
      }
    }
  });

  // Save workflow
  await callTool('update_workflow', {
    id: workflowId,
    instance,
    nodes: wf.nodes
  });

  console.log(`Workflow ${workflowId} credential references updated`);
}

delete_credential

Remove credential permanently from instance.

Request

Parameters:

Parameter Type Required Description
instance string No Instance identifier
id string Yes Credential ID to delete

Code Example

await callTool('delete_credential', {
  instance: 'staging',
  id: 'cred_test123'
});

console.log('Credential deleted successfully');

Warning: - Deletion is permanent and cannot be undone - Workflows using this credential will fail - Remove credential references from workflows first


list_credentials

Status: ❌ Blocked by n8n API for security

Security Guidance

This operation is intentionally blocked by n8n's REST API to prevent credential exposure.

What Happens:

const response = await callTool('list_credentials', {
  instance: 'production'
});

// Returns security guidance, not credentials

Response:

{
  "message": "Credential listing is blocked by n8n API for security.",
  "reason": "Credentials are encrypted and should only be managed through n8n UI",
  "recommendation": "Use n8n web interface to view and manage credentials",
  "alternatives": [
    "View credentials in n8n UI: Settings → Credentials",
    "Track credential IDs during creation",
    "Use credential references by ID in workflows"
  ]
}

get_credential

Status: ❌ Blocked by n8n API for security

Security Guidance

This operation is intentionally blocked to prevent credential data exposure.

What Happens:

const response = await callTool('get_credential', {
  id: 'cred_123',
  instance: 'production'
});

// Returns security guidance, not credential data

Alternatives:

  1. View in n8n UI: Settings → Credentials → Select credential
  2. Track During Creation: Store credential IDs when created
  3. Reference by ID: Use credential ID in workflow nodes

Best Practices

1. Never Hardcode Credentials

// ❌ Bad: Hardcoded credentials in code
const cred = await callTool('create_credential', {
  type: 'httpBasicAuth',
  data: {
    user: 'admin',
    password: 'password123'  // NEVER do this!
  }
});

// ✅ Good: Use environment variables
const cred = await callTool('create_credential', {
  type: 'httpBasicAuth',
  data: {
    user: process.env.API_USER,
    password: process.env.API_PASSWORD
  }
});

// ✅ Good: Load from secure vault
import { getSecret } from './secure-vault';

const cred = await callTool('create_credential', {
  type: 'httpBasicAuth',
  data: {
    user: await getSecret('api_user'),
    password: await getSecret('api_password')
  }
});

2. Always Use Schema Validation

// ✅ Good: Schema-driven creation
async function createValidatedCredential(
  type: string,
  name: string,
  data: Record<string, any>,
  instance?: string
) {
  // Get schema
  const schemaResponse = await callTool('get_credential_schema', {
    type,
    instance
  });
  const schema = JSON.parse(schemaResponse.content[0].text);

  // Validate
  validateCredentialData(data, schema);

  // Create
  return await callTool('create_credential', {
    instance,
    name,
    type,
    data
  });
}

// ❌ Bad: Guessing fields without schema
const cred = await callTool('create_credential', {
  type: 'unknownType',
  data: {
    field1: 'value',  // May be wrong!
    field2: 'value'   // May be missing required fields!
  }
});

3. Manage Complex Credentials via UI

For OAuth2, JWT, and other complex credential types:

// ✅ Recommended: Use n8n UI for complex types
// - OAuth2 with multiple steps
// - JWT with key generation
// - Service accounts with JSON key files
// - SSH keys

// ✅ Good: Use MCP for simple types
// - HTTP Basic Auth
// - API keys
// - Database credentials
// - Simple tokens

4. Track Credential IDs

// ✅ Good: Track credential IDs for reference
const credentialRegistry: Record<string, string> = {};

async function createAndTrackCredential(
  name: string,
  type: string,
  data: Record<string, any>,
  instance?: string
) {
  const response = await callTool('create_credential', {
    instance,
    name,
    type,
    data
  });

  const credential = JSON.parse(response.content[0].text);

  // Track for later reference
  const key = `${instance || 'default'}-${name}`;
  credentialRegistry[key] = credential.id;

  console.log(`Created and tracked: ${key}${credential.id}`);

  return credential;
}

// Later: retrieve credential ID
const credId = credentialRegistry['production-API Basic Auth'];

5. Secure Credential Lifecycle

// Complete secure credential lifecycle
async function secureCredentialLifecycle() {
  // 1. Get schema
  const schema = await callTool('get_credential_schema', {
    type: 'httpBasicAuth'
  });

  // 2. Load secrets from secure vault (never hardcode!)
  const secrets = await loadSecretsFromVault();

  // 3. Validate against schema
  validateCredentialData(secrets, schema);

  // 4. Create credential
  const credential = await callTool('create_credential', {
    instance: 'production',
    name: 'Secure API Credentials',
    type: 'httpBasicAuth',
    data: secrets
  });

  // 5. Track credential ID (don't track data!)
  saveCredentialId(credential.id);

  // 6. Clear secrets from memory
  Object.keys(secrets).forEach(key => delete secrets[key]);

  // 7. Use in workflows by reference
  return credential.id;
}

Next Steps


Document Version: 1.0 Last Updated: January 2025 Related Epic: Epic 2 (Credentials API Implementation) Security Note: Always follow security best practices when handling credentials