{"record":{"id":"26740b0bbe236c52","repo":"sahat/hackathon-starter","slug":"missing-or-invalid-token-tokensecret","errorCode":null,"errorMessage":"Missing or invalid token/tokenSecret","messagePattern":"Missing or invalid token/tokenSecret","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"config/passport.js","lineNumber":593,"sourceCode":" * Tumblr API OAuth.\n */\npassport.use(\n  'tumblr',\n  new OAuthStrategy(\n    {\n      requestTokenURL: 'https://www.tumblr.com/oauth/request_token',\n      accessTokenURL: 'https://www.tumblr.com/oauth/access_token',\n      userAuthorizationURL: 'https://www.tumblr.com/oauth/authorize',\n      consumerKey: process.env.TUMBLR_KEY,\n      consumerSecret: process.env.TUMBLR_SECRET,\n      callbackURL: '/auth/tumblr/callback',\n      state: true,\n      passReqToCallback: true,\n    },\n    async (req, token, tokenSecret, profile, done) => {\n      try {\n        if (!token || !tokenSecret) {\n          throw new Error('Missing or invalid token/tokenSecret');\n        }\n        // Helper function to generate the OAuth 1.0a authHeader for Tumblr API.\n        // This function is not going to make any actual calls to\n        // tumblr's /request_token or /access_token endpoints.\n        function getTumblrAuthHeader(url, method) {\n          const oauth = new OAuth('https://www.tumblr.com/oauth/request_token', 'https://www.tumblr.com/oauth/access_token', process.env.TUMBLR_KEY, process.env.TUMBLR_SECRET, '1.0A', null, 'HMAC-SHA1');\n          return oauth.authHeader(url, token, tokenSecret, method);\n        }\n        const userInfoURL = 'https://api.tumblr.com/v2/user/info';\n        const response = await fetch(userInfoURL, { headers: { Authorization: getTumblrAuthHeader(userInfoURL, 'GET') } });\n        if (!response.ok) {\n          throw new Error(`HTTP error! status: ${response.status}`);\n        }\n        const data = await response.json();\n        // Extract user info from the API response\n        const tumblrUser = data.response.user;\n        const primaryBlog = tumblrUser.blogs?.find((blog) => blog.primary) || tumblrUser.blogs?.[0];\n        const providerProfile = {","sourceCodeStart":575,"sourceCodeEnd":611,"githubUrl":"https://github.com/sahat/hackathon-starter/blob/c12e339564db59443df0b901818c9bb661331b28/config/passport.js#L575-L611","documentation":"OAuth 1.0a strategies exchange the request token for an access token and tokenSecret; this Tumblr strategy callback throws when either is falsy, meaning the token exchange step failed or returned empty credentials.","triggerScenarios":"Completing the Tumblr OAuth 1.0a handshake where the callback receives token or tokenSecret as null/undefined/empty — e.g. user denied authorization, callback URL mismatch, or Tumblr returned an error payload instead of credentials.","commonSituations":"TUMBLR_KEY/TUMBLR_SECRET missing or wrong in .env, callback URL registered in the Tumblr app not matching the route, or clock/nonce issues in OAuth 1.0a causing an empty token response.","solutions":["Verify TUMBLR_KEY and TUMBLR_SECRET are set and match the Tumblr app credentials","Check the callback URL in the Tumblr app matches /auth/tumblr/callback exactly (scheme, host, path)","Watch server logs for the preceding OAuth exchange error; if the user denied consent, prompt them to retry and approve"],"exampleFix":"// before\nif (!token || !tokenSecret) throw new Error('Missing or invalid token/tokenSecret');\n// after: surface a flash message via the done(error) handler / auth/failure route\nif (!token || !tokenSecret) return done(new Error('Tumblr authorization was not completed. Please try again.'));","handlingStrategy":"try-catch","validationCode":"if (!process.env.TUMBLR_KEY || !process.env.TUMBLR_SECRET) throw new Error('Tumblr env vars missing');","typeGuard":null,"tryCatchPattern":"catch (e) { if (/Missing or invalid token/.test(e.message)) return done(null, false, {msg:'Tumblr authorization incomplete'}); throw e; }","preventionTips":["Fail fast on missing env vars at startup","Keep the registered callback URL in sync with the deployed host"],"tags":["oauth","oauth1","tumblr","env-vars"],"backgroundTag":"oauth1-token-exchange-failed","analyzedSha":"c12e339564db59443df0b901818c9bb661331b28","analyzedAt":"2026-08-27T11:05:00.872Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}