This text is part of Introduction to OAuth with Node.js mini-book which is available at gum.co/hRyc.
Let’s start with good old OAuth 1.0. The way it usually works is as follows:
- For the first time, when we authorize a user to use our app, we need to perform extra work and obtain access token and secret (three-legged).
- You store these values for each user in your application.
- Then, on subsequent requests, things become much simpler. We construct auth headers and make HTTP requests (one-legged).
In this chapter, will be dealing only with those later, one-legged requests, as shown in Figure 1–1, while the former three-legged approach will be covered in the Everyauth chapter, i.e., building from simple to more complex.
Twitter provides OAuth tools to generate tokens and secrets for your own apps. This is what we’ll be using for requests. You’ll need four values to make an OAuth 1.0 request to Twitter API v1.1, or any other service using OAuth 1.0:
- Application key, a.k.a. consumer key
- Application secret key
- User token for this application
- User secret for this application
All four of them can be obtained for your own apps at dev.twitter.com, as shown in Figure 1–2.
Just to reiterate, in case you are not the user (which is the most common use case), you’ll need to perform a three-legged OAuth / Sign in with Twitter, or something else. The result of Sign in with Twitter is the response with the user’s token and secret, which can be store in the app database for later usage. For more information, follow the examples in the Everyauth chapter.
Going back to obtaining the keys, click on “Sign in” located in the right upper corner and you’ll see a list of your Twitter applications, if you have any. Your own apps refers to the apps that you have created using your Twitter account. For example, there are three apps shown in Figure 1–3.
For the sake of this exercise, it’s easier to simply create a brand new app and get tokens and secrets for it. Click on Create New App from Figure 1–3’s screenshot and it will take you to the page Create an application, as shown in Figure 1–4.
Fill in the values for Name, Description, Website and Callback URL (it doesn’t matter what it is, as long as it starts with http://
). The callback value can be anything, but if it’s empty, the Twitter app will be locked into the OOB mode, which will prevent us from testing the OAuth Sign-in later (you’ll see Desktop applications only support the OAuth_callback value 'oob'
error). For this reason, put any URL in the callback field, e.g., http://webapplog.com
.
Once the app is created, go to the Permission tab, and change the permission to Read, Write and Access direct messages. This will result in a new value for the Access level field of the API Keys tab, as shown in Figure 1–5. From the same tab, click the button Create my access token. After generation is finished, the results will be in the Your access token section, as show in Figure 1–5. Note that your keys will differ from the illustration.
After the values are generated (it may take some time), copy and store these values:
- API key:
twitterKey
in the Node.js script - API secret:
twitterSecret
in the Node.js script - Access token:
token
in the Node.js script - Access token secret:
secret
in the Node.js script
There are many Node.js OAuth modules and even Node.js Twitter SDKs (wrappers for the Twitter API). However, to understand the basics of making OAuth requests, we’ll be using the most minimalistic module, oauth
. This module will help us to construct auth headers for HTTP requests without the necessity of having to understand all the complexities required to build the headers.
To authorize a request, it must have certain parameters in its Authorization
header (docs), for example:
OAuth oauth_consumer_key="xvz1evFS4wEEPTGEFPHBog", oauth_nonce="kYjzVBB8Y0ZFabxSWbWovY3uYSQ2pTgmZeNu2VS4cg", oauth_signature="tnnArxj06cWHq44gCs1OSKk%2FjLY%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1318622958", oauth_token="370773112-GmHxMAgYyLbNEtIKZeRNFsMKPR9EyMZeS9weJAEb", oauth_version="1.0"
Let’s take a brief look at each of these parameters:
oauth_consumer_key
: this is the same as the application key or Twitter consumer key, i.e., the unique identifier of your appoauth_nonce
: a unique identifier of your request, usually constructed with some random param and hashing algorithmoauth_timestamp
: current time in seconds, since the Unix epochoauth_version
: should always be1.0
for OAuth 1.0oauth_signature_method
: should beHMAC-SHA1
oauth_signature
: a hashed combination of all the other parameters
The exact generation of these parameters is outside the scope of this introductory book. Luckily, there are many modules that can do this legwork for us, i.e., oauth
.
To install the oauth
module, you can use:
$ npm install oauth@0.9.12
In the oauth1/index.js
file, we define the variables for the key, token, and secrets. Replace the string placeholders with your values:
var twitterKey = 'your Twitter application consumer key',
twitterSecret = 'your Twitter application secret',
token = 'your user token for this app',
secret = 'your user secret for this app';
The following is simply an example of how key formats look. Please use your own, because these values will be invalidated:
twitterKey = 'A3UP583JRnLWuAdeMUBJjzOn2';
twitterSecret = 'tQEu1d0cMU43hk2hk5J77UhIweJ7z4oEPVl6OhxbMRONtLMLMG';
token = '575632191-r98rIwyKnAxTHFt86bKX5ZaFeYRzmfOF5JbaPyPI';
secret = 'eryuMTstgYrcerrL43XwVX1EAOJMTdQxvGKHu5UUSiBY7';
Going back to our file (oauth1/index.js
), we import the OAuth
class and create an object for OAuth 1.0 where the parameters are Twitter API endpoints, key, and secret; version (1.0A); and encryption method (HMAC-SHA1):
var OAuth = require('OAuth');
var oauth = new OAuth.OAuth(
'https://api.twitter.com/oauth/request_token',
'https://api.twitter.com/oauth/access_token',
twitterKey,
twitterSecret,
'1.0A',
null,
'HMAC-SHA1'
);
After we created the oauth
object using the parameters, we can call aouth.get()
function to fetch a secured resource. The function accepts the URL, user token, user secret (don’t confuse this secret with the Twitter secret), and the callback:
oauth.get(
'https://api.twitter.com/1.1/trends/place.json?id=23424977',
token,
secret,
function (error, data, response){
if (error) console.error(error);
data = JSON.parse(data);
console.log(JSON.stringify(data, 0, 2));
});
Behind the scenes, the get()
function constructs unique values for the request header — Authorization header. The method encrypts the URL, timestamp, application, and other information in a signature, so the same header won’t work for another URL or after a specific time window.
In the callback function, we parse the data
string into a JavaScript object and then print it with indentation using JSON.stringify
parameters. The last argument of the callback, response
, will have the response information with the headers.
The full source code of the oauth1/index.js
:
var twitterKey = 'your Twitter application consumer key',
twitterSecret = 'your Twitter application secret',
token = 'your user token for this app',
//you can get it at dev.twitter.com for your own apps
secret = 'your user secret for this app';
//you can get it at dev.twitter.com for your own apps
var OAuth = require('OAuth');
var oauth = new OAuth.OAuth(
'https://api.twitter.com/oauth/request_token',
'https://api.twitter.com/oauth/access_token',
twitterKey,
twitterSecret,
'1.0A',
null,
'HMAC-SHA1'
);
oauth.get(
'https://api.twitter.com/1.1/trends/place.json?id=23424977',
token,
secret,
function (error, data, response){
if (error) console.error(error);
// data = JSON.parse(data);
// console.log(JSON.stringify(data, 0, 2));
console.log(response);
});
When you run the file with $ node index.js
, you should see the data from the protected Twitter API endpoint, e.g., the top ten trending topics for a given location (WOEID
lookup) via the trends/place
endpoint:
https://api.twitter.com/1.1/trends/place.json?id=23424977
The trends docs are available at https://dev.twitter.com/docs/api/1.1/get/trends/place. The result might look like this:
[
{
"trends": [
{
"name": "#WorldCup",
"query": "%23WorldCup",
"url": "http://twitter.com/search?q=%23WorldCup",
"promoted_content": null
},
{
"name": "Kershaw",
"query": "Kershaw",
"url": "http://twitter.com/search?q=Kershaw",
"promoted_content": null
},
{
"name": "#RE2PECT",
"query": "%23RE2PECT",
"url": "http://twitter.com/search?q=%23RE2PECT",
"promoted_content": null
},
...
{
"name": "Starbucks",
"query": "Starbucks",
"url": "http://twitter.com/search?q=Starbucks",
"promoted_content": null
}
],
"as_of": "2014-07-14T17:45:52Z",
"created_at": "2014-07-14T17:41:24Z",
"locations": [
{
"name": "United States",
"woeid": 23424977
}
]
}
]
Good point. Yes, technically it’s a three-legged OAuth 1.0, but we manually side-step the first two steps (for the ease of presenting). There’s nothing wrong with it. Token and secret are always temporary and can be invalidated. With Twitter API this approach will work after 10 seconds— I tested many times. ;-)
If you read the book (or book’s Table of Contents) the normal three-legged OAuth 1.0 is also covered there.
Searching the web suggests that there is no 1-legged oAuth flow among all versions of oAuth.
Can you link to specification for oAuth 1.0 1-legged flow?
BTW what you’re describing is 3-legged and you’re doing authentication part manually. This is WRONG. Both user token and secret are temporarily data, they’re subject to expiration, invalidation etc and it is NOT guaranteed that your app will be able to use this data ten seconds from now.
I think the concept of three legged vs one legged is not accurately described in the post.
The three legged token is the one that includes information about: User, Developer and Application.
On the other hand a 2-Legged token is one that includes information about Developer and Application, usually those tokens are issued by an API Management Service such as APIGee or Mashery.
The process you are describing is a common developer enrolment process to start using an API.
I hope my comment helps.
Cristian