Testing AWS-Protected APIs: How We Built Our Own Superagent Plugin
At Certible, security isn’t optional. Our APIs are protected by AWS IAM roles and require AWS Signature Version 4 authentication for every request. This keeps our production data safe, but it created an interesting challenge: how do you run comprehensive end-to-end tests against authenticated AWS endpoints?
The answer led us to create and open-source @certible/superagent-aws-sign ⤴ – a Superagent plugin that seamlessly handles AWS request signing in our test suite.
The Challenge: Testing Real AWS Resources
Like many modern applications, our architecture relies heavily on AWS services:
-
API Gateway endpoints protected by IAM
-
Lambda functions that require authenticated requests
-
S3 buckets with strict access policies
-
DynamoDB tables behind IAM roles
While mocking these services works for unit tests, our end-to-end tests needed to hit the real AWS resources to catch integration issues, permission problems, and deployment configuration errors.
The problem? Every request needed to be signed with AWS Signature Version 4 – a complex process involving cryptographic signatures, canonical request formatting, and precise timestamp handling.
Why Existing Solutions Weren’t Enough
We initially looked at existing packages, but found limitations:
-
Outdated dependencies: Many plugins hadn’t been maintained in years
-
Limited flexibility: Hard to switch between different AWS profiles or assume roles
-
Complex setup: Required extensive configuration for simple use cases
-
TypeScript gaps: Poor type definitions for our TypeScript test suite
We needed something that “just worked” with our existing Superagent-based test framework while providing the flexibility to test different AWS environments and permission scenarios.
Our Solution: Clean AWS Authentication for Tests
We built @certible/superagent-aws-sign with a focus on developer experience and testing workflows. Here’s how it integrates into our test suite:
import AwsSignRequest from '@certible/superagent-aws-sign';
import superagent from 'superagent';
describe('API Gateway Integration Tests', () => {
let signer;
beforeAll(async () => {
signer = new AwsSignRequest();
// Load credentials from local AWS profile
await signer.setCredentialsFromConfig('test-profile');
signer.setRegion('us-east-1');
});
test('should authenticate and fetch user data', async () => {
const response = await superagent
.get('https://api.example.com/users/123')
.use(signer.add())
.expect(200);
expect(response.body.user).toBeDefined();
});
test('should handle role-based permissions', async () => {
// Assume a specific role for this test
await signer.assumeRole({
RoleArn: 'arn:aws:iam::123456789:role/TestRole',
RoleSessionName: 'e2e-test-session'
});
const response = await superagent
.post('https://api.example.com/admin/users')
.send({ name: 'Test User' })
.use(signer.add())
.expect(201);
// Clean up - revert to original credentials
signer.removeRole();
});
});
Key Features That Make Testing Easier
Flexible Credential Management: Load from AWS profiles, environment variables, or set manually – perfect for different CI/CD environments.
Role Assumption: Test different permission levels by assuming roles on-the-fly, then easily revert back.
TypeScript Ready: Full type definitions included, with JSDoc comments for excellent IDE support.
Error Handling: Clear error messages when credentials are missing or roles can’t be assumed.
Superagent Integration: Drop-in plugin that works with your existing Superagent test patterns.
Why We Open-Sourced It
Authentication shouldn’t be a barrier to good testing. We’ve seen too many teams skip end-to-end tests because setting up AWS authentication was too complex.
The package is available on npm ⤴ and the source code is on GitHub ⤴ under the MIT license. We built it on top of the solid foundation of existing packages but updated it for modern JavaScript/TypeScript workflows.
Getting Started
Install the package:
npm install @certible/superagent-aws-sign
The basic setup is straightforward:
const AwsSignRequest = require('@certible/superagent-aws-sign');
const signer = new AwsSignRequest();
await signer.setCredentialsFromConfig('default');
const response = await superagent
.get('your-aws-api-endpoint')
.use(signer.add());
The Bigger Picture
Good testing requires the right tools. By removing the friction around AWS authentication, we’ve made our tests more comprehensive and our deployments more confident.
Whether you’re testing API Gateway endpoints, Lambda functions, or any AWS service that requires IAM authentication, having a simple way to sign requests can transform your testing strategy.