aws-samples / amazon-cognito-passwordless-auth

Passwordless authentication with Amazon Cognito: FIDO2 (WebAuthn, support for Passkeys), Magic Link, SMS OTP Step Up
Apache License 2.0
355 stars 62 forks source link

ERR_PACKAGE_PATH_NOT_EXPORTED #119

Closed myevit closed 10 months ago

myevit commented 10 months ago

Good day, I am trying to follow with example from https://github.com/aws-samples/amazon-cognito-passwordless-auth/blob/main/CUSTOMIZE-AUTH.md#1-create-your-own-lambda-function-using-this-library-and-call-configure but when I add the sample code to my stack.ts right before I call to construct I have an error Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: Package subpath './custom-auth' is not defined by "exports" in C:\Users\user\work\AWS-cognito\cdk\node_modules\amazon-cognito-passwordless-auth\package.json Without the sample injection code works as expected.

import * as cdk from "aws-cdk-lib";
import { Construct } from "constructs";
import { Passwordless } from "amazon-cognito-passwordless-auth/cdk";
import { magicLink } from "amazon-cognito-passwordless-auth/custom-auth";

const sesFromAddress: string =
  "Login Link <test@test.com>";

export { createAuthChallengeHandler as handler } from "amazon-cognito-passwordless-auth/custom-auth";

const defaultConfig = magicLink.configure();

magicLink.configure({
  async contentCreator({ secretLoginLink }) {
    return {
      html: {
        data: `<html><body><p>Your login link: <a href="${secretLoginLink}">sign in</a></p>This link is valid for ${Math.floor(
          defaultConfig.secondsUntilExpiry / 60
        )} minutes<p>Do not share this email with anyone.</p></body></html>`,
        charSet: "UTF-8",
      },
      text: {
        data: `Your login link: ${secretLoginLink}`,
        charSet: "UTF-8",
      },
      subject: {
        data: "Your login link",
        charSet: "UTF-8",
      },
    };
  },
});

class stackID extends cdk.Stack {
  passwordless: Passwordless;
  constructor(scope?: Construct, id?: string, props?: cdk.StackProps) {
    super(scope, id, props);
    // const spa = cloudfrontServedEmptySpaBucket(this, "ExampleSpa");

    this.passwordless = new Passwordless(this, "Passwordless", {
      allowedOrigins: [
        "http://localhost:5173",

      ],
      clientMetadataTokenKeys: ["consent_id"],
      magicLink: {
        sesFromAddress,
        secretsTableProps: {
          removalPolicy: cdk.RemovalPolicy.DESTROY,
          billingMode: cdk.aws_dynamodb.BillingMode.PAY_PER_REQUEST,
        },
      },
      userPoolProps: {
        removalPolicy: cdk.RemovalPolicy.DESTROY,
      },
      fido2: {
        authenticatorsTableProps: {
          removalPolicy: cdk.RemovalPolicy.DESTROY,
          billingMode: cdk.aws_dynamodb.BillingMode.PAY_PER_REQUEST,
        },
        relyingPartyName: "Passwordless Fido2",
        allowedRelyingPartyIds: [
          "localhost",

        ],
        attestation: "none",
        userVerification: "required",
      },
      smsOtpStepUp: {},
      userPoolClientProps: {
        idTokenValidity: cdk.Duration.minutes(5),
        accessTokenValidity: cdk.Duration.minutes(5),
        refreshTokenValidity: cdk.Duration.hours(1),

        preventUserExistenceErrors: false,
      },
      // while testing/experimenting it's heplful to see e.g. full request details in logs:
      logLevel: "DEBUG",

  }
}

const app = new cdk.App();
const stack = new stackID(app, "test");
ottokruse commented 10 months ago

Hi @myevit it doesn't work to define the lambda code and CDK code in the same file (that would be cool but right now CDK doesn't really support that).

So instead, you have to create the lambda code in a separate file (in a separate dir too probably) as you normally would for a Lambda function in CDK, and reference that in your CDK code.

alejandrog79 commented 3 months ago

Hi! Any chance to see an example of how this was solved? I'm stuck on this issue and can't implement the custom lambda. I have this code on a separate file (custom-auth.js):

// custom-auth.ts
import { magicLink } from "amazon-cognito-passwordless-auth/custom-auth";

// Export the solution's handler to be the handler of YOUR Lambda function too:
export { createAuthChallengeHandler as handler } from "amazon-cognito-passwordless-auth/custom-auth";

// Calling configure() without arguments retrieves the current configuration:
const defaultConfig = magicLink.configure();

// Swap in your own logic:
magicLink.configure({
    sesFromAddress: "no-reply@example.com",
    async contentCreator({ secretLoginLink }) {
        return {
            html: {
                data: `<html><body><p>Your secret sign-in link: <a href="${secretLoginLink}">sign in</a></p>This link is valid for ${Math.floor(
                    defaultConfig.secondsUntilExpiry / 60
                )} minutes<p></p></body></html>`,
                charSet: "UTF-8",
            },
            text: {
                data: `Your secret sign-in link: ${secretLoginLink}`,
                charSet: "UTF-8",
            },
            subject: {
                data: "Your secret sign-in link",
                charSet: "UTF-8",
            },
        };
    },
});

Then I imported this file on cdk-stack.ts:

import { handler as createAuthChallengeHandler } from "./custom-auth.js";

Where do I use createAuthChallengeHandler?

I tried to use it as the value of createAuthChallengeFn on the Passwordless constructor with no luck:

 const passwordless = new Passwordless(
this,
"Passwordless",
{
    userPool,
    allowedOrigins: [
        process.env.WS_PREVIEW_URL!,
        `https://${distribution.distributionDomainName}`, // Allow CDN
    ],
    fido2: {
        allowedRelyingPartyIds: [
            process.env.WS_PREVIEW_HOST!,
            distribution.distributionDomainName, // Allow CDN
        ],
    },
    createAuthChallengeFn: createAuthChallengeHandler,
    magicLink: {
        sesFromAddress: "no-reply@example.com",
    },
}
);

Any help is appreciated!

alejandrog79 commented 3 months ago

Also tried this configuration on the Passwordles construct:

functionProps: {
    createAuthChallenge: {
        // Override entry, to point to your custom code:
        entry: join(__dirname, "./custom-auth.ts"),
    },
},

With this, it deploys the stack, but when I'm trying to get the magic link I've got this error:

CreateAuthChallenge invocation failed due to error Socket timeout while invoking Lambda function.