I am trying to authenticate twitter login on Flask.
if flask.request.args.get('oauth_verifier')==None:
twauth = tweepy.OAuthHandler("***","***")
twauth.secure = True
try:
redirect_url = twauth.get_authorization_url() #This call requests the token from twitter and returns to us the authorization URL
except tweepy.TweepError,e:
logging.info('Failed : %s' % e)
print redirect_url
flask.session['request_token'] = twauth.request_token #storing the request token in a session:
twauth.get_authorization_url() creates error below
2018-06-13 16:50:48.047 JST
Fetching token from https://api.twitter.com/oauth/request_token using client <Client nonce=None, signature_method=HMAC-SHA1, realm=None, encoding=utf-8, timestamp=None, resource_owner_secret=None, decoding=utf-8, verifier=None, signature_type=AUTH_HEADER, rsa_key=None, resource_owner_key=None, client_secret=****, callback_uri=None, client_key=gpQh2S0rWdIdTCHfoaA3q2KYL> (lib.zip/requests_oauthlib/oauth1_session.py:363)
2018-06-13 16:50:48.048 JST
Signing request <PreparedRequest [POST]> using client <Client nonce=None, signature_method=HMAC-SHA1, realm=None, encoding=utf-8, timestamp=None, resource_owner_secret=None, decoding=utf-8, verifier=None, signature_type=AUTH_HEADER, rsa_key=None, resource_owner_key=None, client_secret=****, callback_uri=None, client_key=gpQh2S0rWdIdTCHfoaA3q2KYL> (lib.zip/requests_oauthlib/oauth1_auth.py:63)
2018-06-13 16:50:48.048 JST
Including body in call to sign: False (lib.zip/requests_oauthlib/oauth1_auth.py:75)
2018-06-13 16:50:48.048 JST
Collected params: [(u'oauth_version', u'1.0'), (u'oauth_consumer_key', u'gpQh2S0rWdIdTCHfoaA3q2KYL'), (u'oauth_signature_method', u'HMAC-SHA1'), (u'oauth_nonce', u'25122590467764310441528876248'), (u'oauth_timestamp', u'1528876248')] (lib.zip/oauthlib/oauth1/rfc5849/__init__.py:135)
2018-06-13 16:50:48.049 JST
Normalized params: oauth_consumer_key=gpQh2S0rWdIdTCHfoaA3q2KYL&oauth_nonce=25122590467764310441528876248&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1528876248&oauth_version=1.0 (lib.zip/oauthlib/oauth1/rfc5849/__init__.py:140)
2018-06-13 16:50:48.049 JST
Normalized URI: https://api.twitter.com/oauth/request_token (lib.zip/oauthlib/oauth1/rfc5849/__init__.py:141)
2018-06-13 16:50:48.049 JST
Signing: signature base string: POST&https%3A%2F%2Fapi.twitter.com%2Foauth%2Frequest_token&oauth_consumer_key%3DgpQh2S0rWdIdTCHfoaA3q2KYL%26oauth_nonce%3D25122590467764310441528876248%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1528876248%26oauth_version%3D1.0 (lib.zip/oauthlib/oauth1/rfc5849/__init__.py:146)
2018-06-13 16:50:48.049 JST
Signature: auihczIZGViCuENQooh5i5BRIA0= (lib.zip/oauthlib/oauth1/rfc5849/__init__.py:153)
2018-06-13 16:50:48.049 JST
Encoding URI, headers and body to utf-8. (lib.zip/oauthlib/oauth1/rfc5849/__init__.py:321)
2018-06-13 16:50:48.049 JST
Updated url: https://api.twitter.com/oauth/request_token (lib.zip/requests_oauthlib/oauth1_auth.py:92)
2018-06-13 16:50:48.050 JST
Updated headers: {'Content-Length': '0', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'User-Agent': 'python-requests/2.19.0', 'Connection': 'keep-alive', 'Authorization': 'OAuth oauth_nonce="25122590467764310441528876248", oauth_timestamp="1528876248", oauth_version="1.0", oauth_signature_method="HMAC-SHA1", oauth_consumer_key="gpQh2S0rWdIdTCHfoaA3q2KYL", oauth_signature="auihczIZGViCuENQooh5i5BRIA0%3D"'} (lib.zip/requests_oauthlib/oauth1_auth.py:93)
2018-06-13 16:50:48.050 JST
Updated body: None (lib.zip/requests_oauthlib/oauth1_auth.py:94)
2018-06-13 16:50:48.077 JST
Failed : Only tempfile.TemporaryFile is available for use (/base/data/home/apps/b~ktest321986/20180613t164654.410404564513746141/control/contact.py:68)
I try on localhost, there is no problem.
The problem comes when I deploy to GAE.
How to solve this?
Thanks
I just figure out that Tweepy 3.5.0 does not work with GAE.
I use version 2.3.0 and it just works.
I replicated your code in App Engine flexible and came across the same issues deploying. Checking the requirements.txt, I had specified an older version of Tweepy - changing it to the latest (3.6.0) resolved the issue, so I would try that one also.
Related
I am trying to programmatically access an IAP-protected App Engine Standard app via Python from outside of the GCP environment.
I have tried various methods, including the method shown in the docs here: https://cloud.google.com/iap/docs/authentication-howto#iap-make-request-python. Here is my code:
from google.auth.transport.requests import Request
from google.oauth2 import id_token
import requests
def make_iap_request(url, client_id, method='GET', **kwargs):
"""Makes a request to an application protected by Identity-Aware Proxy.
Args:
url: The Identity-Aware Proxy-protected URL to fetch.
client_id: The client ID used by Identity-Aware Proxy.
method: The request method to use
('GET', 'OPTIONS', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE')
**kwargs: Any of the parameters defined for the request function:
https://github.com/requests/requests/blob/master/requests/api.py
If no timeout is provided, it is set to 90 by default.
Returns:
The page body, or raises an exception if the page couldn't be retrieved.
"""
# Set the default timeout, if missing
if 'timeout' not in kwargs:
kwargs['timeout'] = 90
# Obtain an OpenID Connect (OIDC) token from metadata server or using service
# account.
open_id_connect_token = id_token.fetch_id_token(Request(), client_id)
print(f'{open_id_connect_token=}')
# Fetch the Identity-Aware Proxy-protected URL, including an
# Authorization header containing "Bearer " followed by a
# Google-issued OpenID Connect token for the service account.
resp = requests.request(
method, url,
headers={'Authorization': 'Bearer {}'.format(
open_id_connect_token)}, **kwargs)
print(f'{resp=}')
if resp.status_code == 403:
raise Exception('Service account does not have permission to '
'access the IAP-protected application.')
elif resp.status_code != 200:
raise Exception(
'Bad response from application: {!r} / {!r} / {!r}'.format(
resp.status_code, resp.headers, resp.text))
else:
return resp.text
if __name__ == '__main__':
res = make_iap_request(
'https://MYAPP.ue.r.appspot.com/',
'Client ID from IAP>App Engine app>Edit OAuth Client>Client ID'
)
print(res)
When I run it locally, I have the GOOGLE_APPLICATION_CREDENTIALS environment variable set to a local JSON credential file containing the keys for the service account I want to use. I have also tried running this in Cloud Functions so it would presumably use the metadata service to pick up the App Engine default service account (I think?).
In both cases, I am able to generate a token that appears valid. Using jwt.io, I see that it contains the expected data and the signature is valid. However, when I make a request to the app using the token, I always get this exception:
Bad response from application: 401 / {'X-Goog-IAP-Generated-Response': 'true', 'Date': 'Tue, 09 Feb 2021 19:25:43 GMT', 'Content-Type': 'text/html', 'Server': 'Google Frontend', 'Content-Length': '47', 'Alt-Svc': 'h3-29=":443"; ma=2592000,h3-T051=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"'} / 'Invalid GCIP ID token: JWT signature is invalid'
What could I be doing wrong?
The solution to this problem is to exchange the Google Identity Token for an Identity Platform Identity Token.
The reason for the error Invalid GCIP ID token: JWT signature is invalid is caused by using a Google Identity Token which is signed by a Google RSA private key and not by a Google Identity Platform RSA private key. I overlooked GCIP in the error message, which would have told me the solution once we validated that the token was not corrupted in use.
In the question, this line of code fetches the Google Identity Token:
open_id_connect_token = id_token.fetch_id_token(Request(), client_id)
The above line of code requires that Google Cloud Application Default Credentials are setup. Example: set GOOGLE_APPLICATION_CREDENTIALS=c:\config\service-account.json
The next step is to exchange this token for an Identity Platform token:
def exchange_google_id_token_for_gcip_id_token(google_open_id_connect_token):
SIGN_IN_WITH_IDP_API = 'https://identitytoolkit.googleapis.com/v1/accounts:signInWithIdp'
API_KEY = '';
url = SIGN_IN_WITH_IDP_API + '?key=' + API_KEY;
data={
'requestUri': 'http://localhost',
'returnSecureToken': True,
'postBody':'id_token=' + google_open_id_connect_token + '&providerId=google.com'}
try:
resp = requests.post(url, data)
res = resp.json()
if 'error' in res:
print("Error: {}".format(res['error']['message']))
exit(1)
# print(res)
return res['idToken']
except Exception as ex:
print("Exception: {}".format(ex))
exit(1)
The API Key can be found in the Google Cloud Console -> Identity Platform. Top right "Application Setup Details". This will show the apiKey and authDomain.
More information can be found at this link:
Exchanging a Google token for an Identity Platform token
I am calling web-service from AngularJS using this code:
$http({
url: "DBService.asmx/GetRG_Users",
dataType: 'json',
method: 'POST',
data: '',
headers: {
"Content-Type": "application/json"
}
But I am only able to access limited number of rows from Service. Once I tried to get all rows it will throw:
500 (Internal Server Error)
Its a server side implementation. You cannot retrieve huge amount of response from the server using http request. You need to set the max size as
php_value post_max_size 20M
I found the solution by using below information in config
<system.web.extensions>
<scripting>
<webServices>
<jsonSerialization maxJsonLength="50000000"/>
</webServices>
</scripting>
</system.web.extensions>
I am trying to get access to the google drive content of my users.
I can redeem a code on my domain using the google drive user consent url with correct parameters:
https://accounts.google.com/o/oauth2/v2/auth?response_type=code&client_id='+$scope.googledriveApi.client_id+'&scope='+$scope.googledriveApi.scopes+'&redirect_uri='+$scope.googledriveApi.redirect_uri
I am trying to do an angular $http request to the https://www.googleapis.com/oauth2/v4/token endpoint.
The request looks like this:
$http({
method: 'POST',
headers: {"Content-Type" : "application/x-www-form-urlencoded"},
data: $.param({
"code" : $routeParams.code,
"client_id" : $scope.googledriveApi.client_id,
"client_secret" : $scope.googledriveApi.secret,
"redirect_uri" : $scope.googledriveApi.redirect_uri,
"grant_type" : "authorization_code"
}),
url: 'https://www.googleapis.com/oauth2/v4/token'
})
However the response I get from the request is as follows:
{
"error": "invalid_client",
"error_description": "The OAuth client was not found."
}
Does anyone know why this happens? I have tried changing product name and client id name to be the same. I have checked this for spaces. The reason I'm mentioning this is because this seemed to be the case for other people who asked a question for the same error, however my error happens at the $http request.
I am getting back the user consent code and I am trying to exchange for an access token in this request. This is when the error comes in and I am stuck.
Try these:
Under OAuth consent screen, make sure Product name is not the same with project name as stated in this SO thread:
Try to include an authorization header in your URI request:
headers: { 'Authorization': 'bearer ' + accessToken }
I'm using $http to post some data to my data base.
Here is the documentation of the database.
I use it on my terminal and it works.
Here's the error message I got from Safari's console:
1)Failed to load resource: Request header field 0 is not allowed by Access-Control-Allow-Headers. (seems to be sensed by the database)
2)XMLHttpRequest cannot load https://beta-api.mongohq.com/mongo/MyDId/myDatabse/collections/myCollection/documents. Request header field 0 is not allowed by Access-Control-Allow-Headers.
Here's my code:
factory.sendUrlTag = function(data){
d = '{"document" : {"url_URL":"53738eef9256a31f4fdf6bf8","tag_Tag":"537375fc9256a31f4fdf6bf3"} }'
return $http({
url: 'https://beta-api.mongohq.com/mongo/MyDId/myDatabse/collections/myCollection/documents',
method: "POST",
data: d,
headers: [
{'Access-Control-Allow-Origin':'*'},
{'Access-Control-Allow-Headers':'Origin, X-Requested-With, Content-Type, Accept'},
{'Content-Type': 'application/json'},
{'Authorization' : 'api-key MyKey'}
]
})
}
return factory;
};
I didn't have " {'Access-Control-Allow-Origin':'*'},
{'Access-Control-Allow-Headers':'Origin, X-Requested-With, Content-Type, Accept'}," before, but I did some research after I got the error and added these. But it's still not working.
I do $http.get() in my app to the same database and it works.
This thing is driving me nuts....
Please help!
Thank you all! :)
Access-Control-Allow-Origin and friends are response headers, not request headers. It wouldn't make sense if Bob was responsible for granting Bob permission to Alice's system.
The server (https://beta-api.mongohq.com/mongo/MyDId/myDatabse/collections/myCollection/documents) has to send them, not the client.
Since you are making a cross-origin POST request, the server also needs to be able to respond to a pre-flight OPTIONS request.
I found some way maybe able to get around the issue:
Use this and here to get around the cross origin origin issue.
And this to get around the localhost
It may work.
Another relative post.
DEMO: http://jsfiddle.net/rob_balfre/7QUUf/
How do you POST data (across domain) using $resource?
For example this curl writes to the API with no problem:
curl --dump-header - -H "Content-Type: application/json" -X POST --data '{"name": "Wobbly"}' http://192.168.91.20/api/food/
and the header response is:
HTTP/1.0 201 CREATED
Date: Thu, 25 Oct 2012 08:19:42 GMT
Server: WSGIServer/0.1 Python/2.6.1
Access-Control-Allow-Headers: Content-Type,*
Location: http://localhost/api/food/15/
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST,GET,OPTIONS,PUT,DELETE
Content-Type: text/html; charset=utf-8
I'm totally stuck on how to get angular to POST the same way. This is my $resource, it's worth noting that 'get' works just fine:
angular.module('tastypieModule', ['ngResource']).
factory('FoodOptions', function($resource, $timeout) {
var FoodOptions = $resource('http://testurl/api/:type',
{type: 'food'},
{
get: {method: 'JSONP', params: {format: 'jsonp', callback:'JSON_CALLBACK'}},
update: {method: 'POST', headers: {'Content-Type': 'application/json'}}
}
);
return FoodOptions;
})
When I call update it just fails and I see this is the console network tab:
METHOD: OPTIONS
STATUS: (canceled) Load cancelled
On the server you need to implement a Cross Origin Resource Sharing. http://www.html5rocks.com/en/tutorials/cors/ and http://omarrr.com/cors-html5-approach-to-crossdomain-policies/ both have good articles about the topic. The HEAD request is coming from the browser to your server to check for the headers that contain (or in your case, don't contain) the CORS permissions. If you implement CORS on the server then you'll see the browser first make a HEAD request once to the server then after confirming the correct permissions it will make the POST.