{"record":{"id":"379b328c6f162ec4","repo":"ellite/Wallos","slug":"invalid-secret-parameter","errorCode":null,"errorMessage":"Invalid \"secret\" parameter.","messagePattern":"Invalid \"secret\" parameter\\.","errorType":"exception","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"libs/OTPHP/ParameterTrait.php","lineNumber":50,"sourceCode":"\n    /**\n     * @return array<non-empty-string, mixed>\n     */\n    public function getParameters(): array\n    {\n        $parameters = $this->parameters;\n\n        if ($this->getIssuer() !== null && $this->isIssuerIncludedAsParameter() === true) {\n            $parameters['issuer'] = $this->getIssuer();\n        }\n\n        return $parameters;\n    }\n\n    public function getSecret(): string\n    {\n        $value = $this->getParameter('secret');\n        (is_string($value) && $value !== '') || throw new InvalidArgumentException('Invalid \"secret\" parameter.');\n\n        return $value;\n    }\n\n    public function getLabel(): null|string\n    {\n        return $this->label;\n    }\n\n    public function setLabel(string $label): void\n    {\n        $this->setParameter('label', $label);\n    }\n\n    public function getIssuer(): null|string\n    {\n        return $this->issuer;\n    }","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/ellite/Wallos/blob/52820e87ca5a6e105fdbb7f1c0c681bc0cfee2fd/libs/OTPHP/ParameterTrait.php#L32-L68","documentation":"This is a validation guard inside OTPHP's ParameterTrait: getSecret() fetches the 'secret' parameter from the OTP parameters array and throws InvalidArgumentException when it is missing, not a string, or an empty string. It fires when an OTP (TOTP/LTOTP) object was constructed or loaded (e.g., from a provisioning URI or createFromUpdatedProvisioningUri) without a valid secret being set, and code then tries to read the secret via getSecret(). Fix by ensuring the object is created with a non-empty secret string before calling getSecret().","triggerScenarios":"Instantiating an OTP object without a secret (e.g. new TOTP() or an empty-string secret), loading a provisioning URI without secret= in the query, or a secret parameter that was somehow set to null/non-string.","commonSituations":"Empty env var or DB column for the secret; URI parse dropping the query string; factory misuse creating an object before assigning the secret.","solutions":["Always pass a non-empty base32 secret to TOTP::create()/HOTP::create().","Check the configuration source: ensure the secret env var/DB field is populated before constructing the OTP.","When parsing URIs, verify the query string contains secret=<base32>.","Guard in calling code: if ($secret === '' || $secret === null) throw a domain-specific error."],"exampleFix":"// before\n$totp = TOTP::create($_ENV['OTP_SECRET'] ?? ''); // empty -> throws later\n// after\n$secret = $_ENV['OTP_SECRET'] ?? null;\nif (!is_string($secret) || $secret === '') {\n    throw new RuntimeException('OTP_SECRET is not configured');\n}\n$totp = TOTP::create($secret);","handlingStrategy":"validation","validationCode":"if (!is_string($secret) || $secret === '') {\n    throw new MissingConfigurationException('OTP secret is not configured');\n}\n$totp = TOTP::create($secret);","typeGuard":"function hasSecret(object $otp): bool {\n    try { return $otp->getSecret() !== ''; } catch (InvalidArgumentException) { return false; }\n}","tryCatchPattern":"try {\n    $code = $otp->at(time());\n} catch (InvalidArgumentException $e) {\n    log_error('OTP secret missing or invalid', ['exception' => $e->getMessage()]);\n    throw new OtpNotConfiguredException($e);\n}","preventionTips":["Fail fast at boot if the OTP secret env var/DB field is empty","Never construct OTP objects from unvalidated config values","Assert secrets are non-empty base32 in a health check","Centralize OTP construction in one factory that validates inputs"],"tags":["php","otp","secret","missing-value"],"backgroundTag":"empty-required-field","analyzedSha":"52820e87ca5a6e105fdbb7f1c0c681bc0cfee2fd","analyzedAt":"2026-09-13T14:09:30.873Z","contentChangedAt":"2026-09-13T14:09:30.873Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}