OAuth2: RuntimeError: A refresh_token is not available - ruby

I use OAuth2::Client for get access_token.
Need refresh it with refresh_token
client_id = '95585XXXXXXXoogleercontent.com'
secret_key = 'R10Ze490IYa'
client = OAuth2::Client.new(client_id, secret_key, {
authorize_url: 'https://accounts.google.com/o/oauth2/auth',
token_url: 'https://accounts.google.com/o/oauth2/token'
})
redirect_url = client.auth_code.authorize_url({
scope: 'https://www.googleapis.com/auth/analytics.readonly',
redirect_uri: 'https://example.com',
access_type: 'offline'
})
auth_code = '4/5AF6VI0JMcmA38XXXXX' # getted from redirect_url clicking
access_token = client.auth_code.get_token(auth_code, redirect_uri: 'https://example.com')
Then I try to refresh token:
access_token.refresh!
And I have error:
RuntimeError: A refresh_token is not available

Need add - prompt: 'consent':
redirect_url = client.auth_code.authorize_url({
scope: 'https://www.googleapis.com/auth/analytics.readonly',
redirect_uri: 'https://example.com',
access_type: 'offline',
prompt: 'consent'
})
Then you can get new access_token:
new_access_token = access_token.refresh!
Also you can save token for future using:
hash = access_token.to_hash # save it
# load:
loaded_token = OAuth2::AccessToken.from_hash(client, hash)

Related

Ruby implementing oauth2 client credentials flow

I'm new to Ruby and I'm trying to implement a oauth2 with client credentials flow.
I've found the "ouath2" gem, but that requires a redirect_uri that I don't have.
Here is the gem.
Here is what I'm trying to implement
secret_id = 'this-is-a-secret-id'
token_id = 'this-is-a-token-id'
scope = 'such-a-good-scope'
grant_type = 'client_credentials'
#client = nil
# Get access token
def GetAccessToken
HttpRequest request = HttpRequest::Post("https://awesome-page.com/oauth/token")
request.content = {
{ "client_id" => token_id },
{ "client_secret" => secret_id }
{ 'grant_type' => grant_type },
{ 'scope' => scope}
}
response = request.send
json = response.content
accessToken = JsonConvert.DeserializeObject<Token>(json)
#client = Client.new(bearer: accessToken)
end
# Refresh token
def RefreshToken
HttpRequest request = HttpRequest::Post("https://awesome-page.com/oauth/token")
request.content = {
{ "client_id" => token_id },
{ "client_secret" => secret_id }
{ 'grant_type' => grant_type },
{ 'refresh_token' => scope}
}
response = request.send
json = response.content
accessToken = JsonConvert.DeserializeObject<Token>(json)
#client = Client.new(bearer: accessToken)
end
# End then implementing the "getting the resources with the client" part and so on...
Any idea how to do this, I'm getting a little bit desperate now
Any help is greatly appreciated!
You’re kind of going about this all wrong. With the Oauth2 gem you need to:
Initialise a new Oauth2::Client with your client ID, secret, scope, and define the token and redirect url (this is a url in your app that users logging in get sent back to. Not used for Client Credentials flow as it’s for server to server comms)
Call token = client.client_credentials.get_token. This sets token to an AccessToken it obtained.
Then call token.get(‘https://your-url.com/path/to/resource’) - or post/patch/delete.
Look at the access_token.rb file in the repo to see the methods you can call. They also take a series of params, for things like additional headers or body payload you can pass. It’s based on Faraday so you can always look up Faraday docs for help with that part.

The request signature we calculated does not match the signature you provided | Aws::Sigv4::Signer | Ruby

I'm getting this error
The request signature we calculated does not match the signature you provided
The Canonical String for this request should have been
The String-to-Sign should have been
I am trying to implement the SP APIs in rails.
I've fetched the access-token from https://api.amazon.com/auth/o2/token endpoint.
And after wards created the temporary session token using Aws::STS::Client.
I used Aws::Sigv4::Signer for signature.
First Step (Access Token)
payload = {
grant_type: 'refresh_token',
client_id: [ClientId],
refresh_token: [RefreshToken],
client_secret: [ClientSecret],
}
headers = {'Content-Type': 'application/json'}
response = HTTParty.post("https://api.amazon.com/auth/o2/token", body: payload.to_json, headers: headers)
access_token = response["access_token"]
Second Step (Create Assume Role Using AWS::STS)
result = sts = Aws::STS::Client.new(
region: "us-east-1",
credentials: Aws::Credentials.new("aws-access-key", "aws-secret-key")
).assume_role({
role_arn: "role_arn",
role_session_name: 'sp-api'
})
enter code here
Third Step (Create Signature )
signer = Aws::Sigv4::Signer.new(
service: 'execute-api',
region: 'us-east-1',
# static credentials
access_key_id: access_key_id,
secret_access_key: secret_access_key,
session_token: session_token
)
signature = signer.sign_request(
http_method: 'GET',
url: 'https://sellingpartnerapi-na.amazon.com/orders/v0/orders/ordersID',
headers: {
'host' => 'sellingpartnerapi-na.amazon.com',
'X-Amz-Access-Token' => access_token,
})
Final Step (To call the API with the Signature Headers)
headers = {
'Content-Type' => 'application/json',
"host" => signature.headers["host"],
"X-Amz-Date" => signature.headers['x-amz-date'],
"X-Amz-Security-Token" => signature.headers["x-amz-security-token"],
"X-Amz-Content-Sha256" => signature.headers["x-amz-content-sha256"],
"Authorization" => signature.headers['authorization']
}
data = HTTParty.send(:get, "https://sellingpartnerapi-na.amazon.com/orders/v0/orders/ordersID", headers: headers)

How to check if my token is active ruby on rails

I would like to set my token only once per user, do you know how to check if my token is already set ?
Here is my Controller :
def connexion
code = request.params[:code]
#decoded_code = URI.decode(code)
#id_connection = request.params[:id_connection]
#token = HTTParty.post('https://test-sandbox/auth/token/access',
body: {
client_id: XXXXXX,
client_secret: "YYYYYYYYYYYYYYYYY",
code: #decoded_code
}
)
end
If I go back to my page and re-set the token I have the following error : You have already got an access_token for this user
You can use ||= operator to set token, if it is not set than it will try to get token
#token ||= HTTParty.post('https://test-sandbox/auth/token/access',
body: {
client_id: XXXXXX,
client_secret: "YYYYYYYYYYYYYYYYY",
code: #decoded_code
}
)

Get Refresh Token with lib google-drive-ruby

From article: https://github.com/gimite/google-drive-ruby/blob/master/doc/authorization.md
Code:
credentials = ... same as above ...
credentials.code = authorization_code
credentials.fetch_access_token!
Then
If you want to restore a session afterwards, you can store credentials.refresh_token after credentials.fetch_access_token!
But after credentials.fetch_access_token!
credentials.refresh_token is nil
How i can get refresh_token?
Or save credentials to database for next time?
Need add additional_parameters:
require "googleauth"
credentials = Google::Auth::UserRefreshCredentials.new(
client_id: "YOUR CLIENT ID",
client_secret: "YOUR CLIENT SECRET",
scope: [
"https://www.googleapis.com/auth/drive",
"https://spreadsheets.google.com/feeds/",
],
redirect_uri: "http://example.com/redirect",
:additional_parameters => {
"access_type"=>"offline",
"include_granted_scopes"=>"true",
"prompt" => "consent"
}
)
auth_url = credentials.authorization_uri
credentials.code = authorization_code
credentials.fetch_access_token!
then get:
refresh_token = credentials.refresh_token
and then refresh_token can be stored in database and used later:
credentials.refresh_token = refresh_token
credentials.fetch_access_token!
session = GoogleDrive::Session.from_credentials(credentials)

OAuth2 error invalid client

I'm getting an invalid client error. Client works for auth_code.authorize_url, but not for auth_code.get token
relevant code:
CLIENT_ID = "$$$.apps.googleusercontent.com"
CLIENT_SECRET = "secret"
REDIRECT_URI = 'http://localhost:3000'
client = OAuth2::Client.new(CLIENT_ID, CLIENT_SECRET,
site: 'https://accounts.google.com',
token_url: '/o/oauth2/token',
authorize_url: '/o/oauth2/auth')
url = client.auth_code.authorize_url(scope: "https://www.google.com/m8/feeds",
redirect_uri: REDIRECT_URI)
puts url
code = "taken from url" #line 20
token = client.auth_code.get_token(code, :redirect_uri => REDIRECT_URI)
Error message:
/.rvm/gems/ruby-2.2.1/gems/oauth2-1.0.0/lib/oauth2/client.rb:113:in `request': invalid_client: (OAuth2::Error)
{
"error" : "invalid_client"
}
from /.rvm/gems/ruby-2.2.1/gems/oauth2-1.0.0/lib/oauth2/client.rb:138:in `get_token'
from /.rvm/gems/ruby-2.2.1/gems/oauth2-1.0.0/lib/oauth2/strategy/auth_code.rb:29:in `get_token'
from oauth.rb:20:in `<main>'
One clarification I think I need is that say the code given from the url is /?code=$code$ do I use just the $code$?(currently doing this) or code=$code$
Thanks in advance for the help
Fixed:
The answer was the allow offline mode when initializing the client. I was also using a code I had previously used.
changed this:
client = OAuth2::Client.new(CLIENT_ID, CLIENT_SECRET,
site: 'https://accounts.google.com',
token_url: '/o/oauth2/token',
authorize_url: '/o/oauth2/auth')
to this:
client = OAuth2::Client.new(CLIENT_ID, CLIENT_SECRET,
site: 'https://accounts.google.com',
token_url: '/o/oauth2/token',
authorize_url: '/o/oauth2/auth',
additional_parameters: {"access_type" => "offline"} ) #new line

Resources