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
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:
A first call (which answers 200) using 'InitiateAuthCommand' where I get values such as 'USER_ID_FOR_SRP', 'SECRET_BLOCK', 'SALT', 'SRP_B'.
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.