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
380 stars 69 forks source link

Custom Auth Flow With Bad Answer Infinite Loop #208

Open webjunkie01 opened 1 week ago

webjunkie01 commented 1 week ago

Hi guys,

I've been fiddling around with this package and I don't know how to handle the error when a bad code is submitted since the auth flow just loops infinitely here's my pseudo example in Angular.

import { Component, OnInit, ViewEncapsulation, EventEmitter } from '@angular/core';
import { Passwordless } from "amazon-cognito-passwordless-auth";
import { authenticateWithSRP } from "amazon-cognito-passwordless-auth/srp";
export class LoginComponentComponent implements OnInit {
myPromise: Promise<string>
constructor() {
  }

ngOnInit() { 
 Passwordless.configure({
      userPoolId: environment.POOL_ID,
      clientId: environment.CLIENT_ID,
      clientSecret: environment.CLIET_SECRET, // optional
      debug: console.debug
    });
 }
 this.myPromise = new Promise( (resolve, reject) => {
      this.resolvePromise = resolve
    })
}

submitCode(event:any){
    this.resolvePromise(this.formComponent.value.code)
 }

async login() {
  authenticateWithSRP({
      username: this.formComponent.value.email,
      password: this.formComponent.value.password,
      authflow: 'CUSTOM_AUTH',
      smsMfaCode: () => new Promise(() => {}),
      customChallengeAnswer: () => this.myPromise,
    }).signedIn.then( async (tokens) => {
      console.log(tokens);
    });
}

Is there a way to catch the response and look at the challenge name to check if it's still ChallengeName to somehow abort but keep the session alive to make another retry?, what would be the best approach?

ottokruse commented 1 week ago

Hi mate. Renew this.myPromise in submitCode?:

submitCode(event:any){
    this.resolvePromise(this.formComponent.value.code);
    // renew the promise
    this.myPromise = new Promise( (resolve, reject) => {
      this.resolvePromise = resolve
    })
 }
ottokruse commented 1 week ago

Basically every time you need to provide a custom answer, the function that you pass to customChallengeAnswer is invoked: so make sure that actually returns a new promise, or it will just resolve immediately with the old (wrong) value

ottokruse commented 1 week ago

smsMfaCode works like that too

webjunkie01 commented 1 week ago

Thanks that works!

webjunkie01 commented 5 days ago

Hi Otto, I have another question. Now that I have it working all that is left is to display a message to the user that a bad code has been submitted I've been looking at the code in srp.ts trying to figure how could this work but I can't figure it out. Is this possible?.

ottokruse commented 5 days ago

So you mean after all 3 attempts have been wrong?

Cognito will throw the generic error "invalid username or password" then. The signIn promise will reject at that point. You can catch it then, and display an appropriate message as you see fit.