OAuth 1.0a

const createOAuth1Client = require('@arangodb/foxx/oauth1');

The OAuth1 module provides abstractions over OAuth 1.0a providers likeTwitter, XING and Tumblr.

Examples

  1. const router = createRouter();
  2. const oauth1 = createOAuth1Client({
  3. // We'll use Twitter for this example
  4. requestTokenEndpoint: 'https://api.twitter.com/oauth/request_token',
  5. authEndpoint: 'https://api.twitter.com/oauth/authorize',
  6. accessTokenEndpoint: 'https://api.twitter.com/oauth/access_token',
  7. activeUserEndpoint: 'https://api.twitter.com/1.1/account/verify_credentials.json',
  8. clientId: 'keyboardcat',
  9. clientSecret: 'keyboardcat'
  10. });
  11. module.context.use('/oauth1', router);
  12. // See the user management example for setting up the
  13. // sessions and users objects used in this example
  14. router.use(sessions);
  15. router.post('/auth', function (req, res) {
  16. const url = req.reverse('oauth1_callback');
  17. const oauth_callback = req.makeAbsolute(url);
  18. const requestToken = oauth1.fetchRequestToken(oauth_callback);
  19. if (requestToken.oauth_callback_confirmed !== 'true') {
  20. res.throw(500, 'Could not fetch OAuth request token');
  21. }
  22. // Set request token cookie for five minutes
  23. res.cookie('oauth1_request_token', requestToken.oauth_token, {ttl: 60 * 5});
  24. // Redirect to the provider's authorization URL
  25. res.redirect(303, oauth1.getAuthUrl(requestToken.oauth_token));
  26. });
  27. router.get('/auth', function (req, res) {
  28. // Make sure CSRF cookie matches the URL
  29. const expectedToken = req.cookie('oauth1_request_token');
  30. if (!expectedToken || req.queryParams.oauth_token !== expectedToken) {
  31. res.throw(400, 'CSRF mismatch.');
  32. }
  33. const authData = oauth1.exchangeRequestToken(
  34. req.queryParams.oauth_token,
  35. req.queryParams.oauth_verifier
  36. );
  37. const twitterToken = authData.oauth_token;
  38. const twitterSecret = authData.oauth_token_secret;
  39. // Fetch the active user's profile info
  40. const profile = oauth1.fetchActiveUser(twitterToken, twitterSecret);
  41. const twitterId = profile.screen_name;
  42. // Try to find an existing user with the user ID
  43. // (this requires the users collection)
  44. let user = users.firstExample({twitterId});
  45. if (user) {
  46. // Update the twitterToken if it has changed
  47. if (
  48. user.twitterToken !== twitterToken ||
  49. user.twitterSecret !== twitterSecret
  50. ) {
  51. users.update(user, {twitterToken, twitterSecret});
  52. }
  53. } else {
  54. // Create a new user document
  55. user = {
  56. username: `twitter:${twitterId}`,
  57. twitterId,
  58. twitterToken
  59. }
  60. const meta = users.save(user);
  61. Object.assign(user, meta);
  62. }
  63. // Log the user in (this requires the session middleware)
  64. req.session.uid = user._key;
  65. req.session.twitterToken = authData.twitterToken;
  66. req.session.twitterSecret = authData.twitterSecret;
  67. req.sessionStorage.save(req.session);
  68. // Redirect to the default route
  69. res.redirect(303, req.makeAbsolute('/'));
  70. }, 'oauth1_callback')
  71. .queryParam('oauth_token', joi.string().optional())
  72. .queryParam('oauth_verifier', joi.string().optional());

Creating an OAuth1.0a client

createOAuth1Client(options): OAuth1Client

Creates an OAuth1.0a client.

Arguments

  • options: Object

An object with the following properties:

  • requestTokenEndpoint: string

The fully-qualified URL of the provider’sTemporary Credentials Request endpoint.This URL is used to fetch the unauthenticated temporary credentials thatwill be used to generate the authorization redirect for the user.

  • authEndpoint: string

The fully-qualified URL of the provider’sResource Owner Authorization endpoint.This is the URL the user will be redirected to in order to authorize theOAuth consumer (i.e. your service).

  • accessTokenEndpoint: string

The fully-qualified URL of the provider’sToken Request endpoint.This URL is used to exchange the authenticated temporary credentialsreceived from the authorization redirect for the actual token credentialsthat can be used to make requests to the API server.

  • activeUserEndpoint: string (optional)

The fully-qualified URL of the provider’s endpoint for fetching detailsabout the current user.

  • clientId: string

The application’s Client ID (or Consumer Key) for the provider.

  • clientSecret: string

The application’s Client Secret (or Consumer Secret) for the provider.

  • signatureMethod: string (Default: "HMAC-SHA1")

The cryptographic method that will be used to sign OAuth 1.0a requests.Only "HMAC-SHA1-" and "PLAINTEXT" are supported at this time.

Note that many providers may not implement "PLAINTEXT" as it exposes theClient Secret and oauth_token_secret instead of generating a signature.

Returns an OAuth 1.0a client for the given provider.

Setting up OAuth 1.0a for Twitter

If you want to use Twitter as the OAuth 1.0a provider, use the following options:

You also need to obtain a client ID and client secret from Twitter:

  • Create a regular account at Twitter or use anexisting account you own.
  • Visit the Twitter Application Managementdashboard and sign in with your Twitter account.
  • Click on Create New App and follow the instructions provided.The Callback URL should match your oauth_callback later. You may beprompted to add a mobile phone number to your account and verify it.
  • Open the Keys and Access Tones tab, then note down the Consumer Key_and _Consumer Secret.
  • Set the option clientId to the Consumer Key and the optionclientSecret to the Consumer Secret.Note that if you only need read-only access to public information, you can alsouse the clientId and clientSecret directlywithout OAuth 1.0a.

See Twitter REST API Reference Documentation.

Setting up OAuth 1.0a for XING

If you want to use XING as the OAuth 1.0a provider, use the following options:

You also need to obtain a client ID and client secret from XING:

  • Create a regular account at XING or use an existingaccount you own.
  • Visit the XING Developer page and sign in withyour XING account.
  • Click on Create app and note down the Consumer key and Consumer secret.
  • Set the option clientId to the Consumer key and the optionclientSecret to the Consumer secret.See XING Developer Documentation.

Setting up OAuth 1.0a for Tumblr

If you want to use Tumblr as the OAuth 1.0a provider, use the following options:

You also need to obtain a client ID and client secret from Tumblr:

  • Create a regular account at Tumblr or use anexisting account you own.
  • Visit the Tumblr Applications dashboard.
  • Click on Register application, then follow the instructions provided.The Default callback URL should match your oauth_callback later.
  • Note down the OAuth Consumer Key and Secret Key. The secret may behidden by default.
  • Set the option clientId to the OAuth Consumer Key and the optionclientSecret to the Secret Key.See Tumblr API Documentation.

Fetch an unauthenticated request token

oauth1.fetchRequestToken(oauth_callback, opts)

Fetches an oauth_token that can be used to create an authorization URL thatredirects to the given oauth_callback on confirmation.

Performs a POST response to the requestTokenEndpoint.

Throws an exception if the remote server responds with an empty response body.

Arguments

  • oauth_callback: string

The fully-qualified URL of your application’s OAuth 1.0a callback.

  • opts: Object (optional)

An object with additional query parameters to include in the request.

See RFC 5849.

Returns the parsed response object.

Get the authorization URL

oauth1.getAuthUrl(oauth_token, opts): string

Generates the authorization URL for the authorization endpoint.

Arguments

  • oauth_token: string

The oauth_token previously returned by fetchRequestToken.

  • opts: (optional)

An object with additional query parameters to add to the URL.

See RFC 5849.

Returns a fully-qualified URL for the authorization endpoint of the providerby appending the oauthtoken and any additional arguments from _opts tothe authEndpoint.

Examples

  1. const requestToken = oauth1.fetchRequestToken(oauth_callback);
  2. if (requestToken.oauth_callback_confirmed !== 'true') {
  3. throw new Error('Provider could not confirm OAuth 1.0 callback');
  4. }
  5. const authUrl = oauth1.getAuthUrl(requestToken.oauth_token);

Exchange an authenticated request token for an access token

oauth1.exchangeRequestToken(oauth_token, oauth_verifier, opts)

Takes a pair of authenticated temporary credentials passed to the callback URLby the provider and exchanges it for an oauth_token and oauth_token_secretthan can be used to perform authenticated requests to the OAuth 1.0a provider.

Performs a POST response to the accessTokenEndpoint.

Throws an exception if the remote server responds with an empty response body.

Arguments

  • oauth_token: string

The oauth_token passed to the callback URL by the provider.

  • oauth_verifier: string

The oauth_verifier passed to the callback URL by the provider.

  • opts: Object (optional)

An object with additional query parameters to include in the request.

See RFC 5849.

Returns the parsed response object.

Fetch the active user

oauth1.fetchActiveUser(oauth_token, oauth_token_secret, opts): Object

Fetches details of the active user.

Performs a GET response to the activeUserEndpoint.

Throws an exception if the remote server responds with an empty response body.

Returns null if the activeUserEndpoint is not configured.

Arguments

  • oauth_token: string

An OAuth 1.0a access token as returned by exchangeRequestToken.

  • oauth_token_secret: string

An OAuth 1.0a access token secret as returned by exchangeRequestToken.

  • opts: Object (optional)

An object with additional query parameters to include in the request.

See RFC 5849.

Returns the parsed response object.

Examples

  1. const authData = oauth1.exchangeRequestToken(oauth_token, oauth_verifier);
  2. const userData = oauth1.fetchActiveUser(authData.oauth_token, authData.oauth_token_secret);

Create an authenticated request object

oauth1.createSignedRequest(method, url, parameters, oauth_token, oauth_token_secret)

Creates a request object that can be used to perform a request to the OAuth 1.0aprovider with the provided token credentials.

Arguments

  • method: string

HTTP method the request will use, e.g. "POST".

  • url: string

The fully-qualified URL of the provider the request will be performed against.

The URL may optionally contain any number of query parameters.

  • parameters: string | Object | null

An additional object or query string containing query parameters or bodyparameters that will be part of the signed request.

  • oauth_token: string

An OAuth 1.0a access token as returned by exchangeRequestToken.

  • oauth_token_secret: string

An OAuth 1.0a access token secret as returned by exchangeRequestToken.

Returns an object with three properties:

  • url: The normalized URL without any query parameters.

  • qs: A normalized query string containing all parameters and query parameters.

  • headers: An object containing the following properties:

    • accept: The string "application/json".

    • authorization: An OAuth authorization header containing all OAuthparameters and the request signature.

Examples

Fetch a list of tweets mentioning @arangodb:

  1. const request = require('@arangodb/request');
  2. const req = oauth1.createSignedRequest(
  3. 'GET',
  4. 'https://api.twitter.com/1.1/search/tweets.json',
  5. {q: '@arangodb'},
  6. authData.oauth_token,
  7. authData.oauth_token_secret
  8. );
  9. const res = request(req);
  10. console.log(res.json.statuses);

Signing a more complex request:

  1. const url = 'https://api.example.com/v1/timeline?visible=public';
  2. const params = {hello: 'world', longcat: 'is long'};
  3. const req = oauth1.createSignedRequest(
  4. 'POST',
  5. url, // URL includes a query parameter that will be signed
  6. params, // Request body needs to be signed too
  7. authData.oauth_token,
  8. authData.oauth_token_secret
  9. );
  10. const res = request.post(url, {
  11. form: params,
  12. headers: {
  13. accept: 'application/x-www-form-urlencoded',
  14. // Authorization header includes the signature
  15. authorization: req.headers.authorization
  16. }
  17. });
  18. console.log(res.json);