End-to-end Testing AWS APIs with Superagent Plugin

AWS api-testing superagent sigv4 nodejs opensource developer-tools end-to-end-testing typescript certible

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:

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:

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.