BeyondDimension/SteamTools · warning · ApplicationException

Import only supports otpauth://totp/ or otpauth://hotp/

Error message

Import only supports otpauth://totp/ or otpauth://hotp/

What it means

Thrown during authenticator import when the URI scheme is otpauth but the host (the OTP type segment) is neither 'totp' nor 'hotp'. The importer supports only time-based and HMAC-based counter one-time passwords; any other type label in otpauth://<type>/ is rejected.

Source

Thrown at src/BD.WTTS.Client.Plugins.Authenticator/UI/ViewModels/AuthenticatorImportPageViewModel.cs:272

                var qm = line.IndexOf("?", StringComparison.Ordinal);
                if (hash != -1 && hash < qm)
                {
                    line = $"{line.Substring(0, hash)}%23{line[(hash + 1)..]}";
                }

                // parse and validate URI
                var uri = new Uri(line);

                // we only support "otpauth"
                if (uri.Scheme != "otpauth")
                {
                    throw new ApplicationException("Import only supports otpauth://");
                }

                // we only support totp (not hotp)
                if (uri.Host != "totp" && uri.Host != "hotp")
                {
                    throw new ApplicationException("Import only supports otpauth://totp/ or otpauth://hotp/");
                }

                // get the label and optional issuer
                string issuer = string.Empty;
                string label = string.IsNullOrEmpty(uri.LocalPath) == false
                    ? uri.LocalPath[1..]
                    : string.Empty; // skip past initial /
                int p = label.IndexOf(":", StringComparison.Ordinal);
                if (p != -1)
                {
                    issuer = label.Substring(0, p);
                    label = label[(p + 1)..];
                }

                // + aren't decoded
                label = label.Replace("+", " ");

                var query = HttpUtility.ParseQueryString(uri.Query);

View on GitHub (pinned to c16ffa08e0)

Solutions

  1. Re-export the entry as otpauth://totp/ or otpauth://hotp/ from the source authenticator.
  2. For Steam entries, import via the dedicated Steam Guard import flow instead of the otpauth parser.
  3. Manually correct the type segment to 'totp' (most secrets are TOTP-compatible).
  4. Reject the entry in the UI with a clear message listing the supported types.

Example fix

// before
if (uri.Host != "totp" && uri.Host != "hotp")
    throw new ApplicationException("Import only supports otpauth://totp/ or otpauth://hotp/");

// after: tolerant, case-insensitive check with guidance
var type = uri.Host.ToLowerInvariant();
if (type != "totp" && type != "hotp")
    throw new ArgumentException(string.Format(Strings.Import_UnsupportedOtpType, uri.Host));
Defensive patterns

Strategy: validation

Validate before calling

static bool IsSupportedOtpType(Uri uri)
    => uri.Host.Equals("totp", StringComparison.OrdinalIgnoreCase)
    || uri.Host.Equals("hotp", StringComparison.OrdinalIgnoreCase);

if (!IsSupportedOtpType(uri))
    errors.Add(($"Line {n}: otpauth type '{uri.Host}' not supported (use totp or hotp).", line));

Type guard

bool IsTotpOrHotp(Uri u) => u.Host is "totp" or "hotp";

Try / catch

try { ParseAuthenticator(line); }
catch (ApplicationException ex) when (ex.Message.Contains("otpauth://totp/ or otpauth://hotp/"))
{
    importErrors.Add(($"Unsupported OTP type (line {n}).", line));
    continue;
}

Prevention

When it happens

Trigger: Parsing otpauth:// URIs where the authority segment is something other than totp or hotp — e.g. otpauth://steam/..., a custom type, or a malformed URI whose 'host' is empty.

Common situations: Steam-style URIs using a non-standard type label; entries exported by a tool that invented its own type; URI was truncated so the type segment is missing; case/encoding issues that shifted the host.

Related errors


AI-assisted analysis of BeyondDimension/SteamTools@c16ffa08e0 (2026-08-13). Data as JSON: /api/errors/8c3b483803a74d85. Report an issue: GitHub.