Skip to main content

Fluxo de Recuperação de Senha

Escopo: Recuperação e atualização de senha no app Flutter (Coezzion Vendas)
Data: 2026-07-06


1. Resumo

O fluxo de recuperação de senha permite que o usuário redefina sua senha de acesso sem estar autenticado. O processo segue quatro etapas principais:

  1. Informar o CPF
  2. Escolher o método de verificação (SMS ou E-mail)
  3. Validar o código de 6 dígitos recebido
  4. Definir a nova senha

Após a troca bem-sucedida, o app remove as credenciais biométricas salvas e redireciona o usuário à tela de login com CPF e nova senha preenchidos.

O fluxo é protegido por tokens de API (x-api-key) obtidos via Firebase Remote Config, sem necessidade de autenticação JWT do usuário.


2. Pontos de Entrada

Existem dois caminhos que levam ao mesmo fluxo de recuperação:

EntradaCondiçãoArquivo
Botão "Esqueci minha senha" na tela de loginenable_forgot_password == true (Remote Config)lib/controllers/login/login_controller.dart
Atualização obrigatória após loginauth.needChangePassword == true na resposta de autenticaçãolib/screens/login/login_manager.dart

No segundo caso, um bottom sheet informa que a senha precisa ser atualizada por novos recursos de segurança. Se o usuário confirmar, é redirecionado para a mesma tela de CPF do fluxo de recuperação.


3. Fluxo Principal

Passo a passo

EtapaTelaAção do usuárioChamada API
1ForgotPasswordScreenInforma CPF e toca CONTINUARPOST /api/auth/recover-methods/{cpf}
2UpdateUserContactByMethodsScreenEscolhe Telefone (SMS) ou E-mail
3CodeVerificationByMethodScreenAguarda código e informa 6 dígitosPOST /api/auth/verify-recover-method (envio) + POST /api/auth/verify-code-recover (validação)
4ForgotPasswordNewPasswordScreenDefine e confirma nova senhaPOST /api/auth/change-password
5LoginScreenFaz login com nova senha

4. Endpoints

Base URL dinâmica: {baseUrl} obtida via PrefsService.getEnvConfig().

4.1 Fluxo principal

#MétodoEndpointControllerRequest BodyResposta relevante
1POST/api/auth/recover-methods/{cpf}ForgotPasswordController.findRecoverMethods{} (corpo vazio)success[] com {type, maskedValue}
2POST/api/auth/verify-recover-methodCodeVerificationByMethodScreenController.sendCode{cpf, type}Confirmação de envio do código
3POST/api/auth/verify-code-recoverCodeVerificationByMethodScreenController.verifyCode{cpf, type, verificationCode}success.token para troca de senha
4POST/api/auth/change-passwordForgotPasswordNewPasswordController.finish{token, cpf, password}success.title, success.message

Detalhes dos payloads:

// POST /api/auth/verify-recover-method
{ "cpf": "12345678900", "type": "sms" }

// POST /api/auth/verify-code-recover
{ "cpf": "12345678900", "type": "sms", "verificationCode": "123456" }

// POST /api/auth/change-password
{ "token": "<token>", "cpf": "12345678900", "password": "novaSenha1" }

Resposta de recover-methods (sucesso):

{
"isSuccess": true,
"success": [
{ "type": "sms", "maskedValue": "(**) *****-1234" },
{ "type": "email", "maskedValue": "u***@email.com" }
]
}

Resposta de verify-code-recover (sucesso):

{
"isSuccess": true,
"success": {
"userCpf": "12345678900",
"contact": "(**) *****-1234",
"token": "<token>",
"expirationDate": "2026-07-06T12:00:00Z"
}
}

Constantes definidas em lib/shared/utils/api_utils.dart:

static Future<String> getRecoverMethodsUrl({required String cpf}) async {
return '${await _getBaseUrl}$authApi/recover-methods/$cpf';
}

static Future<String> getRecoverMethodsValidateCodeUrl() async {
return '${await _getBaseUrl}$authApi/verify-code-recover';
}

static Future<String> getRecoverMethodSendCodeUrl() async {
return '${await _getBaseUrl}$authApi/verify-recover-method';
}

static const forgetPasswordChangePassword = '$authApi/change-password';

4.2 Endpoints legados (atualização de contato)

Usados no sub-fluxo quando o usuário não recebe o código SMS e precisa atualizar telefone ou e-mail antes de reiniciar a recuperação (CodeVerificationByMethodScreenController.tryAnotherMethod).

MétodoEndpointUso
POST/api/auth/verify-phoneEnviar código SMS (fluxo legado de atualização de telefone)
POST/api/auth/verify-emailEnviar código por e-mail (fluxo legado de atualização de e-mail)
POST/api/auth/verify-codeValidar código (sem sufixo -recover)
POST/api/auth/change-cellphoneAtualizar telefone após validação
POST/api/auth/change-emailAtualizar e-mail após validação
/api/auth/{cpf}/cellphoneConfigurado em ForgotPasswordProvider, mas não utilizado pelo controller atual

5. Telas e Navegação

5.1 Telas do fluxo principal

Rota (AppRoutes)ConstanteTelaTítulo exibidoController
/forgot_passwordchangePasswordForgotPasswordScreenAtualizar senhaForgotPasswordController
/update_user_contact_by_methodsupdateUserContactByMethodsUpdateUserContactByMethodsScreenOpções de atualizaçãoUpdateUserContactByMethodsController
/code_verification_by_methodcodeVerificationByMethodCodeVerificationByMethodScreenCódigo de verificaçãoCodeVerificationByMethodScreenController
/forgot_password_new_passwordforgotPasswordNewPasswordForgotPasswordNewPasswordScreenAtualizar senhaForgotPasswordNewPasswordController
/loginloginLoginScreenLoginController

Nota: A rota AppRoutes.changePassword aponta para /forgot_password e renderiza ForgotPasswordScreen — o nome da constante é legado, mas representa a tela de entrada do fluxo de recuperação.

5.2 Argumentos de navegação

TelaClasse de argumentosCampos
ForgotPasswordScreenForgotPasswordScreenArgumentsrememberCpfOnLogin
UpdateUserContactByMethodsScreenUpdateUserContactByMethodsScreenArgumentavailableMethods, customAuthorizationToken, cpf, rememberCpfOnLogin
CodeVerificationByMethodScreenCodeVerificationByMethodScreenArgumentsverifyMethodsSuccessResponseItem, options, customAuthorizationToken, cpf, rememberCpfOnLogin, hasConfirmedEmail
ForgotPasswordNewPasswordScreenForgotPasswordNewPasswordScreenArgumentstoken, cpf, rememberCpfOnLogin
LoginScreen (retorno)LoginScreenArgumentscpf, password, rememberCpf

5.3 Telas auxiliares (atualização de contato)

RotaTelaQuando é acionada
/update_phoneUpdatePhoneScreenUsuário excede limite de tentativas SMS e opta por atualizar telefone
/code_verification_by_phoneCodeVerificationByPhoneScreenVerificação SMS legada após informar novo telefone
/update_emailUpdateEmailScreenUsuário troca método de verificação para e-mail
/code_verification_by_emailCodeVerificationByEmailScreenVerificação e-mail legada após informar novo e-mail

6. Keys e Configurações

6.1 Firebase Remote Config

KeyTipoPropriedade DartUso
enable_forgot_passwordboolFirebaseRemoteConfigService.dictionary.enableForgotPasswordControla visibilidade do botão "Esqueci minha senha" no login
recover_methods_tokenstringFirebaseRemoteConfigService.dictionary.recoverMethodsTokenValor do header x-api-key para endpoints de recuperação
recover_password_tokenstringFirebaseRemoteConfigService.dictionary.recoverPasswordTokenValor do header x-api-key para paths contendo cellphone

Definições em lib/services/firebase_remote_config_service.dart (FirebaseRemoteConfigKeysEnum).

6.2 Headers HTTP e Interceptors

HeaderInterceptorCondição de aplicaçãoValor
x-api-keyVerifyMethodsInterceptorPath contém: recover-methods, verify-recover-method, verify-email, verify-phone, verify-code, verify-code-recover, change-passwordrecover_methods_token
x-api-keyRecoverPasswordInterceptorPath contém: cellphonerecover_password_token
AuthorizationChangePasswordInterceptorFluxos com customAuthorizationToken (atualização de contato autenticada)Token Bearer customizado

Interceptors registrados globalmente em DioUtils._addInterceptor:

dio.interceptors.add(RecoverPasswordInterceptor());
dio.interceptors.add(VerifyMethodsInterceptor());

7. Modelos de Request/Response

Requests

ModeloCamposEndpoint
SendCodeVerificationByMethodsRequestcpf, typeverify-recover-method
ValidateCodeVerificationByMethodsRequestcpf, type, verificationCodeverify-code-recover
ForgotPasswordChangePasswordRequesttoken, cpf, passwordchange-password

Responses

ModeloCampos relevantes
VerifyMethodsResponseisSuccess, success[] (type, maskedValue), error (title, message, needConfirm)
SendCodeVerificationByMethodsResponseisSuccess, success/error
ValidateCodeVerificationByMethodsResponseisSuccess, success.token, success.expirationDate, error.message
ForgotPasswordChangePasswordResponseisSuccess, success (title, message), error (title, message, needConfirm)

8. Regras de Negócio

Validação de senha

A nova senha deve atender todos os critérios (validados em tempo real em ForgotPasswordNewPasswordController):

  • Mínimo de 6 caracteres
  • Pelo menos 1 número
  • Pelo menos 1 letra
  • Confirmação idêntica à senha informada

Timer de reenvio de código

  • Intervalo de 2 minutos entre solicitações de reenvio
  • Controlado por CodeVerificationTimerController (instâncias separadas para SMS e E-mail via DI tags)
  • Botão "Reenviar código" habilitado apenas após expiração do timer

Limite de tentativas SMS

Implementado em PhoneCodeVerificationCounterService:

  • Máximo de 3 tentativas de SMS em 1 hora (0 em modo debug)
  • Após exceder o limite, exibe bottom sheet oferecendo validação por e-mail
  • Regra só se aplica quando o usuário possui e-mail cadastrado (hasConfirmedEmail == true)

Comportamento pós-troca de senha

CenárioComportamento
SucessoRemove biometria, exibe bottom sheet de confirmação, redireciona ao login com CPF/senha preenchidos (Get.offAllNamed)
ErroExibe bottom sheet com mensagem de erro, retorna à tela de CPF (Get.offNamed/forgot_password)

Tratamento de erros em recover-methods

CondiçãoComportamento
error.needConfirm == trueExibe bottom sheet informativo
error.needConfirm == falseExibe mensagem de erro inline no campo CPF

9. Diagramas

9.1 Fluxo completo com decisões

9.2 Sequência de chamadas API

9.3 Tratamento de erros

9.4 Sub-fluxo de atualização de contato

Acionado quando o usuário excede o limite de tentativas SMS ou opta por atualizar telefone/e-mail durante a verificação.


10. Arquivos Relacionados

Controllers

ArquivoResponsabilidade
lib/controllers/forgot_password/forgot_password_controller.dartCPF e chamada recover-methods
lib/controllers/forgot_password/forgot_password_new_password_controller.dartNova senha e chamada change-password
lib/controllers/code_verification/by_method/code_verification_by_method_controller.dartEnvio e validação de código no fluxo principal
lib/controllers/update_user_contact_by_methods/update_user_contact_by_methods_controller.dartNavegação para verificação por método
lib/controllers/login/login_controller.dartEntrada via "Esqueci minha senha"
lib/controllers/code_verification/phone/code_verification_by_phone_controller.dartVerificação SMS legada
lib/controllers/code_verification/email/code_verification_by_email_controller.dartVerificação e-mail legada
lib/controllers/update_phone/update_phone_controller.dartAtualização de telefone
lib/controllers/update_email/update_email_controller.dartAtualização de e-mail

Screens

ArquivoRota
lib/screens/forgot_password/forgot_password_screen.dart/forgot_password
lib/screens/forgot_password/forgot_password_new_password_screen.dart/forgot_password_new_password
lib/screens/update_user_contact_by_methods/update_user_contact_by_methods_screen.dart/update_user_contact_by_methods
lib/screens/code_verification/by_method/code_verification_by_method_screen.dart/code_verification_by_method
lib/screens/code_verification/phone/code_verification_by_phone_screen.dart/code_verification_by_phone
lib/screens/code_verification/email/code_verification_by_email_screen.dart/code_verification_by_email
lib/screens/update_phone/update_phone_screen.dart/update_phone
lib/screens/update_email/update_email_screen.dart/update_email
lib/screens/login/login_screen.dart/login
lib/screens/login/login_manager.dartEntrada obrigatória (needChangePassword)

Providers

ArquivoURL base
lib/providers/forgot_password/forgot_password_provider.dartapi/auth/{cpf}/cellphone (legado, não usado)
lib/providers/forgot_password/forgot_password_new_password_provider.dartapi/auth/change-password
lib/providers/code_verification/by_method/code_verification_by_method_provider.dartURL dinâmica via controller

Models

ArquivoDescrição
lib/models/forgot_password/verify_methods_response.dartResposta de recover-methods
lib/models/forgot_password/forgot_password_change_password_request.dartRequest de change-password
lib/models/forgot_password/forgot_password_change_password_response.dartResposta de change-password
lib/controllers/forgot_password/send_code_verification_by_methods_request.dartRequest de envio de código
lib/controllers/forgot_password/send_code_verification_by_methods_response.dartResposta de envio de código
lib/controllers/forgot_password/validate_code_verification_by_methods_request.dartRequest de validação de código
lib/controllers/forgot_password/validate_code_verification_by_methods_response.dartResposta de validação de código

Middlewares e infraestrutura

ArquivoDescrição
lib/middlewares/http/recover_methods_interceptor.dartInjeta x-api-key para endpoints de recover
lib/middlewares/http/recover_password_interceptor.dartInjeta x-api-key para paths com cellphone
lib/middlewares/http/change_password.dartInjeta Authorization para fluxos autenticados
lib/shared/utils/api_utils.dartConstantes e builders de URL
lib/shared/utils/dio_utils.dartRegistro de interceptors
lib/shared/routes/app_routes.dartConstantes de rotas
lib/shared/routes/app_pages.dartRegistro de páginas GetX
lib/services/firebase_remote_config_service.dartKeys de Remote Config
lib/screens/code_verification/by_method/code_verification_counter_service.dartControle de tentativas SMS