{"record":{"id":"3619b1ed26fad6b3","repo":"we-promise/sure","slug":"snaptrade-oauth-is-not-configured","errorCode":null,"errorMessage":"SnapTrade OAuth is not configured","messagePattern":"SnapTrade OAuth is not configured","errorType":"exception","errorClass":"Provider::Snaptrade::ConfigurationError","httpStatus":null,"severity":"error","filePath":"app/models/provider/snaptrade.rb","lineNumber":63,"sourceCode":"    end\n\n    def oauth_client_id\n      Rails.configuration.x.snaptrade&.oauth_client_id\n    end\n\n    def oauth_client_secret\n      Rails.configuration.x.snaptrade&.oauth_client_secret\n    end\n\n    # PKCE pair per RFC 7636 (S256)\n    def generate_pkce\n      verifier = SecureRandom.urlsafe_base64(64).delete(\"=\")[0, 128]\n      challenge = Base64.urlsafe_encode64(OpenSSL::Digest::SHA256.digest(verifier), padding: false)\n      { verifier: verifier, challenge: challenge }\n    end\n\n    def authorize_url(redirect_uri:, state:, code_challenge:, scope: \"read\")\n      raise ConfigurationError, \"SnapTrade OAuth is not configured\" unless oauth_configured?\n\n      params = {\n        response_type: \"code\",\n        client_id: oauth_client_id,\n        redirect_uri: redirect_uri,\n        scope: scope,\n        state: state,\n        code_challenge: code_challenge,\n        code_challenge_method: \"S256\"\n      }\n      \"#{AUTHORIZE_URL}?#{params.to_query}\"\n    end\n\n    def exchange_code(code:, redirect_uri:, code_verifier:)\n      token_request(\n        grant_type: \"authorization_code\",\n        code: code,\n        redirect_uri: redirect_uri,","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/we-promise/sure/blob/e69894adb92547273377398c15f45c979cd9416a/app/models/provider/snaptrade.rb#L45-L81","documentation":"Provider::Snaptrade.authorize_url builds the OAuth authorization redirect (authorization-code + PKCE per RFC 7636) and raises ConfigurationError when the instance has no OAuth app credentials. oauth_configured? (app/models/provider/snaptrade.rb:43) requires BOTH Rails.configuration.x.snaptrade.oauth_client_id and .oauth_client_secret, which config/initializers/snaptrade.rb:3-6 populates from ENV['SNAPTRADE_OAUTH_CLIENT_ID'/'SNAPTRADE_OAUTH_CLIENT_SECRET'] or Rails credentials dig(:snaptrade, :oauth_client_id/:oauth_client_secret). Seeing this error means neither source supplied the pair, so the SnapTrade OAuth feature is effectively disabled on this deployment.","triggerScenarios":"A user clicks 'Connect via SnapTrade' and snaptrade_items_controller calls Provider::Snaptrade.authorize_url(redirect_uri:, state:, code_challenge:) on an instance where the admin never registered an OAuth app, or set only one of the two env vars, or only defined credentials without the env vars and vice versa. The raise happens before any URL is built, so the redirect action 500s.","commonSituations":"Fresh self-hosted install without provider setup; keys configured in .env.local for dev but missing in production; typo'd env var name (e.g. SNAPTRADE_OAUTH_CLIENTID); credentials file edited without a :snaptrade: section; Puma/sidekiq not restarted after adding the env vars.","solutions":["Register an OAuth app on dashboard.snaptrade.com and copy its client id/secret","Set both SNAPTRADE_OAUTH_CLIENT_ID and SNAPTRADE_OAUTH_CLIENT_SECRET in the environment (or run 'bin/rails credentials:edit' and add snaptrade: oauth_client_id / oauth_client_secret)","Restart the Rails server and any background workers so the initializer re-reads config","Verify in console: Provider::Snaptrade.oauth_configured? must return true","Guard the connect action with oauth_configured? and render the setup instructions instead of a 500"],"exampleFix":"# before (snaptrade_items_controller)\ndef oauth_start\n  redirect_to Provider::Snaptrade.authorize_url(redirect_uri: oauth_callback_snaptrade_items_url, state: SecureRandom.hex(32), code_challenge: Provider::Snaptrade.generate_pkce[:challenge]), allow_other_host: true\nend\n\n# after\ndef oauth_start\n  unless Provider::Snaptrade.oauth_configured?\n    redirect_to settings_provider_path, alert: t('snaptrade_items.snaptrade.oauth_setup_step_1_html') and return\n  end\n  redirect_to Provider::Snaptrade.authorize_url(redirect_uri: oauth_callback_snaptrade_items_url, state: SecureRandom.hex(32), code_challenge: Provider::Snaptrade.generate_pkce[:challenge]), allow_other_host: true\nend","handlingStrategy":"validation","validationCode":"# Run before starting the OAuth flow\nreturn unless Provider::Snaptrade.oauth_configured?","typeGuard":"def snaptrade_oauth_ready?\n  Provider::Snaptrade.oauth_configured?\nend","tryCatchPattern":"begin\n  redirect_to Provider::Snaptrade.authorize_url(redirect_uri:, state:, code_challenge:)\nrescue Provider::Snaptrade::ConfigurationError\n  redirect_to settings_path, alert: 'SnapTrade OAuth app is not configured on this instance'\nend","preventionTips":["Add a deploy/health check that fails when SNAPTRADE_OAUTH_CLIENT_ID or SNAPTRADE_OAUTH_CLIENT_SECRET is blank","Hide/disable the SnapTrade connect button when !Provider::Snaptrade.oauth_configured?","Keep a boot-time assertion in config/initializers/snaptrade.rb logging a warning when half-configured (one key present)"],"tags":["snaptrade","oauth","configuration","missing-env-var","pkce"],"backgroundTag":"missing-oauth-credentials","analyzedSha":"e69894adb92547273377398c15f45c979cd9416a","analyzedAt":"2026-08-21T18:22:41.165Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}