beemdevelopment/Aegis · error
Bad secret
Error message
Bad secret
What it means
The 'secret' parameter was present but could not be decoded: Base32 decoding failed (for otpauth) or Hex decoding failed (for motp), raising an EncodingException that is wrapped in GoogleAuthInfoException with message 'Bad secret'.
Solutions
- Confirm the secret is valid Base32 (A-Z, 2-7, '=' padding) for otpauth URIs, or hex for motp
- Re-copy the secret from the provider, removing spaces and newlines
- Use a Base32/Hex library to validate the secret before building the URI
Example fix
// before String uri = "otpauth://totp/x?secret=not_base32!!"; // after String secret = "JBSWY3DPEHPK3PXP"; // valid Base32 String uri = "otpauth://totp/x?secret=" + secret;
Defensive patterns
Strategy: validation
Validate before calling
if (!secret.matches("[A-Z2-7=]+")) throw new IllegalArgumentException("secret is not valid Base32"); Try / catch
try { return GoogleAuthInfo.parseUri(uri); } catch (GoogleAuthInfoException e) { if (e.getMessage().contains("Bad secret")) showBadSecretHint(); return null; } Prevention
- Sanitize secrets: uppercase, strip whitespace/newlines
- Use standard Base32 (RFC 4648) when generating URIs
- Distinguish hex secrets (motp) from Base32 (otpauth)
When it happens
Trigger: parseUri(Uri) with a secret containing characters outside the Base32 alphabet (or non-hex chars for motp), wrong casing/padding, or a URL-encoded secret not properly decoded.
Common situations: Manually typing a secret with O/0 or 1/I confusion, copying a hex secret into a totp URI, truncating the secret, or whitespace/newline contamination from copy-paste.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- Invalid Yandex secret length
- Secret is not valid hexadecimal
- Bad URI format
- Unsupported protocol
- Parameter 'secret' is not present
AI-assisted analysis of beemdevelopment/Aegis@d6f4e5925a (2026-09-08).
Data as JSON: /api/errors/b66d9a8c100b918c.
Report an issue: GitHub.
Appendix: source
Thrown at app/src/main/java/com/beemdevelopment/aegis/otp/GoogleAuthInfo.java:60
}
public static GoogleAuthInfo parseUri(Uri uri) throws GoogleAuthInfoException {
String scheme = uri.getScheme();
if (scheme == null || !(scheme.equals(SCHEME) || scheme.equals(MotpInfo.SCHEME))) {
throw new GoogleAuthInfoException(uri, String.format("Unsupported protocol: %s", scheme));
}
// 'secret' is a required parameter
String encodedSecret = uri.getQueryParameter("secret");
if (encodedSecret == null) {
throw new GoogleAuthInfoException(uri, "Parameter 'secret' is not present");
}
byte[] secret;
try {
secret = (scheme.equals(MotpInfo.SCHEME)) ? Hex.decode(encodedSecret) : parseSecret(encodedSecret);
} catch (EncodingException e) {
throw new GoogleAuthInfoException(uri, "Bad secret", e);
}
if (secret.length == 0) {
throw new GoogleAuthInfoException(uri, "Secret is empty");
}
OtpInfo info;
String issuer = "";
try {
String type = (scheme.equals(MotpInfo.SCHEME)) ? MotpInfo.ID : uri.getHost();
if (type == null) {
throw new GoogleAuthInfoException(uri, String.format("Host not present in URI: %s", uri.toString()));
}
switch (type) {
case "totp":
TotpInfo totpInfo = new TotpInfo(secret);
String period = uri.getQueryParameter("period");
if (period != null) {View on GitHub (pinned to d6f4e5925a)