sahat/hackathon-starter · error · Error
Missing or invalid token/tokenSecret
Error message
Missing or invalid token/tokenSecret
What it means
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.
Source
Thrown at config/passport.js:593
* Tumblr API OAuth.
*/
passport.use(
'tumblr',
new OAuthStrategy(
{
requestTokenURL: 'https://www.tumblr.com/oauth/request_token',
accessTokenURL: 'https://www.tumblr.com/oauth/access_token',
userAuthorizationURL: 'https://www.tumblr.com/oauth/authorize',
consumerKey: process.env.TUMBLR_KEY,
consumerSecret: process.env.TUMBLR_SECRET,
callbackURL: '/auth/tumblr/callback',
state: true,
passReqToCallback: true,
},
async (req, token, tokenSecret, profile, done) => {
try {
if (!token || !tokenSecret) {
throw new Error('Missing or invalid token/tokenSecret');
}
// Helper function to generate the OAuth 1.0a authHeader for Tumblr API.
// This function is not going to make any actual calls to
// tumblr's /request_token or /access_token endpoints.
function getTumblrAuthHeader(url, method) {
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');
return oauth.authHeader(url, token, tokenSecret, method);
}
const userInfoURL = 'https://api.tumblr.com/v2/user/info';
const response = await fetch(userInfoURL, { headers: { Authorization: getTumblrAuthHeader(userInfoURL, 'GET') } });
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
// Extract user info from the API response
const tumblrUser = data.response.user;
const primaryBlog = tumblrUser.blogs?.find((blog) => blog.primary) || tumblrUser.blogs?.[0];
const providerProfile = {View on GitHub (pinned to c12e339564)
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
Example fix
// before
if (!token || !tokenSecret) throw new Error('Missing or invalid token/tokenSecret');
// after: surface a flash message via the done(error) handler / auth/failure route
if (!token || !tokenSecret) return done(new Error('Tumblr authorization was not completed. Please try again.')); Defensive patterns
Strategy: try-catch
Validate before calling
if (!process.env.TUMBLR_KEY || !process.env.TUMBLR_SECRET) throw new Error('Tumblr env vars missing'); Try / catch
catch (e) { if (/Missing or invalid token/.test(e.message)) return done(null, false, {msg:'Tumblr authorization incomplete'}); throw e; } Prevention
- Fail fast on missing env vars at startup
- Keep the registered callback URL in sync with the deployed host
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
AI-assisted analysis of sahat/hackathon-starter@c12e339564 (2026-08-27).
Data as JSON: /api/errors/26740b0bbe236c52.
Report an issue: GitHub.