I can't verify google Authenticator OTP, I got alwais Incorrect OTP code in Flutter

271 Views Asked by At

I am tring to enable OTP verification from Google Authenticator or other Authenticator app. I was able to generate secretKey and place on QRcode. Correctly display on Authenticator app, but when I am trying to verify the OTP with the digits I get from the APP I get Incorrect ORP Code, and if I print "generatedCode" it is different from the one in the app. Here is my whole code:

class OtpQrCode extends StatefulWidget {
  @override
  _OtpQrCodeState createState() => _OtpQrCodeState();
}

class _OtpQrCodeState extends State<OtpQrCode> {
  bool _isOtpEnabled = false;
  String? _otpSecret;
  final _formKey = GlobalKey<FormState>();
  String? _otpCode;

  void _toggleOtp() {
    setState(() {
      _isOtpEnabled = !_isOtpEnabled;

      if (_isOtpEnabled) {
        _otpSecret = OTP.randomSecret();
      } else {
        _otpSecret = null;
      }
    });
  }

  final TextEditingController _otpController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          SwitchListTile(
            title: Text('Enable OTP'),
            value: _isOtpEnabled,
            onChanged: (bool value) {
              _toggleOtp();
            },
          ),
          if (_isOtpEnabled)
            QrImage(
              data: _otpUri(),
              version: QrVersions.auto,
              size: 200,
            ),
          if (_isOtpEnabled)
            Text(_otpSecret ?? ''),
          if (_isOtpEnabled)
            Padding(
              padding: const EdgeInsets.symmetric(horizontal: 16.0),
              child: Form(
                key: _formKey,
                child: Column(
                  children: [
                    TextFormField(
                      controller: _otpController,
                      maxLength: 6,
                      keyboardType: TextInputType.number,
                      decoration: InputDecoration(
                        labelText: 'Enter OTP',
                      ),
                      validator: (value) {
                        if (value!.isEmpty || value.length != 6) {
                          return 'Please enter a valid 6-digit OTP';
                        }
                        return null;
                      },
                      onChanged: (value) {
                        setState(() {
                          _otpCode = value;
                        });
                      },
                    ),
                    SizedBox(height: 16.0),
                    ElevatedButton(
                      onPressed: () {
                        if (_formKey.currentState!.validate()) {
                          _verifyOtp();
                        }
                      },
                      child: Text('Verify OTP'),
                    ),
                  ],
                ),
              ),
            ),
        ],
      ),
    );
  }

  String _otpUri() {
    String issuer = 'YourApp';
    String accountName = '[email protected]'; // Replace with user email or unique identifier

    return _generateTOTPUrl(
      secret: _otpSecret,
      accountName: accountName,
      issuer: issuer,
      algorithm: 'SHA1',
      digits: 6,
      period: 30,
    );
  }

  String _generateTOTPUrl({
    @required String? secret,
    @required String? accountName,
    @required String? issuer,
    String algorithm = 'SHA1',
    int digits = 6,
    int period = 30,
  }) {
    return 'otpauth://totp/${Uri.encodeComponent(accountName!)}?secret=$secret&issuer=${Uri.encodeComponent(issuer!)}&algorithm=$algorithm&digits=$digits&period=$period';
  }

  void _verifyOtp() async {
    if (_otpController.text.isEmpty) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Enter OTP')),
      );
      return;
    }

    bool isCodeValid = false;
    int currentTime = DateTime.now().millisecondsSinceEpoch;

    for (int i = -1; i <= 1; i++) {
      int time = ((currentTime + (i * 30 * 1000)) / 1000).floor();
      String generatedCode = OTP.generateTOTPCodeString(
        _otpSecret!,
        time,
        algorithm: Algorithm.SHA1,
        length: 6,
      );

      print(generatedCode);
      if (_otpController.text == generatedCode) {
        isCodeValid = true;
        break;
      }
    }

    if (isCodeValid) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('OTP verified successfully!')),
      );
    } else {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Incorrect OTP code')),
      );
    }
  }
}

0

There are 0 best solutions below