Skip to main content

Integrate SSO into Your Code

Use AWS Single Sign-On (SSO) profiles locally and Identity and Access Management (IAM) roles in the cloud for secure, environment-aware access.

Development Principles

  • Local vs. cloud: Use SSO profiles for local development; use IAM roles in cloud environments
  • Least privilege: Grant only the permissions your application needs
  • No hardcoded secrets: Never store access keys or sensitive data in code or .env files
  • Consistent naming: Reuse the same profile name across projects (e.g., <project>-workload-development)

Credential Resolution Overview

Your app decides credentials depending on the runtime environment:

Environment Detection Pattern

Use a simple, reliable signal like AWS_PROFILE, .env.local, or NODE_ENV=development.
import os, pathlib

def is_local():
    return bool(os.getenv("AWS_PROFILE")) \
        or os.getenv("NODE_ENV") == "development" \
        or pathlib.Path(".env.local").exists()

Python Example (boto3)

Installation

# Install required packages
pip install boto3

Basic Implementation

  • Environment Variable Method
  • Direct Profile Method
  • Class-Based Approach
def create_aws_client(service_name='s3'):
    """
    - Local: uses SSO profile if AWS_PROFILE is set
    - Cloud: falls back to default chain (instance/role)
    """
    profile = os.environ.get("AWS_PROFILE")
    region = os.environ.get("AWS_REGION", "us-west-2")

    if profile:
        try:
            boto3.setup_default_session(profile_name=profile, region_name=region)
        except ProfileNotFound as e:
            raise RuntimeError(f"AWS profile '{profile}' not found") from e
    else:
        boto3.setup_default_session(region_name=region)

    return boto3.client(service_name)

if __name__ == "__main__":
    s3 = create_aws_client('s3')
    resp = s3.list_buckets()
    print([b['Name'] for b in resp.get('Buckets', [])])

Environment Configuration

# Set profile for your development session
export AWS_PROFILE=<project>-<development_workload_account>
export AWS_REGION=us-west-2

# Run your Python application
python app.py

Node.js Example (AWS SDK v3)

Installation

# Install required packages
npm install @aws-sdk/client-s3 @aws-sdk/credential-providers

Implementation Examples

  • Environment Variable Method
  • Direct Profile Method
  • Configuration Manager
import { S3Client, ListBucketsCommand } from '@aws-sdk/client-s3';
import { fromSSO } from '@aws-sdk/credential-providers';

/**
 * Create AWS client with environment-based credentials
 */
function createS3() {
const region = process.env.AWS_REGION || 'us-west-2';
const profile = process.env.AWS_PROFILE;

if (profile) {
    // Local with SSO
    return new S3Client({
    region,
    credentials: fromSSO({ profile })
    });
}
// Cloud: default provider chain (role)
return new S3Client({ region });
}

export async function listS3Buckets() {
const s3 = createS3();
const out = await s3.send(new ListBucketsCommand({}));
console.log('S3 Buckets:', out.Buckets?.map(b => b.Name));
return out.Buckets;
}

// Run example
listS3Buckets().catch(console.error);

Environment Configuration

# Set environment variables
export NODE_ENV=development
export AWS_PROFILE=<project>-<production_workload_account>
export AWS_REGION=us-west-2

# Run your Node.js application
npm start

Go Example

For Go applications, AWS provides excellent SSO support through the official SDK.

Installation

go get github.com/aws/aws-sdk-go-v2/aws
go get github.com/aws/aws-sdk-go-v2/config
go get github.com/aws/aws-sdk-go-v2/service/s3

Implementation

  • Basic Configuration
  • Advanced Configuration
import (
    "context"
    "fmt"
    "log"
    "os"

    "github.com/aws/aws-sdk-go-v2/aws"
    "github.com/aws/aws-sdk-go-v2/config"
    "github.com/aws/aws-sdk-go-v2/service/s3"
)

func newConfig(ctx context.Context) (aws.Config, error) {
    profile := os.Getenv("AWS_PROFILE")
    region  := os.Getenv("AWS_REGION")
    if profile != "" {
        return config.LoadDefaultConfig(ctx,
            config.WithSharedConfigProfile(profile),
            config.WithRegion(region),
        )
    }
    // Cloud: default chain (role)
    return config.LoadDefaultConfig(ctx, config.WithRegion(region))
}

func main() {
    ctx := context.Background()
    cfg, err := newConfig(ctx)
    if err != nil {
        log.Fatalf("unable to load SDK config: %v", err)
    }
    s3c := s3.NewFromConfig(cfg)
    out, err := s3c.ListBuckets(ctx, &s3.ListBucketsInput{})
    if err != nil {
        log.Fatalf("list buckets failed: %v", err)
    }
    for _, b := range out.Buckets {
        fmt.Println(*b.Name)
    }
}

Development Workflow Best Practices

Environment Setup

Use environment-specific files and variables.
  • .env.local
  • .env.production
# Local development 
NODE_ENV=development
AWS_PROFILE=<project>-<development_workload_account>
AWS_REGION=us-west-2

# APP settings
LOG_LEVEL=debug
API_BASE_URL=https://staging-api.<project>.com

Common Patterns and Tips

Best practices for detecting local vs. cloud environments:
import os,pathlib

def is_local_environment():
    return any([
        os.getenv('AWS_PROFILE'),
        os.getenv('NODE_ENV') == 'development',
        pathlib.Path('.env.local').exists()
    ])
Handle common SSO-related errors gracefully:
from botocore.exceptions import TokenRefreshRequired, ProfileNotFound

def handle_aws_errors(func):
    """Decorator for AWS error handling"""
    def wrapper(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except TokenRefreshRequired:
            print("SSO token expired. Please run: aws sso login")
            raise
        except ProfileNotFound as e:
            print(f"AWS profile not found: {e}")
            raise
        except Exception as e:
            print(f"AWS operation failed: {e}")
            raise
    return wrapper
Validate your configuration before running:
def validate_aws_config():
    """Validate AWS configuration"""
    profile = os.getenv('AWS_PROFILE')
    if not profile:
        raise ValueError("AWS_PROFILE environment variable not set")
    
    # Test connection
    try:
        boto3.client('sts').get_caller_identity()
    except Exception as e:
        raise ValueError(f"AWS configuration invalid: {e}")
    
    return True