google drive ruby api login with oauth2, what is "authorization code" - ruby

I try to use login_with_oauth2 with google_drive, but I can't understand what is authorization code in #google_drive.rb doc
client = OAuth2::Client.new(
"522807807986-gjotv2np4tdqp4do8sq0gds0p2bqugtf.apps.googleusercontent.com",
'fmWlfzejvx_UtS3CKq2Sl-WQ',
:site => "https://accounts.google.com",
:token_url => "/o/oauth2/token",
:authorize_url => "/o/oauth2/auth"
)
auth_url = client.auth_code.authorize_url(
:redirect_uri => "urn:ietf:wg:oauth:2.0:oob
http://localhost"
)
# Redirect the user to auth_url and get authorization code from redirect URL.
authorization_code = ''
auth_token = client.auth_code.get_token(
authorization_code, :redirect_uri => "urn:ietf:wg:oauth:2.0:oob
http://localhost")
session = GoogleDrive.login_with_oauth(auth_token.token, 'http://localhost:8087')

OAuth2 is the two-steps authorization mechanism. AFAIU, you have your code simply copy-pasted from official documentation, but unfortunately that’s not a working code. It’s just an example. Take a look at the comment marked red there: it’s very important:
# Redirect the user to auth_url and get authorization code from redirect URL.
You are to specify the correct pingback URI for Google server to send the response with your authorization_code (now there states localhost, which is problematically for Google to understand your IP to send you feedback.)
The summing up: you provide Google with credentials, it replies with JSON, containing your authorization_code to the address you specified. After this phase is successfully completed, you may proceed requesting auth_token.

Related

Ruby Oauth2 Signet Return token with refresh token

I am accessing gmail api. I am using ruby to get the access token. However, I need to get a refresh token with the access token. I am using signet as suggested here.
https://readysteadycode.com/howto-access-the-gmail-api-with-ruby
The code looks like this
client = Signet::OAuth2::Client.new({
client_id: ENV.fetch('GOOGLE_API_CLIENT_ID'),
client_secret: ENV.fetch('GOOGLE_API_CLIENT_SECRET'),
token_credential_uri: 'https://accounts.google.com/o/oauth2/token',
redirect_uri: url_for(:action => :callback),
code: params[:code]
})
// this is undefined
refre_token = client.refresh_token
response = client.fetch_access_token!
access_token = response['access_token']
I tried adding additional parameters like this as suggested here
additional_parameters: {
"access_type" => "offline", # offline access
"include_granted_scopes" => "true", # incremental auth
}
to the client.new call but did not seem to have any effect.
How do I get the refresh token from Signet::OAuth2?
The refresh token will only appear the first time you are authenticated.
Follow these steps to remove the stored access so you can be authenticated like the first time.
Manage your google account -> Security -> Manage 3rd party access -> your app name -> remove access
Note: From my testing, it does not appear that the additional parameters property is necessary.

opt_fields not working with Asana API but url works in the Asana explorer

I'm using Ruby starting from the "hello world" example. Hello world works find. I'm trying to get this GET to work:
GET /projects/192372431230306/tasks?opt_fields=id,assignee,due_on,name,notes&limit=10&completed_since=now
It works exactly as expected in the Asana API explorer.
I'm using the same URI in my code:
uri = URI.parse("https://app.asana.com/api/1.0/projects/192372431230306/tasks?opt_fields=id,assignee,due_on,name,notes&limit=10&completed_since=now")
It still returns ID and Name correctly, but it's not what I want.
I can't see why it works in the explorer but not in the GET request. I am using the personal token and the explorer uses OAuth.
My personal token is set correctly before this code. I can create tasks, get projects, get tasks. I just can't more fields in this query like the API explorer.
Added Code:
uri = URI.parse("https://app.asana.com/api/1.0/projects/192372431230306/tasks?opt_fields=id,assignee,due_on,name,notes&limit=10&completed_since=now")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
# set up the request
header = {
"Content-Type" => "application/json"
}
req = Net::HTTP::Get.new(uri.path, header)
req.basic_auth(personal_access_token, '')
res = http.start { |http| http.request(req) }
body = JSON.parse(res.body)
puts "projects: #{body['data']}"
There isn't quite enough code here to know what's wrong. It sounds like your code is working to some degree, but maybe there's something different between using a personal token as opposed to OAuth. According to the Asana API documentation:
Personal Access Tokens should be used similarly to OAuth access tokens when accessing the API, passing them in the Authorization header:
curl -H "Authorization: Bearer ACCESS_TOKEN" https://app.asana.com/api/1.0/users/me
So in addition to the URL, you need to use the correct headers. I'm not sure what HTTP library you use, but here's how I would do it with HTTParty:
require 'uri'
require 'httparty'
uri = URI.parse("https://app.asana.com/api/1.0/projects/192372431230306/tasks?opt_fields=id,assignee,due_on,name,notes&limit=10&completed_since=now")
task = HTTParty.get(uri,
:headers =>
{'Authorization' => "Bearer ${ENV[ACCESS_TOKEN]}"}
).parsed_response
If you put your personal access token in the ACCESS_TOKEN environment variable, that should correctly authenticate you for the request.
Still, it seems like there's something else missing if you can get all the fields. Maybe your personal access token is associated with a different account than your OAuth access token? It might help to check the results of /users/me/ route?

Accessing Google Calendar using Oauth via Ruby Sinatra app

I'm building a Slack bot, with a backend Sinatra app. The function of the bot is to add and read entries from Google Calendar.
I'm using session and environment variables.
I'm unable to open up the authorization webpage for Oauth and get access to user's Calendar data. Please help!
Here's my code:
#The redirect_url entered in Google Console.
#Google Oauth redirects to this endpoint once user has authorised request.
get '/oauthcallback' do
client = Signet::OAuth2::Client.new({
client_id: ENV['CALENDAR_CLIENT_ID'],
client_secret: ENV['CALENDAR_CLIENT_SECRET'],
authorization_uri: 'https://accounts.google.com/o/oauth2/auth',
redirect_uri: "https://agile-stream-68169.herokuapp.com/oauthcallback",
code: params[:code]
})
response = client.fetch_access_token!
session[:access_token] = response['access_token']
redirect url_for(:action => :calendars)
end
#The Authorization url which checks if credentials are valid.
get '/authorize' do
# NOTE: Assumes the user is already authenticated to the app
user_id = request.session['user_id']
credentials = authorizer.get_credentials(user_id, request)
if credentials.nil?
redirect authorizer.get_authorization_url(login_hint: user_id, request: request)
end
end
#METHOD: Initialising the API by creating a Calendar Service
def intialize_api
$service = Google::Apis::CalendarV3::CalendarService.new
$service.client_options.application_name = ENV['CALENDAR_APPLICATION_NAME']
$service.authorization = auth_calendar
end
def auth_calendar
client = Signet::OAuth2::Client.new({
client_id: ENV['CALENDAR_CLIENT_ID'],
client_secret: ENV['CALENDAR_CLIENT_SECRET'],
authorization_uri: 'https://accounts.google.com/o/oauth2/auth',
scope: Google::Apis::CalendarV3::AUTH_CALENDAR_READONLY,
redirect_uri: "https://agile-stream-68169.herokuapp.com/oauthcallback"
})
redirect client.authorization_uri.to_s
end

Offline access to google contacts using the oauth2 ruby gem

I'm trying to get offline access to google contacts using the oauth2 ruby Gem (https://github.com/intridea/oauth2). My current code is:
#!/usr/bin/env ruby
require 'oauth2'
require 'yaml'
require 'pp'
auth = YAML.load_file('.auth.yml')
client_id = auth['google']['clientid']
client_secret = auth['google']['secret']
redirect = 'urn:ietf:wg:oauth:2.0:oob'
code = ARGV[0]
token = nil
client = OAuth2::Client.new(client_id, client_secret, site: 'https://accounts.google.com', token_url: '/o/oauth2/token', authorize_url: '/o/oauth2/auth')
if code
token = client.auth_code.get_token(code, :redirect_uri => redirect)
auth['google']['token'] = token.to_hash
open('.auth.yml', 'w'){|f| f.write(auth.to_yaml)}
elsif auth['google']['token']
token = OAuth2::AccessToken.from_hash(client, auth['google']['token'])
token.refresh! if token.expired?
auth['google']['token'] = token.to_hash
open('.auth.yml', 'w'){|f| f.write(auth.to_yaml)}
else
puts client.auth_code.authorize_url(scope: 'https://www.google.com/m8/feeds', redirect_uri: redirect, access_type: :offline)
end
pp token.expired? if token
I can use this to get an access token, valid for one hour, and I do see a refresh_token in the response I get when I submit the code I get from the confirmation screen at the generated URL, but the confirmation screen only prompts me for access to my contacts, it does not ask whether I want to give offline access, and the token does indeed expire after an hour. What am I doing wrong?
Every Access token expires after one hour. when you don't request a offline, the user has to grant access again in order to get a new access token.
When requesting offline access token, as you mentioned, you will receive a refresh token. You will use this refresh token to request a new access token after or before it expires. This is done so the user wont be bothered every hour to grant access.
Here is the documentation about refresh token: https://developers.google.com/identity/protocols/OAuth2WebServer#refresh

"Error validating client secret." 404 with Facebook Oauth and ruby

I am trying to implement facebook authentication for an app with warden, after the user allows facebook auth and redirects to my app callback with the token I get a 400 while consuming the api. My warden strategy is this:
class Facebook < Warden::Strategies::Base
def client
#client ||= OAuth2::Client.new MyApp::Facebook::AppID, MyApp::Facebook::AppSecret, :site => 'https://graph.facebook.com'
end
def params
#params ||= Rack::Utils.parse_query(request.query_string)
end
def authorize_url
client.web_server.authorize_url :redirect_uri => request.url, :scope => 'email,publish_stream'
end
def authenticate!
throw(:halt, [302, {'Location' => authorize_url}, []]) unless params['code']
facebook = client.web_server.get_access_token params['code'], :redirect_uri => request.url
rescue OAuth2::HTTPError => e
puts e.response.body
end
end
Strategies.add :facebook, Facebook
The result of printing the response body is this:
{"error":{"type":"OAuthException","message":"Error validating client secret."}}
I am pretty shure the app id and app secret are the ones provided by FB.
Thanks.
I've seen that error message many times. Here are the things I would double check:
your domain is the same as what you listed in the facebook callback url
the app id is correct (actually print this out on a page, sometimes y
the app secret is correct
Add redirect_uri while creating the object of facebook that will fix the issue.
Redirect the user to https://www.facebook.com/dialog/oauth?client_id=YOUR_APP_ID&redirect_uri=YOUR_URL
After user click allow, it'll hit our Redirect Uri
At that point we'll get the code and we need to do a server side HTTP Get to the following Url to exchange the code with our oAuth access token:
https://graph.facebook.com/oauth/access_token?
client_id=YOUR_APP_ID&redirect_uri=YOUR_URL&
client_secret=YOUR_APP_SECRET&code=THE_CODE_FROM_ABOVE
Now at step 3, I kept on getting Http 400 response back.
So after some research, I found out that on that redirect_uri that we submitted on step 3 doesn't do anything but validate the request. Thus, the value need to match with step 2.
I also get the same error and i resolved by doing as below:
double check your client_id, client_secret, redirect_uri.
Add Accept: "application/json" header to thye request
fetch(
`https://graph.facebook.com/v15.0/oauth/access_token?client_id=${process.env.FACEBOOK_APP_ID}&redirect_uri=${process.env.FACEBOOK_REDIRECT_URI}&client_secret=${process.env.FACEBOOK_APP_SECRET}&code=${code}`,
{
method: "GET",
headers: {
Accept: "application/json",
},
}
)

Resources