OAuth ruby examples

From OpenStreetMap Wiki
Jump to navigation Jump to search

As part of the set of OAuth examples, here are some basic examples in ruby, using the ruby OAuth gem. Feel free to improve. Since they are of no use themselves, it doesn't make much sense to run them! If you need any help, please ask away either on dev@openstreetmap.org or contact Gravitystorm

Registering and Authorising your application

#!/usr/bin/ruby

# Get all the auth details you need
# You wouldn't actually do it this way, but hey.
# Normally you'd distribute the consumer stuff with your
# application, and each user gets the access_token stuff
# But hey, this is just a demo.

require 'rubygems'
require 'oauth'
require 'yaml'

# Format of auth.yml:
# consumer_key: (from osm.org)
# consumer_secret: (from osm.org)
# token: (use oauth setup flow to get this)
# token_secret: (use oauth setup flow to get this)
auth={}

puts "First, go register a new application at "
puts "http://api06.dev.openstreetmap.org/oauth_clients/new"
puts "Tick the appropriate boxes"
puts "Enter the consumer key you are assigned:"
auth["consumer_key"] = gets.strip
puts "Enter the consumer secret you are assigned:"
auth["consumer_secret"] = gets.strip
puts "Your application is now set up, but you need to register"
puts "this instance of it with your user account."

@consumer=OAuth::Consumer.new auth["consumer_key"], 
                              auth["consumer_secret"], 
                              {:site=>"http://api06.dev.openstreetmap.org"}

@request_token = @consumer.get_request_token

puts "Visit the following URL, log in if you need to, and authorize the app"
puts @request_token.authorize_url
puts "When you've authorized that token, enter the verifier code you are assigned:"
verifier = gets.strip                                                                                                                                                               
puts "Converting request token into access token..."                                                                                                                                
@access_token=@request_token.get_access_token(:oauth_verifier => verifier)                                                                                                          

auth["token"] = @access_token.token
auth["token_secret"] = @access_token.secret

File.open('auth.yaml', 'w') {|f| YAML.dump(auth, f)}

puts "Done. Have a look at auth.yaml to see what's there."

Making basic HTTP requests

#!/usr/bin/ruby

# Simple OSM Auth example showing GET PUT and DELETE methods
# Requires OAuth rubygem

require 'rubygems'
require 'oauth'
require 'date'
require 'yaml'

# Format of auth.yml:
# consumer_key: (from osm.org)
# consumer_secret: (from osm.org)
# token: (use oauth setup flow to get this)
# token_secret: (use oauth setup flow to get this)
auth = YAML.load(File.open('auth.yaml'))

# The consumer key and consumer secret are the identifiers for this particular application, and are 
# issued when the application is registered with the site. Use your own.
@consumer=OAuth::Consumer.new auth['consumer_key'], 
                              auth['consumer_secret'], 
                              {:site=>"http://api06.dev.openstreetmap.org"}

# Create the access_token for all traffic
@access_token = OAuth::AccessToken.new(@consumer, auth['token'], auth['token_secret']) 

# Use the access token for various commands. Although these take plain strings, other API methods 
# will take XML documents.
@access_token.put('/api/0.6/user/preferences/demo_last_run_time', DateTime.now().to_s, {'Content-Type' => 'text/plain' })
@access_token.put('/api/0.6/user/preferences/deleteme', "This shouldn't be seen", {'Content-Type' => 'text/plain' })
@access_token.delete('/api/0.6/user/preferences/deleteme')
puts @access_token.get('/api/0.6/user/preferences').body

Multipart form uploads

One of the harder things to do is uploading GPX files, since that requires a multipart/form-data POST. The OAuth gem doesn't (appear to) support this, so the request has to be hand-constructed and then signed by the access token. This might change in future versions.

#!/usr/bin/ruby

# hacky script for uploading a file to the OSM GPX api. 
# liberally stolen^Winspired by http://gist.github.com/97756
#
# Format of auth.yml:
# consumer_key: (from osm.org)
# consumer_secret: (from osm.org)
# token: (use oauth setup flow to get this)
# token_secret: (use oauth setup flow to get this)

require 'rubygems'
require 'oauth'
require 'xml/libxml'
require 'date'

CRLF = "\r\n"
endpoint_gpx_create = 'http://api06.dev.openstreetmap.org/api/0.6/gpx/create'

if ARGV.size < 1
  puts "Usage: #{$0} path_to_gpx_file"
  puts "e.g. #{$0} /home/gravitystorm/osm/tracks/20081128.gpx"
  exit(1)
end

# Take GPX file from commandline argument
file = File.new(ARGV[0])

# Format of auth.yml:
# consumer_key: (from osm.org)
# consumer_secret: (from osm.org)
# token: (use oauth setup flow to get this)
# token_secret: (use oauth setup flow to get this)
auth = YAML.load(File.open('auth.yaml'))

@consumer=OAuth::Consumer.new auth['consumer_key'], 
                              auth['consumer_secret'], 
                              {:site=>"http://api06.dev.openstreetmap.org"}

@access_token = OAuth::AccessToken.new(@consumer, auth['token'], auth['token_secret']) 

# Encodes the request as multipart
def add_multipart_data(req,params)
  boundary = Time.now.to_i.to_s(16)
  req["Content-Type"] = "multipart/form-data; boundary=#{boundary}"
  body = ""
  params.each do |key,value|
    esc_key = CGI.escape(key.to_s)
    body << "--#{boundary}#{CRLF}"
    if value.respond_to?(:read)
      body << "Content-Disposition: form-data; name=\"#{esc_key}\"; filename=\"#{File.basename(value.path)}\"#{CRLF}"
      body << "Content-Type: text/xml#{CRLF*2}"
      body << value.read
    else
      body << "Content-Disposition: form-data; name=\"#{esc_key}\"#{CRLF*2}#{value}"
    end
    body << CRLF
  end
  body << "--#{boundary}--#{CRLF*2}"
  req.body = body
  req["Content-Length"] = req.body.size
end
 
# Uses the OAuth gem to add the signed Authorization header
def add_oauth(req)
  @consumer.sign!(req,@access_token)
end
 
#Actually do the request and print out the response
url = URI.parse(endpoint_gpx_create)
Net::HTTP.new(url.host, url.port).start do |http|
  req = Net::HTTP::Post.new(url.request_uri)
  add_multipart_data(req,:file=>file, :tags=>'heheheheh', :description=>'upside down', :public=>'1')
  add_oauth(req)
  res = http.request(req)
  puts res.body
end