OAuth in a command line script

08/05/2015

Many APIs today use OAuth. If you want to use an OAuth API from the command line, then what I recommend is starting a web server locally to handle the OAuth callback. Here’s a quick and dirty example of doing that in Python.

#!/usr/bin/env python

from flask import Flask,redirect, request
import json
import logging
import threading
import time
from urlparse import urlparse
import urllib
import urllib2
import webbrowser

CLIENT_ID = 'xxxx'
CLIENT_SECRET = 'yyyyyyyy'

SCOPE = 'repo:read'
AUTH_URL = 'https://quay.io/oauth/authorize'
IMAGES_URL = 'https://quay.io/api/v1/repository/myorg/myrepo/image/'

oauth_access_token = None

app = Flask(__name__)

@app.route('/oauth_request_token')
def oauth_request_token():
  url = 'https://quay.io/oauth/authorize?response_type=token&redirect_uri=' + urllib.quote('http://localhost:7777/oauth_callback') + '&realm=realm&client_id=' + urllib.quote(CLIENT_ID) + '&scope=' + urllib.quote(SCOPE)
  print 'Redirecting to ' + url
  return redirect(url)

@app.route('/oauth_callback')
def oauth_callback():
  result = """
  <script>
    getHashParams = function() {
      var hashParams = {};
      var e,
        a = /\+/g,  // Regex for replacing addition symbol with a space
        r = /([^&;=]+)=?([^&;]*)/g,
        d = function (s) { return decodeURIComponent(s.replace(a, " ")); },
        q = window.location.hash.substring(1);

      while (e = r.exec(q))
        hashParams[d(e[1])] = d(e[2]);
      return hashParams;
    };
    
    ajax = function(url, callback, data) {
      try {
        var x = new(this.XMLHttpRequest || ActiveXObject)('MSXML2.XMLHTTP.3.0');
        x.open(data ? 'POST' : 'GET', url, 1);
        x.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
        x.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
        x.onreadystatechange = function () {
            x.readyState > 3 && callback && callback(x.responseText, x);
        };
        x.send(data)
      } catch (e) {
        window.console && console.log(e);
      }
    };

    hashParams = getHashParams();
    ajax('/receive_token', function() { window.close(); }, 'access_token=' + hashParams['access_token']);
  </script>
  """
  return result

@app.route('/receive_token', methods=['POST'])
def receive_token():
  global oauth_access_token
  oauth_access_token = request.form['access_token']
  return '{}'

class ServerThread(threading.Thread):

  def __init__(self):
    threading.Thread.__init__(self)

  def run(self):
    app.run(
      port=7777,
      host='localhost'
    )

if '__main__'==__name__:
  logging.getLogger().addHandler(logging.StreamHandler())

  thread = ServerThread()
  thread.daemon = True
  thread.start()

  webbrowser.open('http://localhost:7777/oauth_request_token')

  while oauth_access_token is None:
    time.sleep(0.2)

  print 'Retreived auth code ' + oauth_access_token

  opener = urllib2.build_opener()
  opener.addheaders = [('Authorization', 'Bearer ' + oauth_access_token)]
  images = opener.open(IMAGES_URL)
  print images.read()
Be Sociable, Share!