Ruby Oauth2 Signet Return token with refresh token - ruby

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.

Related

javascript client for oauth2 and google-oauth library's "redirect-uri" missing case

I am working on porting oauth2client library to google-auth and oauthlib library
Right now for oauth2 authentication, I am using javascript client and using grantofflineaccess method in it.
The flow for oauth2client library was:
using the js client, we get the authorization code and pass it in oauth2client.client.credentials_from_code to get the credentials object. In the paramaeters, we pass only clientid,secret,scopes and code. There was no mention of redirect_uri.
Right now I am replacing it with flow
https://google-auth-oauthlib.readthedocs.io/en/latest/reference/google_auth_oauthlib.flow.html
This means that I HAVE TO pass redirect_uri to create the flow object, following which I can use flow.fetch_token(code) to get flow.credentials.
Here is my javascript side code (angularJS) (Reference: https://developers.google.com/identity/sign-in/web/reference)
// init
gapi.load('auth2', () => {
const authScopes = {
client_id: $window.GOOGLE_API_CLIENT_ID,
scope: scopes.join(' '),
};
auth2 = gapi.auth2.init(authScopes);
// When signin button clicked
auth2.grantOfflineAccess({ redirect_uri: 'postmessage', prompt: 'consent' })
.then((response) => {
// We enter this when user signins into google account and 'ALLOWS' the scopes. We receive the code in response using which we get the access and refresh token. The below calls are being made to backend
Something.authenticateUser(response.code).then(() => {
$scope.sheetsWizard.onLoginSuccess();
The backend code: (django)
# Upon receiving the 'code', it calls oauth2client function to get credentials object
credentials = client.credentials_from_code(
GOOGLE_API_CLIENT_ID,
GOOGLE_API_CLIENT_SECRET,
scopes,
data['code']
The above was older code, How the new code looks in the backend (The frontend or angularJS remains the same)
flow = Flow.from_client_config(client_config=dictionary_with_client_credentials, scopes=scopes, redirect_uri='some_website.com')
flow.fetch_token(code = data['code'])
credentials = flow.credentials
My questions:
Is there a method in google-auth that I am missing, so I don't have to pass redirect_uri, and still get at least access_token and refresh_token, after receiving code?
in js gapi client, there is a mention of redirect_uri='postmessage', but could not find documentation related to it. What does it mean?

Problem requesting Yahoo OAuth scopes through Roundcube

I'm currently using the 1.5 version of Roundcube and trying to configure it to work with the Yahoo mail server. I have created an app and have also allowed the email and profile API permissions from the OpenID.
There is an issue with the scopes and when trying to log in it redirects back to an error page and says: "Please request scope from registered scopes and submit again".
This is the current config for Roundcube:
// Enable OAuth2 by defining a provider. Use 'generic' here
$config['oauth_provider'] = 'yahoo';
// Provider name to be displayed on the login button
$config['oauth_provider_name'] = 'Yahoo';
// Mandatory: OAuth client ID for your Roundcube installation
$config['oauth_client_id'] = '------';
// Mandatory: OAuth client secret
$config['oauth_client_secret'] = '------';
// Mandatory: URI for OAuth user authentication (redirect)
$config['oauth_auth_uri'] = 'https://api.login.yahoo.com/oauth2/request_auth';
// Mandatory: Endpoint for OAuth authentication requests (server-to-server)
$config['oauth_token_uri'] = 'https://api.login.yahoo.com/oauth2/get_token';
// Optional: Endpoint to query user identity if not provided in auth response
//$config['oauth_identity_uri'] = 'null';
// Optional: disable SSL certificate check on HTTP requests to OAuth server
// See http://docs.guzzlephp.org/en/stable/request-options.html#verify for possible values
$config['oauth_verify_peer'] = true;
// Mandatory: OAuth scopes to request (space-separated string)
$config['oauth_scope'] = 'openid mail-r mail-w sdct-w';
// Optional: additional query parameters to send with login request (hash array)
$config['oauth_auth_parameters'] = ['nonce' => mt_rand(), 'prompt' => 'consent'];
// Optional: array of field names used to resolve the username within the identity information
$config['oauth_identity_fields'] = null;
// Boolean: automatically redirect to OAuth login when opening Roundcube without a valid session
$config['oauth_login_redirect'] = true;
Here are the settings for the app:
https://imgur.com/pwtNsvx
The error:
https://imgur.com/i11vMnM
https://imgur.com/Ar0tvnK
https://imgur.com/5Lertax
https://imgur.com/aRLVOLt
https://imgur.com/7d2L4Xv
You need to request access to restricted scopes first. Once and if approved you need to create an app and select the mail scope (the email scope is to get access to the users "email" identity, not for access to the mailbox). See https://developer.verizonmedia.com/mail

Okta Authentication works but Get User by Id gives Invalid Token Provided

I have a Django app that authenticates using Okta:
headers = {
'Authorization': 'SSWS {}'.format(<okta api token>),
'Accept': 'application/json',
'Content-Type': 'application/json'
}
authentication_payload = {
'username': <username>,
'password': <password>
}
response = requests.post(
<okta auth endpoint>,
headers=headers,
data=json.dumps(authentication_payload)
)
This works successfully. From the response content I am able to get the User Id:
content = json.loads(r.content.decode('utf-8'))
okta_user_id = content['_embedded']['user']['id']
I then use the okta_user_id to create the endpoint to get the okta user by id:
okta_user_endpoint = https://<org>.okta.com/api/v1/users/<okta_user_id>
I then use the same headers from the authentication call, with the same api token, and try to get the user by id:
user_response = requests.get(
okta_user_endpoint,
headers=headers
)
But this is unsuccessful. I get a 401 error with the following content:
{
"errorCode":"E0000011",
"errorSummary":"Invalid token provided",
"errorLink":"E0000011",
"errorCauses":[]
}
Seems straight forward with an invalid token, but if the token is invalid how am I able to successfully make the authentication call? And if the token if valid for the authentication call why is it not working to get the user by id?
Okta recently changed the way that the /authn endpoint works. The /authn endpoint no longer requires an authentication token. This was done in order to support single-page applications.
It looks like your application will need to be able to fetch user information on an arbitrary user. In that case, using an Okta API token makes sense.
However, if you were making that call from a single-page application, you would want to make a request to the /users/me API endpoint.

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

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

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.

Resources