Skip to content

AWS Cognito Authentication

AWS Cognito provides enterprise-grade user authentication and management for BoilStream. This guide covers setting up Cognito User Pools for JWT token authentication.

Overview

AWS Cognito integration provides:

  • Enterprise User Management: Centralized user authentication and management
  • JWT Token Validation: Secure token-based authentication using RSA signatures
  • Group-based Authorization: Map Cognito groups to BoilStream permissions
  • OAuth 2.0 Scopes: Fine-grained API access control
  • High Availability: AWS-managed service with 99.99% uptime SLA

Prerequisites

  • AWS Account with appropriate permissions
  • AWS CLI configured (optional, for setup)
  • Cognito User Pool with users and groups configured

AWS Cognito Setup

1. Create User Pool

If you don't have a Cognito User Pool yet, create one:

bash
# Create user pool
aws cognito-idp create-user-pool \
    --pool-name "boilstream-users" \
    --policies '{
        "PasswordPolicy": {
            "MinimumLength": 8,
            "RequireUppercase": true,
            "RequireLowercase": true,
            "RequireNumbers": true,
            "RequireSymbols": false
        }
    }' \
    --auto-verified-attributes "email" \
    --alias-attributes "email"
json
{
  "PoolName": "boilstream-users",
  "Policies": {
    "PasswordPolicy": {
      "MinimumLength": 8,
      "RequireUppercase": true,
      "RequireLowercase": true,
      "RequireNumbers": true,
      "RequireSymbols": false
    }
  },
  "AutoVerifiedAttributes": ["email"],
  "AliasAttributes": ["email"]
}

2. Create User Pool Client

Create an app client for BoilStream:

bash
aws cognito-idp create-user-pool-client \
    --user-pool-id "us-east-1_ABC123DEF" \
    --client-name "boilstream-client" \
    --generate-secret \
    --explicit-auth-flows "ADMIN_NO_SRP_AUTH" "ALLOW_USER_PASSWORD_AUTH" "ALLOW_REFRESH_TOKEN_AUTH" \
    --supported-identity-providers "COGNITO" \
    --token-validity-units '{
        "AccessToken": "hours",
        "IdToken": "hours", 
        "RefreshToken": "days"
    }' \
    --access-token-validity 1 \
    --id-token-validity 1 \
    --refresh-token-validity 30

3. Create Groups

Create groups for authorization mapping:

bash
# Admin group
aws cognito-idp create-group \
    --group-name "boilstream-admins" \
    --user-pool-id "us-east-1_ABC123DEF" \
    --description "BoilStream administrators"

# Write group  
aws cognito-idp create-group \
    --group-name "data-producers" \
    --user-pool-id "us-east-1_ABC123DEF" \
    --description "Data producers and writers"

# Read group
aws cognito-idp create-group \
    --group-name "data-analysts" \
    --user-pool-id "us-east-1_ABC123DEF" \
    --description "Data analysts and viewers"

4. Create Test Users

bash
# Create admin user
aws cognito-idp admin-create-user \
    --user-pool-id "us-east-1_ABC123DEF" \
    --username "admin@company.com" \
    --user-attributes Name=email,Value=admin@company.com \
    --temporary-password "TempPass123!" \
    --message-action SUPPRESS

# Add user to admin group
aws cognito-idp admin-add-user-to-group \
    --user-pool-id "us-east-1_ABC123DEF" \
    --username "admin@company.com" \
    --group-name "boilstream-admins"

BoilStream Configuration

Environment Variables

Configure BoilStream to use your Cognito User Pool:

bash
# Enable Cognito authentication
export AUTH_PROVIDERS="cognito"

# Cognito configuration (REQUIRED)
export COGNITO_USER_POOL_ID="us-east-1_ABC123DEF"
export COGNITO_REGION="us-east-1"

# Optional: Specify expected audience
export COGNITO_AUDIENCE="4n8j9k2l1m3n4o5p6q7r"

# Authorization groups
export ADMIN_GROUPS="boilstream-admins"
export WRITE_GROUPS="data-producers,etl-services"
export READ_ONLY_GROUPS="data-analysts,business-users"

Docker Compose Example

yaml
version: '3.8'
services:
  boilstream:
    image: boilstream:latest
    environment:
      # Cognito Authentication
      AUTH_PROVIDERS: "cognito"
      COGNITO_USER_POOL_ID: "us-east-1_ABC123DEF"
      COGNITO_REGION: "us-east-1"
      COGNITO_AUDIENCE: "4n8j9k2l1m3n4o5p6q7r"
      
      # Authorization
      ADMIN_GROUPS: "boilstream-admins"
      WRITE_GROUPS: "data-producers"
      READ_ONLY_GROUPS: "data-analysts"
      
      # Other BoilStream config...
      S3_BUCKET: "my-data-lake"
      AWS_REGION: "us-east-1"

JWT Token Claims

BoilStream extracts the following claims from Cognito JWT tokens:

Standard Claims

  • sub - User ID (subject)
  • iss - Issuer (Cognito User Pool)
  • aud - Audience (Client ID)
  • exp - Expiration timestamp
  • iat - Issued at timestamp
  • token_use - Token type ("access" or "id")

Cognito-Specific Claims

  • cognito:groups - Array of group names
  • scope - Space-separated OAuth scopes
  • username - Cognito username
  • email - User email address

Example JWT Claims

json
{
  "sub": "12345678-1234-1234-1234-123456789abc",
  "iss": "https://cognito-idp.us-east-1.amazonaws.com/us-east-1_ABC123DEF",
  "aud": "4n8j9k2l1m3n4o5p6q7r",
  "token_use": "access",
  "scope": "aws.cognito.signin.user.admin",
  "username": "admin@company.com",
  "exp": 1735689600,
  "iat": 1735686000,
  "cognito:groups": [
    "boilstream-admins",
    "data-engineers"
  ]
}

Authorization Mapping

BoilStream maps Cognito claims to authorization context:

Groups Mapping

bash
# Cognito groups -> BoilStream authorization
cognito:groups: ["boilstream-admins"] -> Admin privileges
cognito:groups: ["data-producers"]    -> Write access  
cognito:groups: ["data-analysts"]     -> Read access

Scopes Mapping

bash
# OAuth scopes -> API permissions
scope: "boilstream:admin" -> Admin operations
scope: "boilstream:write" -> Write operations
scope: "boilstream:read"  -> Read operations

Client Integration

Getting JWT Tokens

Use AWS Cognito SDK to obtain JWT tokens:

python
import boto3

# Create Cognito client
cognito = boto3.client('cognito-idp', region_name='us-east-1')

# Authenticate user
response = cognito.admin_initiate_auth(
    UserPoolId='us-east-1_ABC123DEF',
    ClientId='4n8j9k2l1m3n4o5p6q7r',
    AuthFlow='ADMIN_NO_SRP_AUTH',
    AuthParameters={
        'USERNAME': 'admin@company.com',
        'PASSWORD': 'YourPassword123!'
    }
)

# Extract access token
access_token = response['AuthenticationResult']['AccessToken']
print(f"Bearer {access_token}")
javascript
const AWS = require('aws-sdk');

const cognito = new AWS.CognitoIdentityServiceProvider({
    region: 'us-east-1'
});

async function getToken() {
    const params = {
        AuthFlow: 'ADMIN_NO_SRP_AUTH',
        UserPoolId: 'us-east-1_ABC123DEF',
        ClientId: '4n8j9k2l1m3n4o5p6q7r',
        AuthParameters: {
            USERNAME: 'admin@company.com',
            PASSWORD: 'YourPassword123!'
        }
    };
    
    const result = await cognito.adminInitiateAuth(params).promise();
    const accessToken = result.AuthenticationResult.AccessToken;
    console.log(`Bearer ${accessToken}`);
}
bash
# Get token using AWS CLI
aws cognito-idp admin-initiate-auth \
    --user-pool-id "us-east-1_ABC123DEF" \
    --client-id "4n8j9k2l1m3n4o5p6q7r" \
    --auth-flow "ADMIN_NO_SRP_AUTH" \
    --auth-parameters USERNAME=admin@company.com,PASSWORD=YourPassword123! \
    --query 'AuthenticationResult.AccessToken' \
    --output text

DuckDB Integration

sql
-- Install and load the airport extension
INSTALL airport FROM community;
LOAD airport;

-- Create authentication secret with your Cognito JWT token
CREATE SECRET boilstream_cognito (
    type airport,
    auth_token 'eyJraWQiOiJ6YWZsU0RYQnorRWFyQUgyc1Nwa2pBZE5ja0JoZjVwQUtPTnNjZzlpSW04PSIsImFsZyI6IlJTMjU2In0...',
    scope 'grpc+tls://localhost:50051/'
);

-- Connect to BoilStream with TLS and authentication
ATTACH 'boilstream' (TYPE AIRPORT, location 'grpc+tls://localhost:50051/');

-- Start streaming data (requires appropriate permissions)
CREATE TABLE boilstream.s3.events (id INT, data VARCHAR);
INSERT INTO boilstream.s3.events VALUES (1, 'authenticated data');

Get Cognito Token for DuckDB

bash
# Get token using our setup script
./scripts/cognito_test_setup.sh

# Or manually with AWS CLI
aws cognito-idp admin-initiate-auth \
    --user-pool-id "eu-west-1_gti5vAfvC" \
    --client-id "7ml47mngu8lrcb198epbkkfi5s" \
    --auth-flow "ADMIN_NO_SRP_AUTH" \
    --auth-parameters USERNAME=testuser,PASSWORD=TempPass123! \
    --query 'AuthenticationResult.AccessToken' \
    --output text

Security Considerations

✅ Best Practices

  • Use ID Tokens: Use ID tokens for user identity, access tokens for API access
  • Short Token Lifetime: Keep access tokens short-lived (1 hour or less)
  • Secure Token Storage: Store tokens securely, never in plain text
  • Group-based Authorization: Use Cognito groups rather than individual user permissions

⚠️ Security Warnings

  • Client Secrets: Protect client secrets in server-side applications only
  • Token Transmission: Always use HTTPS/TLS for token transmission
  • Token Validation: BoilStream validates signatures, expiration, and issuer automatically

Network Security

bash
# Ensure BoilStream can reach Cognito JWKS endpoint
curl -v "https://cognito-idp.us-east-1.amazonaws.com/us-east-1_ABC123DEF/.well-known/jwks.json"

# Expected response: JSON with RSA public keys
{
  "keys": [
    {
      "alg": "RS256",
      "e": "AQAB",
      "kid": "abc123...",
      "kty": "RSA",
      "n": "xyz789...",
      "use": "sig"
    }
  ]
}

Troubleshooting

Common Issues

"Authentication failed" errors:

bash
# Check user pool ID and region
aws cognito-idp describe-user-pool --user-pool-id "us-east-1_ABC123DEF"

# Verify JWKS endpoint accessibility
curl "https://cognito-idp.us-east-1.amazonaws.com/us-east-1_ABC123DEF/.well-known/jwks.json"

"Authorization denied" errors:

bash
# Check user group membership
aws cognito-idp admin-list-groups-for-user \
    --user-pool-id "us-east-1_ABC123DEF" \
    --username "admin@company.com"

# Verify group configuration in BoilStream
echo $ADMIN_GROUPS
echo $WRITE_GROUPS
echo $READ_ONLY_GROUPS

Token validation failures:

bash
# Enable debug logging
export RUST_LOG="boilstream::auth=debug"

# Check token claims manually
echo "$TOKEN" | cut -d'.' -f2 | base64 -d | jq .

Debug Logging

Enable detailed authentication logging:

bash
export RUST_LOG="boilstream::auth::cognito=debug,boilstream::auth::manager=debug"

Advanced Configuration

Custom Scopes

Configure custom OAuth scopes in Cognito:

  1. Go to Cognito User Pool → App integration → Resource servers
  2. Create resource server with identifier boilstream
  3. Add custom scopes: read, write, admin
  4. Configure app client to use resource server scopes
bash
# Use scope-based authorization
export REQUIRED_READ_SCOPES="boilstream:read"
export REQUIRED_WRITE_SCOPES="boilstream:write"  
export REQUIRED_ADMIN_SCOPES="boilstream:admin"

Multi-Region Setup

For multi-region deployments, ensure all regions can access JWKS:

bash
# Configure region-specific endpoints
export COGNITO_REGION="us-east-1"
# BoilStream automatically constructs JWKS URL:
# https://cognito-idp.${region}.amazonaws.com/${user_pool_id}/.well-known/jwks.json

Next Steps