HTTParty giving 401 using http basic authentication - ruby-on-rails

I have two applications. One contains an API (Rails) and the second (Sinatra) is a test application to check if the API is working correctly.
In the test application I can get all of the information provided by my API using HTTParty. However, when I try to add http basic authentication in the API application,
the test application always gets a 401 error.
In the controller which provides the API I have written
http_basic_authenticate_with name: "admin", password: "admin"
In my test application I have written
authenticate = {name: "admin", password: "admin"}
options = {query: {username: params[:username], email: params[:email]},
basic_auth: authenticate}
response = HTTParty.get('http://localhost:3000/search.json', options)
What am I doing wrong?

Your key for the username is incorrect:
authenticate = {:username => 'admin', :password => 'admin'}
This should work

Related

Newsletter2go ruby API client authorisation with get_token method

Good day!
Can you please give me an example of authentication request with ruby newsletetr2go API client.
I can't figure it out.
I can connect to API using direct requests like RestClient.post "#{link}/oauth/v2/token", credentials, default_header
In credentials I use my username, password and grant_type, converted to json format
In default header I use content_type: 'application/json' and authorization: "Basic #{Base64.strict_encode64(ENV['NEWSLETTER2GO_AUTH_KEY'])}"
And it works fine. But when I try to use newsletter2go get_token method all I receive is "BAD REQUEST" error.
I'm using initializer to configure SwaggerClient like this:
SwaggerClient.configure do |config|
# Configure OAuth2 access token for authorization: OAuth
config.password = ENV['NEWSLETTER2GO_PASSWORD']
config.username = ENV['NEWSLETTER2GO_USERNAME']
config.api_key = ENV['NEWSLETTER2GO_AUTH_KEY']
end
After that I use newsletter2go api method call
SwaggerClient::AuthorizationApi.new.get_token("https://nl2go.com/jwt")
Seems everything is correct, but error "BAD REQUEST" happens all the time.
I followed the instructions, install swagger_client with ruby extentions in github, and newsletter2go methods are now available from my rails environment.
If I grab access_token manually and add it to my initializer, then do some requests like SwaggerClient::ListApi.new.get_lists it gives me a proper response with status 200 and list_ids
But SwaggerClient::AuthorizationApi.new.get_token("https://nl2go.com/jwt") does not work and this is the issue.
Any help would be very appreciated!
I figured out the reason why Newsletter2Go API ruby client does not grab api_key value. For some reason it's hardcoded to setup basic auth token which stands from username and password packed.
Here is code from
module SwaggerClient
class Configuration
# Gets Basic Auth token string
def basic_auth_token
'Basic ' + ["#{username}:#{password}"].pack('m').delete("\r\n")
end
# Returns Auth Settings hash for api client.
def auth_settings
{
'OAuth' =>
{
type: 'oauth2',
in: 'header',
key: 'Authorization',
value: "Bearer #{access_token}"
},
'Basic' =>
{
type: 'basic',
in: 'header',
key: 'Authorization',
value: basic_auth_token
},
}
end

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 %>

Integrating Rails 4, timekit api, rest-client and Devise

I am a newbie Rails 4 developer and need some help adding an API to my simple application using rest-client. For simplification, I will just ask about the API's authentication system.
I have a simple app which uses the Devise gem for authentication. I would like for every user that creates an account to have a calendar for scheduling and booking purposes. to achieve this I am using an API called timekit (http://timekit.io/). Their authentication system responds the to following cURL code example:
curl -X POST \
-H 'Timekit-App: docs' \
-d '{
"email": "doc.brown#timekit.io",
"password": "DeLorean"
}' \
https://api.timekit.io/v2/auth
This will then return the following JSON:
{
"data": {
"activated": true,
"email": "doc.brown#timekit.io",
"first_name": "Dr. Emmett",
"img": "http://www.gravatar.com/avatar/7a613e5348d63476276935025",
"last_name": "Brown",
"last_sync": null,
"name": "Dr. Emmett Brown",
"timezone": "America/Los_Angeles",
"token": "UZpl3v3PTP1PRwqIrU0DSVpbJkNKl5gN",
"token_generated_at": null,
"api_token": "FluxCapacitator", // note that this is usually a randomized string and not an actual word
}
}
So now my questions are the following:
1) Where in the Rails framework do I implement this?
2) How do I do so using rest-client instead of cURL?
3) How do I integrate this with Devise?
4)What are good resources to enhance my own understanding of what I am actually doing here?
Awesome to see your using Timekit (I'm one of the core devs) :)
We don't currently have a ruby gem and I'm not a Ruby developer, but here's a quick code example on how to accomplish this with the HTTParty library:
# Global configs for "admin" user
TK_ADMIN_USER = 'my-email#gmail.com'
TK_ADMIN_TOKEN = '12345ABCD'
# Example usage:
# timekit = Timekit.new(TK_ADMIN_USER, TK_ADMIN_TOKEN)
# tk_user = timekit.create_user(account)
# someInternalUser.update(tk_token: tk_user.token)
class Timekit
include HTTParty
base_uri 'https://api.timekit.io'
headers 'Timekit-App' => 'your-app-name'
def initialize(user, password)
#auth = {username: user, password: password}
end
def create_user(account)
options = {
body: {
"email" => account.email,
"first_name" => account.first_name,
"last_name" => account.last_name,
"timezone" => "America/Los_Angeles"
}.to_json,
basic_auth: #auth,
}
self.class.post('/v2/users/', options)
end
def create_calendar(account)
options = {
body: {
name: "Bookings",
description: "Hold bookings for clients."
}.to_json,
basic_auth: #auth
}
self.class.post('/v2/calendars', options)
end
end
https://gist.github.com/laander/83cb7f5dde1f933173c7
In general, the idea is to create a user through our API (you can do it transparently whenever a user signs up in your onboarding) and then save the API Token that the API returns. After that, you can perform API calls impersonating that users (fetch calendars, create events, query availability etc)
Just write us in the chat on timekit.io if you need more hands-on help!
You might consider creating a small library to wrap interactions with the Timekit web API in the /lib directory of your project. I didn't see a gem for this web API, so you might consider extracting this logic into one so the community can benefit.
The rest-client gem appears pretty easy to use:
auth_hash = {
"email" => "doc.brown#timekit.io",
"password" => "DeLorean"
}
RestClient.post "https://api.timekit.io/v2/auth", auth_hash.to_json, content_type: :json, accept: :json
If you are creating a new Timekit account for each user, you might consider adding the credential to the User model or another related model that stores the credential.

Can I send requests to app with devise without credentials?

I have backend app with devise and a ionic app from which I make requests to backend.
Whenever I send requests, gets me 401 status unauthorized.
In this project I've already doorkeeper to manage authorization, so I don't rly need authorization from devise. Can I somehow make these requests( add something to headers ) always authorized without sending post request with credentials?
You need to identify the user somehow. If you're not using a session, you'll need to generate some kind of access token, which Doorkeeper can do for you. I'm not sure if this is helpful or not, but I set up the following flow recently.
One option when using OAuth2 through a trusted client, e.g. a front-end app you build/distribute yourself, is the Resource Owner Password Credentials Grant. Doorkeeper has a guide in the docs for this with advice on dealing with Devise.
I ended up with something like this in my Doorkeeper initializer. You don't need to authorize the client, because you trust it:
resource_owner_from_credentials do |routes|
request.params[:user] = {:email => request.params[:email], :password => request.params[:password]}
request.env['devise.allow_params_authentication'] = true
request.env['warden'].authenticate!(:scope => :user)
end
skip_authorization do |resource_owner|
true
end
Then you should be able to send a request using the password grant type as follows (also shown in the docs).
RestClient.post 'http://localhost:3000/oauth/token', {grant_type: 'password', email: 'email#gmail.com', password: 'password'}, {:accept => 'application/json'}
You should receive the same JSON back as shown in the docs.
{
"access_token": "1f0af717251950dbd4d73154fdf0a474a5c5119adad999683f5b450c460726aa",
"token_type": "bearer",
"expires_in": 7200
}
Now you have a way of identifying your user. You just attach this token to each request to endpoints protected by doorkeeper_for.
RestClient.get 'http://localhost/api/v1/users', { 'Authorization' => 'Bearer 1f0af717251950dbd4d73154fdf0a474a5c5119adad999683f5b450c460726aa', :accept => 'application/json'}

Ruby and Twitter: Getting Access Token from Request Token?

I am currently in Step 3 of the processing on getting an oauth token/secret from an user trying to login via Twitter. https://dev.twitter.com/docs/auth/implementing-sign-twitter
Step 3 tells me to send this request to the API, but I am stuck as to how to do so. I currently have BOTH the oauth_token and oauth_verifier, but how do I send this POST request to get the oauth_token, oauth_token_secret pair?
Is there a standard Oauth Ruby gem I can use to send this POST request? I see examples online where I pass an #accessToken object, but i do not have such an object available. I just have the oauth_token and oauth_verifier (as strings). Given these 2 things, how do I convert them to an oauth_token and oauth_token_secret?
POST /oauth/access_token HTTP/1.1
User-Agent: themattharris' HTTP Client
Host: api.twitter.com
Accept: */*
Authorization: OAuth oauth_consumer_key="cChZNFj6T5R0TigYB9yd1w",
oauth_nonce="a9900fe68e2573b27a37f10fbad6a755",
oauth_signature="39cipBtIOHEEnybAR4sATQTpl2I%3D",
oauth_signature_method="HMAC-SHA1",
oauth_timestamp="1318467427",
oauth_token="NPcudxy0yU5T3tBzho7iCotZ3cnetKwcTIRlX0iwRl0",
oauth_version="1.0"
Content-Length: 57
Content-Type: application/x-www-form-urlencoded
oauth_verifier=uw7NjWHT6OJ1MpJOXsHfNxoAhPKpgI8BlYDhxEjIBY
Try something like the following rails controller actions, using the twitter and oauth gems:
def redirect
consumer = OAuth::Consumer.new(CONSUMER_KEY, CONSUMER_SECRET, {
:site => "https://api.twitter.com",
:scheme => :header
})
request_token = consumer.get_request_token(:oauth_callback => CALLBACK_URL)
session[:twitter_request_token] = request_token
redirect_to request_token.authorize_url #=> "https://api.twitter.com/oauth/authorize?oauth_token=XYZ"
end
def callback
request_token = session[:twitter_request_token]
access_token = request_token.get_access_token(:oauth_verifier => params[:oauth_verifier])
client = Twitter::REST::Client.new(
:consumer_key => CONSUMER_KEY,
:consumer_secret => CONSUMER_SECRET,
:access_token => access_token.token,
:access_token_secret => access_token.secret
)
twitter_user = client.user
redirect_to root_url # or do something with the twitter_user
end
See also: http://barkingiguana.com/2009/10/13/twitter-oauth-authentication-using-ruby/
yes there is the Omniauth gem for authentication with Twitter. The documentation is straight forward.
I personally use Omniauth integrated with Devise and the Twitter gem to access Twitter - works very well.
Hope this helps,
Eugen
The common procedure is the following:
You shell to register your app on twitter development page.
Then set the proper Name, Description, and Website values up for your application.
App Name
App Description
http://your_app_domain.zone:3000/
Change Application Type is your app, by default it has read only access type.
Setup the callback URL for yuor application:
http://your_app_domain.zone:3000/auth/twitter/callback
Store the all keys, and secrets that are shewn on the OAuth tool twitter page:
Consumer key:
Consumer secret:
Access token:
Access token secret:
Setup route on your site with devise, or devise-like gem with the specified twitter keys, and secrets to enable authentication engine. The route list now shall include /auth/twitter path.
By going to http://your_app_domain.zone:3000/auth/twitter you will be redirected to twitter site, and dropped back to your site with passed oauth_token
But
You simple receive those keys, and secrets, and apply then in your app, avoiding the 6, and 7 points:
client = Twitter::REST::Client.new do |config|
config.consumer_key = "YOUR_CONSUMER_KEY"
config.consumer_secret = "YOUR_CONSUMER_SECRET"
config.access_token = "YOUR_ACCESS_TOKEN"
config.access_token_secret = "YOUR_ACCESS_SECRET"
end

Resources