simonmcallister0210 / cognito-srp-helper

A helper for SRP authentication in AWS Cognito
Apache License 2.0
9 stars 0 forks source link

fix: add `isHashed` flag to createSrpSession to allow users to defer password hashing to signSrpSession #29

Closed simonmcallister0210 closed 3 months ago

simonmcallister0210 commented 3 months ago

Context

Email and Phone logins don't work because hashing requires the user ID. See this issue for details. To fix this we can allow users to defer hashing until the signing operation. At this point we'll have access to user ID, which will allow users to login with their Email and Phone number

Changes

Testing

With password hashing - users can only authenticate with Username (aka. user ID)

const {
  createSrpSession,
  signSrpSession,
  wrapAuthChallenge,
  wrapInitiateAuth,
  createPasswordHash,
} = require("../cognito-srp-helper");
const {
  CognitoIdentityProviderClient,
  InitiateAuthCommand,
  RespondToAuthChallengeCommand,
} = require("@aws-sdk/client-cognito-identity-provider");

(async () => {
  const username = "a2c2e290-6d0f-4a08-a5ca-f0162935f3a6"; // this works
  // const username = "yorej57765@comsb.com"; // this won't work

  const password = "Qwerty1!";
  const poolId = "eu-west-2_eYpv1mFHB";
  const clientId = "18u8119jgbpr464n28s1itk2mq";
  const cognitoIdentityProviderClient = new CognitoIdentityProviderClient({
    region: "eu-west-2",
  });

  const passwordHash = createPasswordHash(username, password, poolId);
  const srpSession = createSrpSession(username, passwordHash, poolId);

  const initiateAuthRes = await cognitoIdentityProviderClient
    .send(
      new InitiateAuthCommand(
        wrapInitiateAuth(srpSession, {
          ClientId: clientId,
          AuthFlow: "USER_SRP_AUTH",
          AuthParameters: {
            CHALLENGE_NAME: "SRP_A",
            USERNAME: username,
          },
        })
      )
    )
    .catch((err) => {
      console.error(err);
      throw err;
    });

  console.log("initiateAuthRes:");
  console.log(initiateAuthRes);

  const signedSrpSession = signSrpSession(srpSession, initiateAuthRes);

  console.log("signedSrpSession:");
  console.log(signedSrpSession);

  const respondToAuthChallengeRes = await cognitoIdentityProviderClient
    .send(
      new RespondToAuthChallengeCommand(
        wrapAuthChallenge(signedSrpSession, {
          ClientId: clientId,
          ChallengeName: "PASSWORD_VERIFIER",
          ChallengeResponses: {
            USERNAME: username,
          },
        })
      )
    )
    .catch((err) => {
      console.error(err);
      throw err;
    });

  console.log("respondToAuthChallengeRes:");
  console.log(respondToAuthChallengeRes);
})();

Without password hashing - users can authenticate with Username (aka. user ID), and email

const {
  createSrpSession,
  signSrpSession,
  wrapAuthChallenge,
  wrapInitiateAuth,
} = require("../cognito-srp-helper");
const {
  CognitoIdentityProviderClient,
  InitiateAuthCommand,
  RespondToAuthChallengeCommand,
} = require("@aws-sdk/client-cognito-identity-provider");

(async () => {
  // const username = "a2c2e290-6d0f-4a08-a5ca-f0162935f3a6"; // this works
  const username = "yorej57765@comsb.com"; // and this works

  const password = "Qwerty1!";
  const poolId = "eu-west-2_eYpv1mFHB";
  const clientId = "18u8119jgbpr464n28s1itk2mq";
  const cognitoIdentityProviderClient = new CognitoIdentityProviderClient({
    region: "eu-west-2",
  });

  const srpSession = createSrpSession(username, password, poolId, false);

  const initiateAuthRes = await cognitoIdentityProviderClient
    .send(
      new InitiateAuthCommand(
        wrapInitiateAuth(srpSession, {
          ClientId: clientId,
          AuthFlow: "USER_SRP_AUTH",
          AuthParameters: {
            CHALLENGE_NAME: "SRP_A",
            USERNAME: username,
          },
        })
      )
    )
    .catch((err) => {
      console.error(err);
      throw err;
    });

  console.log("initiateAuthRes:");
  console.log(initiateAuthRes);

  const signedSrpSession = signSrpSession(srpSession, initiateAuthRes);

  console.log("signedSrpSession:");
  console.log(signedSrpSession);

  const respondToAuthChallengeRes = await cognitoIdentityProviderClient
    .send(
      new RespondToAuthChallengeCommand(
        wrapAuthChallenge(signedSrpSession, {
          ClientId: clientId,
          ChallengeName: "PASSWORD_VERIFIER",
          ChallengeResponses: {
            USERNAME: username,
          },
        })
      )
    )
    .catch((err) => {
      console.error(err);
      throw err;
    });

  console.log("respondToAuthChallengeRes:");
  console.log(respondToAuthChallengeRes);
})();