or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

cognito-credentials.mdconfiguration-file-credentials.mdcustom-credential-chains.mddefault-provider-chain.mdenvironment-credentials.mdhttp-credentials.mdindex.mdmetadata-service-credentials.mdprocess-credentials.mdsso-credentials.mdtemporary-credentials.mdweb-identity-credentials.md
tile.json

custom-credential-chains.mddocs/

Custom Credential Chains

Custom credential chain functionality allows building flexible credential provider sequences that try multiple credential sources in order, with automatic expiration and refresh capabilities.

Capabilities

Credential Chain Builder

Creates a custom credential provider chain from multiple credential providers.

/**
 * Creates a credential chain from multiple credential providers that are tried in sequence
 * @param credentialProviders - One or more credential providers to chain together
 * @returns Chainable credential provider with expiration control
 */
function createCredentialChain(
  ...credentialProviders: RuntimeConfigAwsCredentialIdentityProvider[]
): RuntimeConfigAwsCredentialIdentityProvider & CustomCredentialChainOptions;

interface CustomCredentialChainOptions {
  /** Sets credential expiration time to force refresh after specified milliseconds */
  expireAfter(milliseconds: number): AwsCredentialIdentityProvider & CustomCredentialChainOptions;
}

Usage Examples:

import { S3Client } from "@aws-sdk/client-s3";
import { 
  createCredentialChain, 
  fromEnv, 
  fromIni, 
  fromInstanceMetadata 
} from "@aws-sdk/credential-providers";

// Basic credential chain
const client = new S3Client({
  region: "us-east-1",
  credentials: createCredentialChain(
    fromEnv(),
    fromIni(),
    fromInstanceMetadata()
  )
});

// Chain with custom expiration
const expiringClient = new S3Client({
  region: "us-east-1",
  credentials: createCredentialChain(
    fromEnv(),
    fromIni({ profile: "default" })
  ).expireAfter(15 * 60 * 1000) // 15 minutes
});

// Complex chain with multiple profiles and sources
const complexClient = new S3Client({
  region: "us-east-1",
  credentials: createCredentialChain(
    fromEnv(),
    fromIni({ profile: "development" }),
    fromIni({ profile: "default" }),
    fromInstanceMetadata()
  )
});

Chain Execution Behavior

Credential chains follow this execution pattern:

  1. Sequential Evaluation: Providers are tried in the order specified
  2. First Success Wins: Chain stops on first successful credential resolution
  3. Error Propagation: Fatal errors stop the chain, retriable errors continue to next provider
  4. All Providers Failed: If all providers fail, the last error is thrown
import { createCredentialChain, fromEnv, fromIni } from "@aws-sdk/credential-providers";

const chainWithLogging = createCredentialChain(
  fromEnv({ logger: console }), // Try environment variables first
  fromIni({ 
    profile: "backup-profile",
    logger: console 
  }) // Fallback to INI file
);

// This will:
// 1. Try environment variables
// 2. If that fails, try the backup-profile from INI
// 3. If both fail, throw the last error

Custom Credential Functions

Mix existing providers with custom credential functions:

import { createCredentialChain, fromEnv, fromIni } from "@aws-sdk/credential-providers";

// Custom credential function
async function fromCustomSource(): Promise<AwsCredentialIdentity> {
  // Fetch credentials from your custom source
  // e.g., corporate credential management system, vault, etc.
  const response = await fetch("https://internal-auth.company.com/credentials");
  const data = await response.json();
  
  return {
    accessKeyId: data.accessKey,
    secretAccessKey: data.secretKey,
    sessionToken: data.sessionToken,
    expiration: new Date(data.expiresAt)
  };
}

// Create chain with custom provider
const client = new S3Client({
  region: "us-east-1",
  credentials: createCredentialChain(
    fromEnv(),
    fromCustomSource,
    fromIni()
  )
});

Expiration Control

Set automatic credential expiration to force periodic refresh:

import { createCredentialChain, fromEnv, fromIni } from "@aws-sdk/credential-providers";

// Credentials expire after 30 minutes
const thirtyMinuteCredentials = createCredentialChain(
  fromEnv(),
  fromIni()
).expireAfter(30 * 60 * 1000);

// Minimum expiration is 5 minutes
try {
  const tooShort = createCredentialChain(fromEnv()).expireAfter(60 * 1000); // 1 minute
} catch (error) {
  console.error(error.message); 
  // "@aws-sdk/credential-providers - createCredentialChain(...).expireAfter(ms) may not be called with a duration lower than five minutes."
}

Shared Configuration Across Providers

Apply shared initialization properties to all providers in the chain:

import { createCredentialChain, fromEnv, fromIni } from "@aws-sdk/credential-providers";

// Shared configuration
const sharedInit = { 
  logger: console,
  clientConfig: { 
    maxAttempts: 3,
    requestTimeout: 10000 
  }
};

const client = new S3Client({
  region: "us-east-1",
  credentials: createCredentialChain(
    fromEnv(sharedInit),
    fromIni({
      ...sharedInit,
      profile: "development"
    })
  )
});

Environment-Specific Chains

Create different chains for different environments:

import { 
  createCredentialChain, 
  fromEnv, 
  fromIni, 
  fromInstanceMetadata,
  fromContainerMetadata 
} from "@aws-sdk/credential-providers";

function createCredentialsForEnvironment(environment: string) {
  switch (environment) {
    case "development":
      return createCredentialChain(
        fromEnv(),
        fromIni({ profile: "dev" })
      );
    
    case "testing":
      return createCredentialChain(
        fromEnv(),
        fromIni({ profile: "test" })
      );
    
    case "production":
      return createCredentialChain(
        fromInstanceMetadata(), // EC2 instances
        fromContainerMetadata(), // ECS containers
        fromEnv() // Fallback to environment
      );
    
    default:
      return createCredentialChain(
        fromEnv(),
        fromIni()
      );
  }
}

const client = new S3Client({
  region: "us-east-1",
  credentials: createCredentialsForEnvironment(process.env.NODE_ENV || "development")
});

Error Handling and Debugging

Handle chain failures and debug credential resolution:

import { createCredentialChain, fromEnv, fromIni } from "@aws-sdk/credential-providers";

const debugChain = createCredentialChain(
  fromEnv({ logger: console }),
  fromIni({ 
    profile: "nonexistent",
    logger: console 
  })
);

try {
  const credentials = await debugChain();
  console.log("Credentials resolved successfully");
} catch (error) {
  console.error("All credential providers in chain failed:");
  console.error("Final error:", error.message);
  
  // Check specific error types
  if (error.name === "ProviderError") {
    console.error("No providers in chain succeeded");
  }
}

Advanced Chain Patterns

Conditional Provider Chain

import { createCredentialChain, fromEnv, fromIni, fromInstanceMetadata } from "@aws-sdk/credential-providers";

function createAdaptiveChain() {
  const providers = [fromEnv()];
  
  // Add profile-based provider if profile is available
  if (process.env.AWS_PROFILE) {
    providers.push(fromIni({ profile: process.env.AWS_PROFILE }));
  }
  
  // Add metadata provider if running on AWS
  if (process.env.AWS_EXECUTION_ENV || process.env.AWS_LAMBDA_FUNCTION_NAME) {
    providers.push(fromInstanceMetadata());
  }
  
  return createCredentialChain(...providers);
}

Retry-Enhanced Chain

import { createCredentialChain, fromEnv, fromIni } from "@aws-sdk/credential-providers";

function withRetry<T extends (...args: any[]) => any>(fn: T, maxRetries = 3): T {
  return (async (...args: any[]) => {
    let lastError;
    for (let i = 0; i <= maxRetries; i++) {
      try {
        return await fn(...args);
      } catch (error) {
        lastError = error;
        if (i < maxRetries) {
          await new Promise(resolve => setTimeout(resolve, 1000 * Math.pow(2, i)));
        }
      }
    }
    throw lastError;
  }) as T;
}

const resilientChain = createCredentialChain(
  withRetry(fromEnv()),
  withRetry(fromIni())
);

Performance Considerations

  • Chain Length: Keep chains reasonably short to minimize latency
  • Provider Order: Place fastest/most likely providers first
  • Caching: Individual providers handle their own caching
  • Expiration: Use expireAfter() judiciously to balance security and performance

Availability

  • Node.js: ✅ Available
  • Browser: ❌ Not available (most chained providers are Node.js only)
  • React Native: ❌ Not available