verifyCode method

Future<AuthPhoneNumberSignInResult> verifyCode({
  1. required TContext context,
  2. required String phoneNumber,
  3. required String code,
  4. String? name,
  5. DateTime? now,
})

Verifies a code and returns the authenticated user.

Implementation

Future<AuthPhoneNumberSignInResult> verifyCode({
  required TContext context,
  required String phoneNumber,
  required String code,
  String? name,
  DateTime? now,
}) async {
  _ensureConfigured();
  final normalized = _normalizePhoneNumber(phoneNumber);
  final normalizedCode = code.trim();
  if (!RegExp(
    '^[0-9]{$codeLength}\$',
  ).hasMatch(normalizedCode)) {
    throw AuthFlowException('invalid_phone_code');
  }
  final current = (now ?? DateTime.now()).toUtc();
  AuthUser? candidate;
  final knownIdentity = await _backend.findPhoneNumberIdentity(normalized);
  if (allowSignUp && knownIdentity == null) {
    final requestedName = name?.trim();
    if (requestedName != null && requestedName.length > 256) {
      throw AuthFlowException('invalid_request');
    }
    candidate = await Future.sync(
      () =>
          createUser?.call(
            context,
            normalized,
            requestedName?.isEmpty ?? false ? null : requestedName,
          ) ??
          AuthUser(
            id: secureRandomToken(length: 24),
            name: requestedName?.isEmpty ?? false ? null : requestedName,
          ),
    );
  }
  final verification = await _backend.verifyPhoneNumberCode(
    AuthPhoneNumberVerifyCodeCommand(
      phoneNumber: normalized,
      codeDigest: _digest(normalized, normalizedCode),
      now: current,
      candidateUser: candidate,
    ),
  );
  switch (verification.status) {
    case AuthPhoneNumberVerifyStatus.invalid:
      throw AuthFlowException('invalid_phone_code');
    case AuthPhoneNumberVerifyStatus.expired:
      throw AuthFlowException('phone_code_expired');
    case AuthPhoneNumberVerifyStatus.tooManyAttempts:
      throw AuthFlowException('phone_code_too_many_attempts');
    case AuthPhoneNumberVerifyStatus.userNotFound:
    case AuthPhoneNumberVerifyStatus.userUnavailable:
      throw AuthFlowException('user_not_found');
    case AuthPhoneNumberVerifyStatus.conflict:
      throw AuthFlowException('phone_account_conflict');
    case AuthPhoneNumberVerifyStatus.verified:
      break;
  }
  final user = verification.user;
  if (user == null || authUserIsDisabled(user)) {
    throw AuthFlowException('user_not_found');
  }
  await onVerified?.call(context, normalized, user);
  return AuthPhoneNumberSignInResult(phoneNumber: normalized, user: user);
}