diff --git a/.github/commit-msg b/.github/commit-msg index 6437e582..25d5e7b1 100755 --- a/.github/commit-msg +++ b/.github/commit-msg @@ -2,4 +2,4 @@ . "$(dirname "$0")/_/husky.sh" . "$(dirname "$0")/required-apps" -cd web && ${PMGR} commit +cd web && ${PMGR} commitlint --edit "$1" diff --git a/docs/security/measures.md b/docs/security/measures.md index 2555f865..ba4bcc86 100644 --- a/docs/security/measures.md +++ b/docs/security/measures.md @@ -252,7 +252,7 @@ typically located at `/etc/fail2ban/filter.d`. [Definition] failregex = ^.*Unsuccessful 1FA authentication attempt by user .*remote_ip="?"? stack.* - ^.*Unsuccessful (TOTP|DUO|U2F) authentication attempt by user .*remote_ip="?"? stack.* + ^.*Unsuccessful (TOTP|Duo|U2F) authentication attempt by user .*remote_ip="?"? stack.* ignoreregex = ^.*level=debug.* ^.*level=info.* diff --git a/internal/authentication/ldap_user_provider.go b/internal/authentication/ldap_user_provider.go index 01ebe967..d6124476 100644 --- a/internal/authentication/ldap_user_provider.go +++ b/internal/authentication/ldap_user_provider.go @@ -117,7 +117,7 @@ func (p *LDAPUserProvider) CheckUserPassword(inputUsername string, password stri userConn, err := p.connect(profile.DN, password) if err != nil { - return false, fmt.Errorf("Authentication of user %s failed. Cause: %s", inputUsername, err) + return false, fmt.Errorf("authentication failed. Cause: %w", err) } defer userConn.Close() diff --git a/internal/authentication/ldap_user_provider_test.go b/internal/authentication/ldap_user_provider_test.go index 202cd636..946d8507 100644 --- a/internal/authentication/ldap_user_provider_test.go +++ b/internal/authentication/ldap_user_provider_test.go @@ -1098,14 +1098,14 @@ func TestShouldCheckInvalidUserPassword(t *testing.T) { Return(mockConn, nil), mockConn.EXPECT(). Bind(gomock.Eq("uid=test,dc=example,dc=com"), gomock.Eq("password")). - Return(errors.New("Invalid username or password")), + Return(errors.New("invalid username or password")), mockConn.EXPECT().Close(), ) valid, err := ldapClient.CheckUserPassword("john", "password") assert.False(t, valid) - require.EqualError(t, err, "Authentication of user john failed. Cause: Invalid username or password") + require.EqualError(t, err, "authentication failed. Cause: invalid username or password") } func TestShouldCallStartTLSWhenEnabled(t *testing.T) { diff --git a/internal/handlers/handler_sign_duo.go b/internal/handlers/handler_sign_duo.go index de6d93d2..b710f98c 100644 --- a/internal/handlers/handler_sign_duo.go +++ b/internal/handlers/handler_sign_duo.go @@ -21,7 +21,7 @@ func SecondFactorDuoPost(duoAPI duo.API) middlewares.RequestHandler { ) if err := ctx.ParseBody(&requestBody); err != nil { - ctx.Logger.Errorf(logFmtErrParseRequestBody, regulation.AuthTypeDUO, err) + ctx.Logger.Errorf(logFmtErrParseRequestBody, regulation.AuthTypeDuo, err) respondUnauthorized(ctx, messageMFAValidationFailed) @@ -71,7 +71,7 @@ func SecondFactorDuoPost(duoAPI duo.API) middlewares.RequestHandler { } if authResponse.Result != allow { - _ = markAuthenticationAttempt(ctx, false, nil, userSession.Username, regulation.AuthTypeDUO, + _ = markAuthenticationAttempt(ctx, false, nil, userSession.Username, regulation.AuthTypeDuo, fmt.Errorf("duo auth result: %s, status: %s, message: %s", authResponse.Result, authResponse.Status, authResponse.StatusMessage)) @@ -80,7 +80,7 @@ func SecondFactorDuoPost(duoAPI duo.API) middlewares.RequestHandler { return } - if err = markAuthenticationAttempt(ctx, true, nil, userSession.Username, regulation.AuthTypeDUO, nil); err != nil { + if err = markAuthenticationAttempt(ctx, true, nil, userSession.Username, regulation.AuthTypeDuo, nil); err != nil { respondUnauthorized(ctx, messageMFAValidationFailed) return } @@ -248,7 +248,7 @@ func HandleAllow(ctx *middlewares.AutheliaCtx, targetURL string) { err := ctx.Providers.SessionProvider.RegenerateSession(ctx.RequestCtx) if err != nil { - ctx.Logger.Errorf(logFmtErrSessionRegenerate, regulation.AuthTypeDUO, userSession.Username, err) + ctx.Logger.Errorf(logFmtErrSessionRegenerate, regulation.AuthTypeDuo, userSession.Username, err) respondUnauthorized(ctx, messageMFAValidationFailed) diff --git a/internal/handlers/handler_sign_duo_test.go b/internal/handlers/handler_sign_duo_test.go index 3ab9d599..71bfdd62 100644 --- a/internal/handlers/handler_sign_duo_test.go +++ b/internal/handlers/handler_sign_duo_test.go @@ -96,7 +96,7 @@ func (s *SecondFactorDuoPostSuite) TestShouldAutoSelect() { Successful: true, Banned: false, Time: s.mock.Clock.Now(), - Type: regulation.AuthTypeDUO, + Type: regulation.AuthTypeDuo, RemoteIP: models.NewIPAddressFromString("0.0.0.0"), })). Return(nil) @@ -285,7 +285,7 @@ func (s *SecondFactorDuoPostSuite) TestShouldUseInvalidMethodAndAutoSelect() { Successful: true, Banned: false, Time: s.mock.Clock.Now(), - Type: regulation.AuthTypeDUO, + Type: regulation.AuthTypeDuo, RemoteIP: models.NewIPAddressFromString("0.0.0.0"), })). Return(nil) @@ -413,7 +413,7 @@ func (s *SecondFactorDuoPostSuite) TestShouldCallDuoAPIAndDenyAccess() { Successful: false, Banned: false, Time: s.mock.Clock.Now(), - Type: regulation.AuthTypeDUO, + Type: regulation.AuthTypeDuo, RemoteIP: models.NewIPAddressFromString("0.0.0.0"), })). Return(nil) @@ -496,7 +496,7 @@ func (s *SecondFactorDuoPostSuite) TestShouldRedirectUserToDefaultURL() { Successful: true, Banned: false, Time: s.mock.Clock.Now(), - Type: regulation.AuthTypeDUO, + Type: regulation.AuthTypeDuo, RemoteIP: models.NewIPAddressFromString("0.0.0.0"), })). Return(nil) @@ -545,7 +545,7 @@ func (s *SecondFactorDuoPostSuite) TestShouldNotReturnRedirectURL() { Successful: true, Banned: false, Time: s.mock.Clock.Now(), - Type: regulation.AuthTypeDUO, + Type: regulation.AuthTypeDuo, RemoteIP: models.NewIPAddressFromString("0.0.0.0"), })). Return(nil) @@ -590,7 +590,7 @@ func (s *SecondFactorDuoPostSuite) TestShouldRedirectUserToSafeTargetURL() { Successful: true, Banned: false, Time: s.mock.Clock.Now(), - Type: regulation.AuthTypeDUO, + Type: regulation.AuthTypeDuo, RemoteIP: models.NewIPAddressFromString("0.0.0.0"), })). Return(nil) @@ -639,7 +639,7 @@ func (s *SecondFactorDuoPostSuite) TestShouldNotRedirectToUnsafeURL() { Successful: true, Banned: false, Time: s.mock.Clock.Now(), - Type: regulation.AuthTypeDUO, + Type: regulation.AuthTypeDuo, RemoteIP: models.NewIPAddressFromString("0.0.0.0"), })). Return(nil) @@ -686,7 +686,7 @@ func (s *SecondFactorDuoPostSuite) TestShouldRegenerateSessionForPreventingSessi Successful: true, Banned: false, Time: s.mock.Clock.Now(), - Type: regulation.AuthTypeDUO, + Type: regulation.AuthTypeDuo, RemoteIP: models.NewIPAddressFromString("0.0.0.0"), })). Return(nil) diff --git a/internal/handlers/handler_sign_u2f_step1.go b/internal/handlers/handler_sign_u2f_step1.go index dec99901..848a7680 100644 --- a/internal/handlers/handler_sign_u2f_step1.go +++ b/internal/handlers/handler_sign_u2f_step1.go @@ -33,7 +33,7 @@ func SecondFactorU2FSignGet(ctx *middlewares.AutheliaCtx) { challenge, err := u2f.NewChallenge(appID, trustedFacets) if err != nil { - ctx.Logger.Errorf("Unable to create %s challenge for user '%s': %+v", regulation.AuthTypeFIDO, userSession.Username, err) + ctx.Logger.Errorf("Unable to create %s challenge for user '%s': %+v", regulation.AuthTypeU2F, userSession.Username, err) respondUnauthorized(ctx, messageMFAValidationFailed) @@ -45,11 +45,11 @@ func SecondFactorU2FSignGet(ctx *middlewares.AutheliaCtx) { respondUnauthorized(ctx, messageMFAValidationFailed) if err == storage.ErrNoU2FDeviceHandle { - _ = markAuthenticationAttempt(ctx, false, nil, userSession.Username, regulation.AuthTypeFIDO, fmt.Errorf("no registered U2F device")) + _ = markAuthenticationAttempt(ctx, false, nil, userSession.Username, regulation.AuthTypeU2F, fmt.Errorf("no registered U2F device")) return } - ctx.Logger.Errorf("Could not load %s devices for user '%s': %+v", regulation.AuthTypeFIDO, userSession.Username, err) + ctx.Logger.Errorf("Could not load %s devices for user '%s': %+v", regulation.AuthTypeU2F, userSession.Username, err) return } @@ -74,7 +74,7 @@ func SecondFactorU2FSignGet(ctx *middlewares.AutheliaCtx) { userSession.U2FChallenge = challenge if err = ctx.SaveSession(userSession); err != nil { - ctx.Logger.Errorf(logFmtErrSessionSave, "challenge and registration", regulation.AuthTypeFIDO, userSession.Username, err) + ctx.Logger.Errorf(logFmtErrSessionSave, "challenge and registration", regulation.AuthTypeU2F, userSession.Username, err) respondUnauthorized(ctx, messageMFAValidationFailed) @@ -84,7 +84,7 @@ func SecondFactorU2FSignGet(ctx *middlewares.AutheliaCtx) { signRequest := challenge.SignRequest([]u2f.Registration{registration}) if err = ctx.SetJSONBody(signRequest); err != nil { - ctx.Logger.Errorf(logFmtErrWriteResponseBody, regulation.AuthTypeFIDO, userSession.Username, err) + ctx.Logger.Errorf(logFmtErrWriteResponseBody, regulation.AuthTypeU2F, userSession.Username, err) respondUnauthorized(ctx, messageMFAValidationFailed) diff --git a/internal/handlers/handler_sign_u2f_step2.go b/internal/handlers/handler_sign_u2f_step2.go index c0e28f95..c6705258 100644 --- a/internal/handlers/handler_sign_u2f_step2.go +++ b/internal/handlers/handler_sign_u2f_step2.go @@ -16,7 +16,7 @@ func SecondFactorU2FSignPost(u2fVerifier U2FVerifier) middlewares.RequestHandler ) if err := ctx.ParseBody(&requestBody); err != nil { - ctx.Logger.Errorf(logFmtErrParseRequestBody, regulation.AuthTypeFIDO, err) + ctx.Logger.Errorf(logFmtErrParseRequestBody, regulation.AuthTypeU2F, err) respondUnauthorized(ctx, messageMFAValidationFailed) @@ -25,7 +25,7 @@ func SecondFactorU2FSignPost(u2fVerifier U2FVerifier) middlewares.RequestHandler userSession := ctx.GetSession() if userSession.U2FChallenge == nil { - _ = markAuthenticationAttempt(ctx, false, nil, userSession.Username, regulation.AuthTypeFIDO, errors.New("session did not contain a challenge")) + _ = markAuthenticationAttempt(ctx, false, nil, userSession.Username, regulation.AuthTypeU2F, errors.New("session did not contain a challenge")) respondUnauthorized(ctx, messageMFAValidationFailed) @@ -33,7 +33,7 @@ func SecondFactorU2FSignPost(u2fVerifier U2FVerifier) middlewares.RequestHandler } if userSession.U2FRegistration == nil { - _ = markAuthenticationAttempt(ctx, false, nil, userSession.Username, regulation.AuthTypeFIDO, errors.New("session did not contain a registration")) + _ = markAuthenticationAttempt(ctx, false, nil, userSession.Username, regulation.AuthTypeU2F, errors.New("session did not contain a registration")) respondUnauthorized(ctx, messageMFAValidationFailed) @@ -42,7 +42,7 @@ func SecondFactorU2FSignPost(u2fVerifier U2FVerifier) middlewares.RequestHandler if err = u2fVerifier.Verify(userSession.U2FRegistration.KeyHandle, userSession.U2FRegistration.PublicKey, requestBody.SignResponse, *userSession.U2FChallenge); err != nil { - _ = markAuthenticationAttempt(ctx, false, nil, userSession.Username, regulation.AuthTypeFIDO, err) + _ = markAuthenticationAttempt(ctx, false, nil, userSession.Username, regulation.AuthTypeU2F, err) respondUnauthorized(ctx, messageMFAValidationFailed) @@ -50,14 +50,14 @@ func SecondFactorU2FSignPost(u2fVerifier U2FVerifier) middlewares.RequestHandler } if err = ctx.Providers.SessionProvider.RegenerateSession(ctx.RequestCtx); err != nil { - ctx.Logger.Errorf(logFmtErrSessionRegenerate, regulation.AuthTypeFIDO, userSession.Username, err) + ctx.Logger.Errorf(logFmtErrSessionRegenerate, regulation.AuthTypeU2F, userSession.Username, err) respondUnauthorized(ctx, messageMFAValidationFailed) return } - if err = markAuthenticationAttempt(ctx, true, nil, userSession.Username, regulation.AuthTypeFIDO, nil); err != nil { + if err = markAuthenticationAttempt(ctx, true, nil, userSession.Username, regulation.AuthTypeU2F, nil); err != nil { respondUnauthorized(ctx, messageMFAValidationFailed) return } @@ -66,7 +66,7 @@ func SecondFactorU2FSignPost(u2fVerifier U2FVerifier) middlewares.RequestHandler err = ctx.SaveSession(userSession) if err != nil { - ctx.Logger.Errorf(logFmtErrSessionSave, "authentication time", regulation.AuthTypeFIDO, userSession.Username, err) + ctx.Logger.Errorf(logFmtErrSessionSave, "authentication time", regulation.AuthTypeU2F, userSession.Username, err) respondUnauthorized(ctx, messageMFAValidationFailed) diff --git a/internal/handlers/handler_sign_u2f_step2_test.go b/internal/handlers/handler_sign_u2f_step2_test.go index 8cb3c289..7fb0ec18 100644 --- a/internal/handlers/handler_sign_u2f_step2_test.go +++ b/internal/handlers/handler_sign_u2f_step2_test.go @@ -50,7 +50,7 @@ func (s *HandlerSignU2FStep2Suite) TestShouldRedirectUserToDefaultURL() { Successful: true, Banned: false, Time: s.mock.Clock.Now(), - Type: regulation.AuthTypeFIDO, + Type: regulation.AuthTypeU2F, RemoteIP: models.NewIPAddressFromString("0.0.0.0"), })) @@ -82,7 +82,7 @@ func (s *HandlerSignU2FStep2Suite) TestShouldNotReturnRedirectURL() { Successful: true, Banned: false, Time: s.mock.Clock.Now(), - Type: regulation.AuthTypeFIDO, + Type: regulation.AuthTypeU2F, RemoteIP: models.NewIPAddressFromString("0.0.0.0"), })) @@ -110,7 +110,7 @@ func (s *HandlerSignU2FStep2Suite) TestShouldRedirectUserToSafeTargetURL() { Successful: true, Banned: false, Time: s.mock.Clock.Now(), - Type: regulation.AuthTypeFIDO, + Type: regulation.AuthTypeU2F, RemoteIP: models.NewIPAddressFromString("0.0.0.0"), })) @@ -141,7 +141,7 @@ func (s *HandlerSignU2FStep2Suite) TestShouldNotRedirectToUnsafeURL() { Successful: true, Banned: false, Time: s.mock.Clock.Now(), - Type: regulation.AuthTypeFIDO, + Type: regulation.AuthTypeU2F, RemoteIP: models.NewIPAddressFromString("0.0.0.0"), })) @@ -170,7 +170,7 @@ func (s *HandlerSignU2FStep2Suite) TestShouldRegenerateSessionForPreventingSessi Successful: true, Banned: false, Time: s.mock.Clock.Now(), - Type: regulation.AuthTypeFIDO, + Type: regulation.AuthTypeU2F, RemoteIP: models.NewIPAddressFromString("0.0.0.0"), })) diff --git a/internal/handlers/handler_user_totp.go b/internal/handlers/handler_user_totp.go index 2f7344bc..fbf13375 100644 --- a/internal/handlers/handler_user_totp.go +++ b/internal/handlers/handler_user_totp.go @@ -17,10 +17,12 @@ func UserTOTPGet(ctx *middlewares.AutheliaCtx) { if err != nil { if errors.Is(err, storage.ErrNoTOTPConfiguration) { ctx.SetStatusCode(fasthttp.StatusNotFound) - ctx.Error(err, "No TOTP Configuration.") + ctx.SetJSONError("Could not find TOTP Configuration for user.") + ctx.Logger.Errorf("Failed to lookup TOTP configuration for user '%s'", userSession.Username) } else { ctx.SetStatusCode(fasthttp.StatusInternalServerError) - ctx.Error(err, "Unknown Error.") + ctx.SetJSONError("Could not find TOTP Configuration for user.") + ctx.Logger.Errorf("Failed to lookup TOTP configuration for user '%s' with unknown error: %v", userSession.Username, err) } return diff --git a/internal/handlers/handler_verify.go b/internal/handlers/handler_verify.go index ba3f71f6..1767aea0 100644 --- a/internal/handlers/handler_verify.go +++ b/internal/handlers/handler_verify.go @@ -95,7 +95,7 @@ func verifyBasicAuth(ctx *middlewares.AutheliaCtx, header, auth []byte) (usernam authenticated, err := ctx.Providers.UserProvider.CheckUserPassword(username, password) if err != nil { - return "", "", nil, nil, authentication.NotAuthenticated, fmt.Errorf("unable to check credentials extracted from %s header: %s", header, err) + return "", "", nil, nil, authentication.NotAuthenticated, fmt.Errorf("unable to check credentials extracted from %s header: %w", header, err) } // If the user is not correctly authenticated, send a 401. diff --git a/internal/regulation/const.go b/internal/regulation/const.go index f5c2e604..84b00a8a 100644 --- a/internal/regulation/const.go +++ b/internal/regulation/const.go @@ -12,12 +12,12 @@ const ( // AuthTypeTOTP is the string representing an auth log for second-factor authentication via TOTP. AuthTypeTOTP = "TOTP" - // AuthTypeFIDO is the string representing an auth log for second-factor authentication via FIDO/CTAP1/U2F. - AuthTypeFIDO = "FIDO" + // AuthTypeU2F is the string representing an auth log for second-factor authentication via FIDO/CTAP1/U2F. + AuthTypeU2F = "U2F" - // AuthTypeFIDO2 is the string representing an auth log for second-factor authentication via FIDO2/CTAP2/Webauthn. - // TODO: Add FIDO2. + // AuthTypeWebAuthn is the string representing an auth log for second-factor authentication via FIDO2/CTAP2/WebAuthn. + // TODO: Add WebAuthn. - // AuthTypeDUO is the string representing an auth log for second-factor authentication via DUO. - AuthTypeDUO = "DUO" + // AuthTypeDuo is the string representing an auth log for second-factor authentication via DUO. + AuthTypeDuo = "Duo" ) diff --git a/internal/storage/migrations/V0001.Initial_Schema.mysql.up.sql b/internal/storage/migrations/V0001.Initial_Schema.mysql.up.sql index 44ab514b..1e6dda17 100644 --- a/internal/storage/migrations/V0001.Initial_Schema.mysql.up.sql +++ b/internal/storage/migrations/V0001.Initial_Schema.mysql.up.sql @@ -4,7 +4,7 @@ CREATE TABLE IF NOT EXISTS authentication_logs ( successful BOOLEAN NOT NULL, banned BOOLEAN NOT NULL DEFAULT FALSE, username VARCHAR(100) NOT NULL, - auth_type VARCHAR(5) NOT NULL DEFAULT '1FA', + auth_type VARCHAR(8) NOT NULL DEFAULT '1FA', remote_ip VARCHAR(47) NULL DEFAULT NULL, request_uri TEXT NOT NULL, request_method VARCHAR(8) NOT NULL DEFAULT '', diff --git a/internal/storage/migrations/V0001.Initial_Schema.postgres.up.sql b/internal/storage/migrations/V0001.Initial_Schema.postgres.up.sql index 800330b0..30beeaa3 100644 --- a/internal/storage/migrations/V0001.Initial_Schema.postgres.up.sql +++ b/internal/storage/migrations/V0001.Initial_Schema.postgres.up.sql @@ -4,7 +4,7 @@ CREATE TABLE IF NOT EXISTS authentication_logs ( successful BOOLEAN NOT NULL, banned BOOLEAN NOT NULL DEFAULT FALSE, username VARCHAR(100) NOT NULL, - auth_type VARCHAR(5) NOT NULL DEFAULT '1FA', + auth_type VARCHAR(8) NOT NULL DEFAULT '1FA', remote_ip VARCHAR(47) NULL DEFAULT NULL, request_uri TEXT, request_method VARCHAR(8) NOT NULL DEFAULT '', diff --git a/internal/storage/migrations/V0001.Initial_Schema.sqlite.up.sql b/internal/storage/migrations/V0001.Initial_Schema.sqlite.up.sql index f5876e25..e2aa1b3e 100644 --- a/internal/storage/migrations/V0001.Initial_Schema.sqlite.up.sql +++ b/internal/storage/migrations/V0001.Initial_Schema.sqlite.up.sql @@ -4,7 +4,7 @@ CREATE TABLE IF NOT EXISTS authentication_logs ( successful BOOLEAN NOT NULL, banned BOOLEAN NOT NULL DEFAULT FALSE, username VARCHAR(100) NOT NULL, - auth_type VARCHAR(5) NOT NULL DEFAULT '1FA', + auth_type VARCHAR(8) NOT NULL DEFAULT '1FA', remote_ip VARCHAR(47) NULL DEFAULT NULL, request_uri TEXT, request_method VARCHAR(8) NOT NULL DEFAULT '', diff --git a/internal/suites/suite_cli_test.go b/internal/suites/suite_cli_test.go index c64a56e0..7ba37728 100644 --- a/internal/suites/suite_cli_test.go +++ b/internal/suites/suite_cli_test.go @@ -270,8 +270,6 @@ func (s *CLISuite) TestStorage02ShouldShowSchemaInfo() { func (s *CLISuite) TestStorage03ShouldExportTOTP() { storageProvider := storage.NewSQLiteProvider(&storageLocalTmpConfig) - s.Require().NoError(storageProvider.StartupCheck()) - ctx := context.Background() var ( diff --git a/internal/suites/suite_standalone_test.go b/internal/suites/suite_standalone_test.go index b16e76b3..c1672ead 100644 --- a/internal/suites/suite_standalone_test.go +++ b/internal/suites/suite_standalone_test.go @@ -123,7 +123,6 @@ func (s *StandaloneWebDriverSuite) TestShouldCheckUserIsAskedToRegisterDevice() // Clean up any TOTP secret already in DB. provider := storage.NewSQLiteProvider(&storageLocalTmpConfig) - require.NoError(s.T(), provider.StartupCheck()) require.NoError(s.T(), provider.DeleteTOTPConfiguration(ctx, username)) // Login one factor. diff --git a/web/package.json b/web/package.json index 3e374f82..a32add4e 100644 --- a/web/package.json +++ b/web/package.json @@ -29,8 +29,7 @@ "coverage": "VITE_COVERAGE=true vite build", "lint": "eslint . --ext .js,.jsx,.ts,.tsx --fix", "test": "jest --coverage --no-cache", - "report": "nyc report -r clover -r json -r lcov -r text", - "commit": "commitlint --edit $1" + "report": "nyc report -r clover -r json -r lcov -r text" }, "eslintConfig": { "extends": "react-app" diff --git a/web/src/views/LoginPortal/SecondFactor/OneTimePasswordMethod.tsx b/web/src/views/LoginPortal/SecondFactor/OneTimePasswordMethod.tsx index f49b213e..c0920c2a 100644 --- a/web/src/views/LoginPortal/SecondFactor/OneTimePasswordMethod.tsx +++ b/web/src/views/LoginPortal/SecondFactor/OneTimePasswordMethod.tsx @@ -47,8 +47,10 @@ const OneTimePasswordMethod = function (props: Props) { }, [onSignInErrorCallback, err]); useEffect(() => { - fetch(); - }, [fetch]); + if (props.registered && props.authenticationLevel === AuthenticationLevel.OneFactor) { + fetch(); + } + }, [fetch, props.authenticationLevel, props.registered]); const signInFunc = useCallback(async () => { if (!props.registered || props.authenticationLevel === AuthenticationLevel.TwoFactor) {