0

I am implementing in my angular project an authentication with Cognito using SRP(Secure remote password), I am following the documentation of the necessary methods to implement them, as seen below in these links:

https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_InitiateAuth.html

https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_RespondToAuthChallenge.html#API_RespondToAuthChallenge_RequestSyntax

I have implemented my angular code, which inside the component: login.component.ts uses the class 'cognito.service.ts' which declares this function login()

login(email: string, password: string): Observable<AuthenticationResultType> {
        const config = {
            region: this.environment.aws.region,
            credentials: {
                accessKeyId: this.environment.aws.accessKey,
                secretAccessKey: this.environment.aws.secretKey,
            },
            clientSecret: this.environment.auth.clientSecret, // Agregar clientSecret aquí
        };
  
        const client = new CognitoIdentityProviderClient(config);

        const srpA = this.generateSrpA(
            email,
            password,
            this.environment.auth.userPoolId,
            this.environment.auth.clientId
        );

        const secretHash = this.getSecretHash(
            email,
            this.environment.auth.clientId,
            this.environment.auth.clientSecret
        );

        const input = {
            AuthFlow: 'USER_SRP_AUTH',
            AuthParameters: {
                USERNAME: email,
                SRP_A: srpA,
                SECRET_HASH: secretHash,
            },
            ClientId: this.environment.auth.clientId,
        };

        const command = new InitiateAuthCommand(input);

        return from(client.send(command)).pipe(
            switchMap((res) => {
                console.log('Resultado primera llamada: ', res);
                const { ChallengeName: challengeName, ChallengeParameters: challengeParameters } =
                    res;
                if (!challengeParameters) {
                    return throwError(
                        () => new Error(`No se encontro AuthenticationResult en la respuesta`)
                    );
                }
                const {
                    USER_ID_FOR_SRP: userIdForSrp,
                    SECRET_BLOCK: secretBlock,
                    SALT: salt,
                    SRP_B: srpB,
                } = challengeParameters;

                const hkdf = this.getHkdf(userIdForSrp, password, srpB, salt);
                console.log('hkdf:  ', hkdf);

                const signatureString = this.calculateSignature(
                    hkdf,
                    email,
                    // this.environment.auth.userPoolId.split('_')[1],
                    this.environment.auth.userPoolId,
                    secretBlock,
                    this.getFechaInFormat()
                );          

                const respondToAuthChallengeInput = {
                    ChallengeName: challengeName,
                    ChallengeResponses: {
                        USERNAME: userIdForSrp,
                        SECRET_HASH: this.getSecretHash(
                            userIdForSrp,
                            this.environment.auth.clientId,
                            this.environment.auth.clientSecret
                        ),
                        PASSWORD_CLAIM_SECRET_BLOCK: secretBlock,
                        TIMESTAMP: this.getFechaInFormat(),
                        PASSWORD_CLAIM_SIGNATURE: signatureString,
                    },
                    ClientId: this.environment.auth.clientId,
                    Session: res.Session,
                };

                console.log('Request 2:  ', respondToAuthChallengeInput);

                const respondToAuthChallengeCommand = new RespondToAuthChallengeCommand(
                    respondToAuthChallengeInput
                );

                console.log('response auth to challenge: ', respondToAuthChallengeCommand);

                return from(client.send(respondToAuthChallengeCommand)).pipe(
                    switchMap((res) => {
                        console.log('RESULTADO DE LA LLAMADA 2: ', res);
                        if (res.AuthenticationResult) {
                            return of(res.AuthenticationResult);
                        }
                        return throwError(
                            () => new Error(`No se encontró AuthenticationResult en la respuesta`)
                        );
                    })
                );
            })
        );
    }
  • For this implementation in my code I have used as explained in the following link 2 calls:

https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-authentication-flow.html

  1. A first call (which answers 200) using 'InitiateAuthCommand' where I get values such as 'USER_ID_FOR_SRP', 'SECRET_BLOCK', 'SALT', 'SRP_B'.

  2. A second call (which answers the error in the title) using 'RespondToAuthChallengeCommand' I have done different variations in the hash generation but I really don't know what I am doing wrong, I have followed all the steps and in different forums they do it in a similar way.

  • Additionally these are the functions I use for the hkdf generation (Value Used as parameter in the second function for the signature generation for the variable 'PASSWORD_CLAIM_SIGNATURE')
getHkdf(userIdForSrp: string, password: string, salt: string, srpB: string): string {
        const input = userIdForSrp + password + salt + srpB;
        // Convertir el input a un objeto WordArray de CryptoJS

        const inputWordArray = crypto.enc.Utf8.parse(input);

        // Calcular el HKDF utilizando HMAC-SHA256
        const hkdf = crypto.HmacSHA256(inputWordArray, 'Banbif-Pass-Secret');

        // Convertir el resultado a una cadena hexadecimal
        const hkdfHex = hkdf.toString(crypto.enc.Hex);

        return hkdfHex;
    }


calculateSignature(
        hkdf: string,
        userIdForSrp: string,
        userPoolId: string,
        secretBlock: string,
        dateNow: string
 ): string {
        const secretBlockWordArray = enc.Hex.parse(secretBlock);
        const dateNowWordArray = enc.Latin1.parse(dateNow);

        const signature = HmacSHA256(
            userIdForSrp +
                userPoolId +
                secretBlockWordArray.toString(enc.Hex) +
                dateNowWordArray.toString(enc.Latin1),
            enc.Hex.parse(hkdf)
        );

        return signature.toString(enc.Base64);
    }
  • I think the error is in the variable 'PASSWORD_CLAIM_SIGNATURE' so I would like to know if my method to generate the hash is also the correct one.

  • I would be very grateful for any help, because I am really stuck on how to solve it.

BRUNO
  • 13
  • 1

0 Answers0