{"record":{"id":"48418688dd2a5c37","repo":"passbolt/passbolt_api","slug":"record-not-found-in-table-sso-auth-tokens","errorCode":null,"errorMessage":"Record not found in table \"sso_auth_tokens\"","messagePattern":"Record not found in table \"sso_auth_tokens\"","errorType":"http","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"plugins/PassboltEe/SsoRecover/src/Controller/RecoverStartController.php","lineNumber":78,"sourceCode":"            $settingsDto = (new SsoSettingsGetService())->getActiveOrFail();\n        } catch (RecordNotFoundException $e) {\n            throw new BadRequestException(__('No valid SSO settings found.'), null, $e);\n        }\n\n        $form = new SsoRecoverStartForm();\n        if (!$form->execute($this->getRequest()->getData())) {\n            throw new FormValidationException(__('Could not validate the SSO recover request.'), $form);\n        }\n\n        // Assert & consume sso auth token\n        $ssoAuthService = new SsoAuthenticationTokenGetService();\n        try {\n            $ssoAuthToken = $ssoAuthService->getOrFail(\n                $form->getData('token'),\n                SsoState::TYPE_SSO_RECOVER\n            );\n        } catch (RecordNotFoundException $e) {\n            throw new BadRequestException($e->getMessage(), null, $e);\n        }\n\n        $uac = new ExtendedUserAccessControl(\n            Role::GUEST,\n            $ssoAuthToken->user_id,\n            null,\n            $this->User->ip(),\n            $this->User->userAgent()\n        );\n        $ssoAuthService->assertAndConsume($ssoAuthToken, $uac, $settingsDto->id);\n\n        $url = (new SsoRecoverStartService())->generateAndGetRecoverUrl($ssoAuthToken->user_id);\n\n        $this->success(__('The operation was successful.'), ['url' => $url]);\n    }\n}\n","sourceCodeStart":60,"sourceCodeEnd":95,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltEe/SsoRecover/src/Controller/RecoverStartController.php#L60-L95","documentation":"Thrown when SsoAuthenticationTokenGetService::getOrFail() (with type TYPE_SSO_RECOVER) cannot find the supplied token, and the raw RecordNotFoundException message naming the sso_auth_tokens table is propagated as a BadRequestException. Unlike the success controllers, this message is not rewritten, so the table name appears in the response.","triggerScenarios":"POST /sso/recover/start with a token that does not exist, was already consumed, is of the wrong type, or was deleted; token field valid per form but unknown to the DB.","commonSituations":"Client fabricates or typos the token; token consumed by a prior start attempt; testing with an expired link's token; DB truncation/cleanup between test runs.","solutions":["Use the exact token value from the current SSO recover initiation (verify_token/start response)","Restart the recover flow to mint a new token if the old one was consumed","Check sso_auth_tokens for the token row, its type and active flag when debugging","Ensure only one client/consumer processes the flow at a time to avoid consuming the token twice"],"exampleFix":"// before\nPOST /sso/recover/start {\"username\":\"...\", \"token\":\"<unknown>\"}  -> 400 Record not found in table \"sso_auth_tokens\"\n// after: obtain a live token first\nPOST /sso/recover/start {\"username\":\"...\"} -> follow returned flow -> present the token from that response","handlingStrategy":"validation","validationCode":"if (typeof token !== 'string' || token.length === 0) {\n  throw new Error('token is required for SSO recover start completion');\n}","typeGuard":"const hasValidToken = (data) => typeof data?.token === 'string' && data.token.length > 0;","tryCatchPattern":"try {\n  await ssoRecoverStartComplete({username, token});\n} catch (e) {\n  if (e.message.includes('sso_auth_tokens')) await restartRecoverFlow();\n  else throw e;\n}","preventionTips":["Only use tokens returned by the current flow response","Assume tokens are single-use; request a new one after consumption","Persist the token securely between steps of the flow","Do not run duplicate parallel recover attempts for the same user"],"tags":["sso","auth-token","record-not-found"],"backgroundTag":"record-not-found","analyzedSha":"31c1bbc10f32808a607fa9bd81891e898779c0bc","analyzedAt":"2026-09-17T00:04:38.960Z","contentChangedAt":"2026-09-17T00:04:38.960Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}