I'm so confused by OAuth and Google. It took me forever to get the refresh_token to create a new access_token. Then to find out the refresh_token expires too?? What is the point of that!!!??
All I need to do is persist a valid access_token for use with legato.
Here is what I manually enter into my terminal to retrieve an OAUTH code:
client = OAuth2::Client.new('GA_CLIENT_ID', 'GA_SECRET_KEY', {
:authorize_url => 'https://accounts.google.com/o/oauth2/auth',
:token_url => 'https://accounts.google.com/o/oauth2/token'
})
client.auth_code.authorize_url({
:scope => 'https://www.googleapis.com/auth/analytics.readonly',
:redirect_uri => 'http://localhost',
:access_type => 'offline',
:approval_prompt=> 'force'
})
Then I manually enter the outputted url to in my browser. I export the returned OAUTH code as to an env variable and get the access token:
access_token = client.auth_code.get_token(ENV['GA_OAUTH_CODE'], :redirect_uri => 'http://localhost')
Then I can access the access_token and refresh_token:
begin
api_client_obj = OAuth2::Client.new(ENV['GA_CLIENT_ID'], ENV['GA_SECRET_KEY'], {:site => 'https://www.googleapis.com'})
api_access_token_obj = OAuth2::AccessToken.new(api_client_obj, ENV['GA_OAUTH_ACCESS_TOKEN'])
self.user = Legato::User.new(api_access_token_obj)
self.user.web_properties.first # this tests the access code and throws an exception if invalid
rescue Exception => e
refresh_token
end
end
def refresh_token
refresh_client_obj = OAuth2::Client.new(ENV['GA_CLIENT_ID'], ENV['GA_SECRET_KEY'], {
:authorize_url => 'https://accounts.google.com/o/oauth2/auth',
:token_url => 'https://accounts.google.com/o/oauth2/token'
})
refresh_access_token_obj = OAuth2::AccessToken.new(refresh_client_obj, ENV['GA_OAUTH_ACCESS_TOKEN'], {refresh_token: ENV['GA_OAUTH_REFRESH_TOKEN']})
refresh_access_token_obj.refresh!
self.user = Legato::User.new(refresh_access_token_obj)
end
After an hour, my tokens expire and I have to manually start the process over again from the browser! How can I replicate this in code??
Here you go, made a little something just for you :)
It's a simple implementation, specifically to ease the pain of renewing tokens.
Just be sure to:
Put in your own APP_ID and APP_SECRET.
Either only save your refresh_token and call refresh_token() every time before you use it, or use refresh_token_if_needed() every time, and re-save the token and expires_at (preferred obviously , since you'll only refresh when needed).
Let me know how it worked out.
.
require 'gmail'
require 'gmail_xoauth'
require 'httparty'
class GmailManager
APP_ID = "DDDDDDDDDDDD-SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS.apps.googleusercontent.com"
APP_SECRET = "SSSSSS-SSSSSSSSSSSSSSSSS"
def refresh_token(refresh_token)
Rails.logger.info "[GmailManager:refresh_token] refreshing using this refresh_token: #{refresh_token}"
# Refresh auth token from google_oauth2 and then requeue the job.
options = {
body: {
client_id: APP_ID,
client_secret: APP_SECRET,
refresh_token: refresh_token,
grant_type: 'refresh_token'
},
headers: {
'Content-Type' => 'application/x-www-form-urlencoded'
}
}
response = HTTParty.post('https://accounts.google.com/o/oauth2/token', options)
if response.code == 200
token = response.parsed_response['access_token']
expires_in = DateTime.now + response.parsed_response['expires_in'].seconds
Rails.logger.info "Success! token: #{token}, expires_in #{expires_in}"
return token, expires_in
else
Rails.logger.error "Unable to refresh google_oauth2 authentication token."
Rails.logger.error "Refresh token response body: #{response.body}"
end
return nil, nil
end
def refresh_token_if_needed(token, expires_on, refresh_token)
if token.nil? or expires_on.nil? or Time.now >= expires_on
Rails.logger.info "[GmailManager:refresh_token_if_needed] refreshing using this refresh_token: #{refresh_token}"
new_token, new_expires_on = self.refresh_token(refresh_token)
if !new_token.nil? and !new_expires_on.nil?
return new_token, new_expires_on
end
else
Rails.logger.info "[GmailManager:refresh_token_if_needed] not refreshing. using this token: #{token}"
end
return token, expires_on
end
end
Related
ERROR: Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.
My code :
#client = Signet::OAuth2::Client.new(
:authorization_uri => 'https://accounts.google.com/o/oauth2/auth',
:token_credential_uri => 'https://oauth2.googleapis.com/token',
:client_id => ENV['GMB_CLIENT_ID'],
:client_secret => ENV['GMB_CLIENT_SECRET'],
:scope => 'https://www.googleapis.com/auth/youtube.upload',
:redirect_uri => 'https://localhost:4200/youtube'
)
# a = my user with token and refresh token got from signet oAuth with google
response = {
"access_token" => a.token,
"refresh_token" => a.refresh_token,
"expries_in" => total_second,
"scope" => "https://www.googleapis.com/auth/youtube.upload",
"token_type" => "Bearer"
}
#client.update!(response)
#service ||= Google::Apis::YoutubeV3::YouTubeService.new
#service.key = "my key"
#service.authorization = #client #setting the authorization for api
status = Google::Apis::YoutubeV3::VideoStatus.new(
privacy_status: 'unlisted',
)
snippet = Google::Apis::YoutubeV3::VideoSnippet.new(
title: "My video",
description: "description",
)
video_object = Google::Apis::YoutubeV3::Video.new(
status: status,
snippet: snippet,
)
#service.insert_video(
'id,snippet,status',
video_object,
notify_subscribers: true,
content_type: 'video/webm',
options: { authorization: #client }
)
Help needed to make it work. Authentication is not working
I am sending API requests to JIRA using JWT token authentication. I added the method (get, post, etc.) and the endpoint to SHA256 encoding. This succeeds:
qsh = Digest::SHA256.hexdigest("GET&#{endpoint}&")
jwt = JWT.encode({
qsh: qsh,
iat: issued_at,
exp: expires_at,
iss: key
}, secret)
However, I cannot add query parameters to the URI. If I append query parameters:
qsh = Digest::SHA256.hexdigest("GET&#{endpoint}&start=50&limit=50")
jwt = JWT.encode({
qsh: qsh,
iat: issued_at,
exp: expires_at,
iss: key
}, secret)
I receive unauthorized response 401.
MVP:
jira_request(:get,"/rest/servicedeskapi/servicedesk/#{serviceDeskId}/organization", nil)
def jira_request(method, endpoint, data)
request = Typhoeus::Request.new(jira_rest_api_url(method, endpoint),
followlocation: true, method: method,
body: data ? data.to_json : nil,
headers: { 'X-ExperimentalApi' => 'opt-in',
'Content-Type' => 'application/json' })
request.on_complete do |response|
if response.success? && !response.body.blank?
return JSON.parse(response.body)
elsif response.code == 204
return true
else
return false
end
end
request.run
end
# Creating JWT token to Auth for each request
def jira_rest_api_url(method, endpoint)
# Gets the ADDON details for generating JWT token
jwt_auth = MyJToken.first
issued_at = Time.now.utc.to_i
expires_at = issued_at + 500
qsh = Digest::SHA256.hexdigest("#{method.to_s.upcase}&#{endpoint}&")
jwt = JWT.encode({ qsh: qsh,
iat: issued_at,
exp: expires_at,
iss: jwt_auth.key
}, jwt_auth.secret)
# return the service call URL with the JWT token added
"#{jwt_auth.api_base_url}#{endpoint}?jwt=#{jwt}"
end
end
The parameters that are hashed in:
qsh = Digest::SHA256.hexdigest("GET&#{endpoint}&limit=50&start=50")
should be added in the request url:
"#{jwt_auth.api_base_url}#{endpoint}?jwt=#{jwt}&start=50&limit=50"
I am trying to get access tokens from OAuth.io for any Google based provider however whenever I authenticate I get an access_token but no refresh_token. I have chosen offline for the access_type but still no joy.
def google_auth
# Create a new API client & load the Google Drive API
client = Google::APIClient.new
client.authorization.client_id = ENV['GOOGLE_ID']
client.authorization.client_secret = ENV['GOOGLE_SECRET']
client.authorization.scope = ENV['GOOGLE_SCOPE']
client.authorization.redirect_uri = ENV['REDIRECT_URI']
client.authorization.code = self.code.chomp || ""
client.authorization.access_token = self.token
client.authorization.refresh_token = self.refresh_token
# client.authorization.additional_parameters = {
# "access_type" => "offline", # offline access
# "include_granted_scopes" => "true" # incremental auth
#
if client.authorization.refresh_token &&
client.authorization.expired?
client.authorization.fetch_access_token!
end
return client
end
def refresh_google
options = {
body: {
client_id: ENV['GOOGLE_ID'],
client_secret: ENV['GOOGLE_SECRET'],
refresh_token: self.refresh_token,
grant_type: 'refresh_token',
access_type: 'offline'
},
headers: {
'Content-Type' => 'application/x-www-form-urlencoded',
# 'access_type' =>'offline'
}
}
#response = HTTParty.post('https://accounts.google.com/o/oauth2/token', options)
if #response.code == 200
self.token = #response.parsed_response['access_token']
self.save
else
Rails.logger.error("Unable to refresh google_oauth2 authentication token.")
Rails.logger.error("Refresh token response body: #{#response.body}")
end
end
Please help in this regard
Issue resolved: I was trying to put
"client.authorization.additional_parameters = {
"access_type" => "offline", # offline access
"include_granted_scopes" => "true" # incremental auth"
in User the rb model where callback was made but had to put it under session controller where API was called!
What does this error signify?
Missing token endpoint URI. highlighted at #account_summaries
def analytics
client = Signet::OAuth2::Client.new(access_token: session[:access_token]['access_token'])
service = Google::Apis::AnalyticsV3::AnalyticsService.new
service.authorization = client
#account_summaries = service.list_account_summaries
end
I tried searching everywhere, but can't understand in context of Google Analytics API what does this even mean?
Technically, the code should just work, but for some reason its not playing nice. Where exactly is it going wrong?
Full code
class WelcomeController < ApplicationController
def redirect
client = Signet::OAuth2::Client.new({
client_id: 'APP ID',
client_secret: 'APP SECRET',
authorization_uri: 'https://accounts.google.com/o/oauth2/auth',
scope: Google::Apis::AnalyticsV3::AUTH_ANALYTICS_READONLY,
redirect_uri: url_for(:action => :oauth2callback)
additional_parameters: { access_type: :offline, approval_prompt: :force }
})
redirect_to client.authorization_uri.to_s
end
def oauth2callback
client = Signet::OAuth2::Client.new({
client_id: 'APP ID',
client_secret: 'APP SECRET',
token_credential_uri: 'https://accounts.google.com/o/oauth2/token',
redirect_uri: url_for(:action => :oauth2callback),
code: params[:code]
})
response = client.fetch_access_token!
session[:access_token] = response['access_token']
redirect_to url_for(:action => :analytics)
end
def analytics
client = Signet::OAuth2::Client.new(access_token: session[:access_token]['access_token'])
service = Google::Apis::AnalyticsV3::AnalyticsService.new
service.authorization = client
#account_summaries = service.list_account_summaries
end
end
In my controller I have the following actions
def twitter
client = TwitterOAuth::Client.new(
:consumer_key => ENV['TWITTER_KEY'],
:consumer_secret => ENV['TWITTER_SECRET']
)
request_token = client.request_token(oauth_callback: "http://myawesomeapp.herokuapp.com/create_users/get_twitter_info")
redirect_to "https://www.twitter.com/oauth/authenticate?oauth_token=#{request_token.params[:oauth_token]}"
end
def get_twitter_info
redirect_to "https://www.twitter.com/oauth/access_token?oauth_verifier=#{params[:oauth_verifier]}&oauth_token=#{params[:oauth_token]}"
end
def results
end
In my Twitter application settings, I've set Access to Read Only and checkmarked Allow this application to be used to Sign in with Twitter. Why is it returning
Invalid Request Token
when it hits the https://twitter.com/oauth/access_token page?
In Main function You write Simply this code
redirect_url = "http://myawesomeapp.herokuapp.com/create_users/get_twitter_info"
url = URI.parse(URI.encode(redirect_url.strip))
consumer_key=consumer key
consumer_secret=consumer secret
oauth = OAuth::Consumer.new(consumer_key, consumer_secret,
{ :site => "http://api.twitter.com" })
request_token = oauth.get_request_token(:oauth_callback => url)
session[:twitter_token] = request_token.token
session[:twitter_secret] = request_token.secret
and in
get_twitter_info
function you write
consumer_key=consumer key
consumer_secret=consumer secret
oauth = OAuth::Consumer.new(consumer_key,consumer_secret,
{ :site => "http://api.twitter.com" })
request_token = OAuth::RequestToken.new(oauth, session[:twitter_token], session[:twitter_secret])
#access_token = request_token.get_access_token(
:oauth_verifier => params[:oauth_verifier])
But Keep in mind in your twitter application setting you mention callback url is
http://myawesomeapp.herokuapp.com/create_users/get_twitter_info