简体   繁体   中英

Getting authorization from iNaturalist for API

I'm trying to use iNaturalist's API via Ruby on Rails. I'm new to Ruby and iNaturalist's documentation is pretty sparse. As a first step, I need to figure out how to get authorization from their site.

iNaturalist provides the sample code below. I set up a project with iNaturalist and tried running the sample code in Rails Console with my credentials. #{url} in the following line is replaced with a url that the user is supposed to go to in order to log in to iNat: puts "Go to #{url}, approve the app, and you should be redirected to your " + "redirect_uri. Copy and paste the 'code' param here."

I went to the resulting url and logged in: https://www.inaturalist.org/oauth/authorize?client_id=[my client id]&redirect_uri= https://ruby_on_rails--timrobinson41199691.codeanyapp.com/login/&response_type=code

iNaturalist responds with "The redirect uri included is not valid."

If I leave off &response_type=code, it responds with "The authorization server does not support this response type."

My website is on codeanywhere.com. The url of the main page is " https://ruby_on_rails--timrobinson41199691.codeanyapp.com/ ". Part of the problem is that I don't understand what kind of page I'm supposed to create for redirect_uri, since I'm still kind of new at this.

require 'rubygems'
require 'rest_client'
require 'json'

site = "https://www.inaturalist.org"
app_id = 'YOUR APP ID'
app_secret = 'YOUR APP SECRET'
redirect_uri = 'YOUR APP REDIRECT URI' # you can set this to some URL you control for testing

# REQUEST AN AUTHORIZATION CODE
# Your web app should redirect the user to this url. They should see a screen
# offering them the choice to authorize your app. If they aggree, they will be
# redirected to your redirect_uri with a "code" parameter
url = "#{site}/oauth/authorize?client_id=#{app_id}&redirect_uri=#{redirect_uri}&response_type=code"

# REQUEST AN AUTH TOKEN
# Once your app has that code parameter, you can exchange it for an access token:
puts "Go to #{url}, approve the app, and you should be redirected to your " + 
  "redirect_uri. Copy and paste the 'code' param here."
print "Code: "
auth_code = gets.strip
puts

payload = {
  :client_id => app_id,
  :client_secret => app_secret,
  :code => auth_code,
  :redirect_uri => redirect_uri,
  :grant_type => "authorization_code"
}
puts "POST #{site}/oauth/token, payload: #{payload.inspect}"
puts response = RestClient.post("#{site}/oauth/token", payload)
puts
# response will be a chunk of JSON looking like
# {
#   "access_token":"xxx",
#   "token_type":"bearer",
#   "expires_in":null,
#   "refresh_token":null,
#   "scope":"write"
# }

# Store the token (access_token) in your web app. You can now use it to make authorized
# requests on behalf of the user, like retrieving profile data:
token = JSON.parse(response)["access_token"]
headers = {"Authorization" => "Bearer #{token}"}
puts "GET /users/edit.json, headers: #{headers.inspect}"
puts RestClient.get("#{site}/users/edit.json", headers)
puts

After the user logs in to iNat, he should be redirected back to my website with the authorization code provided in the data. In routes.rb, my login route is set as:

post '/login', to: 'organisms#login'

I've tried using get, as well.

iNat is returned the error mentioned above and not redirecting back to my site.

OAuth can be a bit daunting at first. And that guide really just shows the equivalent of using cURL to test your API.

In an actual application redirect_uri is whatever endpoint in your application that handles the response when the provider redirects back from authorization.

So lets setup a minimal real rails app.

1. Register your app

Register a new application or edit your existing app. Use http://localhost:3000/oauth/inaturalist/callback for the callback url (adjust the host as needed).

Keep the window open as you will need the client_id and secret in a moment.

2. Setup your routes

# /config/routes.rb
Rails.application.routes.draw do
  # just make sure you have a root path defined.
  root to: 'pages#home'
  namespace :oauth do
    namespace :inaturalist, controller: :callbacks do
      # This is just a simple redirect route
      get '/', action: :passthru, as: :authorize
      # This is the route that handles the actual callback
      get 'callback'
    end
  end
end

You can actually do this without the redirect route and just plant a link to the https://www.inaturalist.org/oauth/authorize... url in your view. But having it isolates your application against the craziness that is OAuth and its how OmniAuth does it.

3. Add your credentials to the Rails app.

In Rails 5 use the encrypted credentials to store your client_id and secret.

Run $ bin/rails credentials:edit from your shell.

inaturalist:
  client_id: <from the inaturalist site>
  secret: <from the inaturalist site>

In earlier versions use ENV vars instead.

4. Install the oauth2 gem

# Place this in your gemfile outside any groups
gem 'oauth2', '~> 1.4', '>= 1.4.1'

Then run bundle install .

4. Setup the controller

# app/controllers/oauth/inaturalist/callbacks_controller.rb
require 'oauth2'

module Oauth
  module Inaturalist
    class CallbacksController < ::ActionController::Base

      # GET /oauth/inaturalist
      def passthru
        redirect_to client.auth_code.authorize_url
      end

      # This endpoint is where the provider redirects the user back to 
      # after authorization.
      # GET /oauth/inaturalist/callback
      def callback
        # Fetch an auth token from the access code
        token = client.auth_code.get_token(params[:code])
        # Perform an authenticated request to get the users data
        api_response = token.get("/users/edit.json")
        @user_data = JSON.parse(api_response.body)
        # This is just an example of how you can use the user data from
        # the provider
        @user = {
          uid: @user_data["id"],
          nickname: @user_data["nickname"]
        }
        session[:user_id] = @user[:uid]
        session[:token] = token.to_hash
        redirect_to root_path, success: "Hello #{@user[:nickname]}"
      end

      private
      # Change this if you are not using Rails 5 credentials.
      def client
        OAuth2::Client.new(
          credentials.fetch(:client_id),
          credentials.fetch(:secret),
          site: "https://www.inaturalist.org",
          redirect_uri: oauth_inaturalist_callback_url
        )
      end
      def credentials
        Rails.application.credentials.fetch(:inaturalist)
      end
    end
  end
end

token here is actually a new OAuth2::AccessToken instance that can be called to call endpoints with the fetched credentials.

This example stores the token in the session. You can retrieve it in subsequent requests with:

token = OAuth2::AccessToken.from_hash( session[:token] )

The docs kind of mention trading the oauth access token for an api token for api.inaturalist.org . But the details are kind of sparse.

5 Add a link to sign in:

<%= link_to 'Sign in to iNaturalist.org', oauth_inaturalist_authorize_path %>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM