Hi everyone! I am a new at provider side contract ...
# pact-js
n
Hi everyone! I am a new at provider side contract testing. I faced some issues using AWSv4 to authenticate GraphQL requests but I sorted it out with some help of an issue and an extra header, so if anyone needs it --> https://github.com/pact-foundation/pact-js/issues/304#issuecomment-1860716105
thankyou 2
Copy code
import { Request, sign } from "aws4";
// ...

const getCredentials = async (
    roleArn?: string
): Promise<AwsCredentialIdentity> =>
    roleArn ? getRoleCredentials(roleArn) : fromEnv()();

export const aws4SignAuth = async (
    apiEndpoint: string,
    requestOptions: Omit<Request, "host" | "path" | "headers">,
    roleArn?: string
): Promise<express.RequestHandler> => {
    const parsedUrl = new URL(apiEndpoint);
    const credentials = await getCredentials(roleArn);

    return (req, res, next) => {
        const options: Request = {
            host: parsedUrl.host,
            path: parsedUrl.pathname + req.path,
            headers: {},
            ...requestOptions,
            ...(req.method === "POST"
                ? {
                      body: String(req.body),
                      headers: { "Content-Type": "application/json" },
                  }
                : {}),
        };
        const signed = sign(options, credentials);
        Object.assign(req.headers, signed.headers);
        next();
    };
};
y
nice one @Nicolas Alejandro Vaquero appreciate the input, solution and you sharing it with others
n
By the way, it says only POST because I use it for Appsync, but anything with a body should be having headers updated one
Copy code
const getCredentials = async (
    roleArn?: string
): Promise<AwsCredentialIdentity> =>
    roleArn ? getRoleCredentials(roleArn) : fromEnv()();

export const aws4SignAuth = async (
    apiEndpoint: string,
    requestOptions: Omit<Request, "host" | "path" | "headers">,
    roleArn?: string
): Promise<express.RequestHandler> => {
    const parsedUrl = new URL(apiEndpoint);
    const credentials = await getCredentials(roleArn);

    return (req, res, next) => {
        const body =
            req.body instanceof Object
                ? JSON.stringify(req.body)
                : String(req.body);
        const options: Request = {
            host: parsedUrl.host,
            path: parsedUrl.pathname + req.path,
            headers: {},
            ...requestOptions,
            ...(req.method === "POST"
                ? {
                      body: Buffer.from(body),
                      headers: {
                          ...req.headers,
                          host: parsedUrl.host,
                      },
                  }
                : {}),
        };
        const signed = sign(options, credentials);
        Object.assign(req.headers, signed.headers);
        next();
    };
};