Schotsl
Schotsl

Reputation: 227

Twitter API returns 'Invalid or expired token.'

I have a simple application that doesn't use very many packages. So I thought this would be the perfect opportunity to try out Deno, the one package I do require that isn't a third-party module is the Twitter API. No problem I thought since I don't need many of the functions it includes. I might as well write it myself!

So I wrote a function for generating an Bearer token using this doc from the Twitter docs:

function getOAuthBearer(consumer_key, consumer_secret) {
    const basic = Buffer.from(`${consumer_key}:${consumer_secret}`).toString('base64')
    const options = {
        url: 'https://api.twitter.com/oauth2/token',
        method: 'POST',
        headers: {
            'Authorization': `Basic ${basic}`,
            'Content-Type': `application/x-www-form-urlencoded;charset=UTF-8`
        },
        body: querystring.stringify({
            'grant_type': 'client_credentials'
        })
    };

    return new Promise((resolve, reject) => {
        request(options, (error, response, body) => {
            if (error) reject(error);
            else resolve(JSON.parse(body).access_token);
        });  
    });
}

Which works! I got my bearer token, so I wrote a function to fetch some user_timeline information from a request example from this doc

function getUserTimeline(bearer_token) {
    const options = {
        url: 'https://api.twitter.com//1.1/statuses/user_timeline.json?count=100&screen_name=twitterapi',
        method: 'GET',
        headers: {
            'Authorization': 'Bearer ' + Buffer.from(bearer_token).toString('base64'),
        }
    }

    return new Promise((resolve, reject) => {
        request(options, (error, response, body) => {
            if (error) reject(error);
            else resolve(JSON.parse(body));
        });  
    });
}

Which returns this:

{ errors: [ { code: 89, message: 'Invalid or expired token.' } ] }

Which is weird but I thought I could just invalidate the bearer and request a new one for which I wrote this function:

function invalideOAuthBearer(consumer_key, consumer_secret, bearer_token) {
    const basic = Buffer.from(`${consumer_key}:${consumer_secret}`).toString('base64');
    const options = {
        url: 'https://api.twitter.com/oauth2/invalidate_token',
        method: 'POST',
        headers: {
            'Authorization': `Basic ${basic}`,
            'Content-Type': `application/x-www-form-urlencoded;charset=UTF-8`
        },
        body: querystring.stringify({
            'access_token': bearer_token
        })
    };

    return new Promise((resolve, reject) => {
        request(options, (error, response, body) => {
            if (error) reject(error);
            else resolve(JSON.parse(body));
        });  
    });
}

But this returns:

{ errors: [ { code: 348, message: 'Client application is not permitted to to invalidate this token.' } ] }

So now I'm somewhat stuck, I tried regenerating my credentials and that doesn't do much. I searched online but could only find old post of people saying it's a bug/infrastructure issue but since there are so many applications using the Twitter API this seems unlikely to me, and of course, there are people just recommending using a package like twitter, which I would but like I said the Deno platform doesn't have any packages like this :(

Upvotes: 1

Views: 555

Answers (1)

dbrands
dbrands

Reputation: 141

The bearer token shouldn't be base64 encoded. Try this:

const options = {
        url: 'https://api.twitter.com//1.1/statuses/user_timeline.json?count=100&screen_name=twitterapi',
        method: 'GET',
        headers: {
            'Authorization': `Bearer ${bearer_token}`,
        }
    }

Upvotes: 2

Related Questions