I've got a Django template that initiates the Facebook OAuth process by doing:
window.location='https://www.facebook.com/dialog/oauth?client_id=MY_CLIENT_ID&redirect_uri=http%3A//localhost%3A8000/fbpanel/explore-python'
Then, in my Django view, I get the resulting code as follows:
import cgi
import urllib
# [...]
code = request.GET['code']
args = {
'client_id': MY_CLIENT_ID,
'redirect_uri': 'http://localhost:8000/fbpanel/explore_python'
'client_secret': MY_CLIENT_SECRET,
'code': code,
}
url = 'https://graph.facebook.com/oauth/access_token?' + \
urllib.urlencode(args)
raw_response = urllib.urlopen(url).read()
response = cgi.parse_qs(raw_response)
if response:
error = ''
if response['access_token']:
access_token = response['access_token'][0]
if response['expires']:
expires = response['expires'][0]
else:
access_token = 'No access token returned'
expires = 'No expiration given'
error = raw_response
Invariably, response is None and raw_response contains Error: {"error":{"message":"Error validating verification code.","type":"OAuthException"}}
The same credentials validate fine with the JavaScript SDK. I was binding my server to localhost in that case too, and have localhost:8000 set in my official app domain. Before I did that, the JavaScript wouldn't work. After, it did. So I don't think localhost is the issue.
I've manually stepped through the code, printing the code returned by FB out,
then manually running the above code line by line in the python interpreter, and
I can't see anything I'm doing wrong. What are my next debugging steps? The FB
documentation offers little guidance if you receive an OAuthException.
The value used for redirect_uri must be exactly the same when you request the token as it was when you requested the code. Since no actual redirect occurs when requesting the token, it can be easy to miss small differences. The error message is not particularly descriptive in this case; what it really means is "The parameters you are sending don't correspond with the code value you are sending".
Related
I am writing a program that can change your Mojang username at whatever time you specify (i.e. the name "tom" becomes available at 09:05:39 so you would set the program to change your name to "tom" at that time). To do this you need a bearer token. I can log into minecraft.net and use EditThisCookie to access that, but I want to be able to have the program wait until it is within a minute of the name dropping to gather proxies and the bearer token automatically for situations where a name is becoming available in the middle of the night or I'm just lazy. I'm not sure why my function for getting the bearer token won't work. I referenced this to write this code.
def getAT():
jsonForAT = json.dumps({"agent":{"name":"Minecraft","version":1},"username":email,"password":password,"clientToken":""})
headersForAT = {'Content-Type': 'application/json'}
requestForAT = requests.post('https://authserver.mojang.com/authenticate', data=jsonForAT, headers=headersForAT)
pullATRequestData = requestForAT.json()
AT = pullATRequestData["accessToken"]
return AT
I am really confused since when I use this, I get a 401 error but the program works when I get the token manually.
I also was experiencing the same issue. Then, I realized that Minecraft/Mojang accounts have security questions. If your function is getting the bearer token and your issue is that your access is denied when posting a name change request:
1st make sure your formatting it properly:
headers={'Authorization': f"Bearer {TOKEN}"
Notice the space between "Bearer" and {TOKEN}
2nd: For some reason, Mojang needs you to send a Get request to their security challenges endpoint. You don't have to do anything with the returned data..
When you got the token manually, I'm assuming your browser automatically sent this get request and that's why it worked. If you're using proxies, you'll probably need to send a post request with your security question answers, look at the API link for documentation.
For Example:
res = requests.get(
"https://api.mojang.com/user/security/challenges",
headers={"Authorization": f"Bearer {TOKEN}"},
)
https://wiki.vg/Mojang_API
Go to the bottom under "Security question-answer flow"
I am trying to capture my access token that is returned by an API during authentication process. The official method of doing the authentication process from the API is:
from xyz_api import accessToken
app_id = "your_app_id"
app_secret = "your_app_secret"
app_session = accessToken.SessionModel(app_id, app_secret)
response = app_session.auth()
The above will return a json like:
{
"code" : 200,
"data" : {
"authorization_code": "some random code"
},
}
Now, the following code is used to generate a URL:
authorization_code = “your_authorization_code”
app_session.set_token(authorization_code)
url = app_session.generate_token()
Now this is where I start having issue.
At this stage, what is recommended by the API author is:
1. Use the generated URL and copy paste it into a browser.
2. The browser will then do the authentication and return the access token to a redirect
url (I used http://localhost:5000).
3. Copy and paste the access token from redirect URL
What I want:
To be able to finish the authentication and get the access_token from
python code itself.
What I tried:
Using requests.get(url), but it doesn't work.
Is there any way to do this all using python only, without having a need to open a browser?
PS: The API I am trying to use is: https://api-docs.fyers.in/v1#authorization
Further Investigation
On further investigation, I discovered the following:
The API uses oauth
The URL obtained from the following code provided by the API author
url = app_session.generate_token()
is same as when I write the following code:
oauth = OAuth2Session('app_id')
authorization_url, state = oauth.authorization_url(url)
The url returned in both cases is of the form:
https://api.fyers.in/api/v1/genrateToken?authorization_code=some_auth_code&appId=my_app_id
If I copy paste this URL in a browser, it send back the access_token to my redirect_url (http://localhost:5000)
I am trying to get the access token using oauth::fetch_token with the following code, which is failing:
oauth1 = OAuth2Session('app_id', state=state, redirect_uri="http://localhost:5000")
token = oauth1.fetch_token('https://api.fyers.in/api/v1/genrateToken/',
client_secret='app_secret',
code='the_auth_code_returned')
Truly appreciate the help.
you are accessing only with Python...
you dont need to do anything manually in a browser..
This API not sure if what you wnat to.
I Believe you registred an APP , got your app_secret
the step
response = app_session.auth()
answer you with a authorization_code
"data" : {
"authorization_code": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqaGdqZzg3NiQ3ODVidjVANjQ3NTZ2NSZnNyM2OTg3Njc5OHhkIjoiWElHVFVYVjBSSSIsImV4cCI6MTU2MTU5NzM5Ny41NjQxNTV9.Agl-Uus63NforrUEdbG7YUlPcbFXu9hLYm4akGuIBkU"
you may access that authorization token like that
import json
r = json.dumps(reponse)
authorization_token = r['data']['authorization_code']
The authorization token AND you app_id must be passed as querystring to https://api.fyers.in/api/v1/genrateToken?
the REAL user will be then asked to accept login trought your app
and if accepted , the user will be redirected to the URL *I imagined you inform in your app register.
let me know if it make sense
I have been working on using the powerbi REST API and I haven't been able to properly make use of it. I made use of this and I was able to register an app and get as far as getting an access token, but still I get 401 statuses on my requests.
My major points of confusion are with regards to the app registration:
1) I am trying to read and write data from a python script. Is this a Native-App or a Web Side Server?
2) What is the meaning of the redirect and home urls on the app registration page? I am currently using my localhost:5000 with different /paths. Could this be the source of the issue?
3) My research indicates that there should be some sort of login interaction. I don't have one, is this an indication that something isn't being done properly?
My code is as follows:
import adal
import requests
AUTHORITY_URL = 'https://login.microsoftonline.com/{my_company}.onmicrosoft.com'
RESOURCE = 'https://analysis.windows.net/powerbi/api'
CLIENT_ID = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
CLIENT_SECRET = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
def make_headers(access_token):
return {
'Authorization': "Bearer {}".format(access_token)
}
context = adal.AuthenticationContext(AUTHORITY_URL)
token = context.acquire_token_with_client_credentials(RESOURCE, CLIENT_ID, CLIENT_SECRET)
access_token = token['accessToken']
headers = make_headers(access_token)
url = "https://api.powerbi.com/v1.0/myorg/datasets"
resp = requests.get(url, headers=headers)
As I said above this works to give me an access token though a get a status 401 response on the request and there is no sign in prompt.
Any help/guidance would be tremendously appreciated.
1) In your case you should register a Native app.
2) Native apps has only Redirect URI. Redirect URI gives AAD more details about the specific application it authenticates. For Native apps you should set it to https://login.live.com/oauth20_desktop.srf.
3) It's hard to say why you are getting Unauthorized response. Check what rights you gave to your application - does it has rights to read or write all datasets? Try to decode the access token at https://jwt.io and look at scp - does it contain "Dataset.Read.All" or "Dataset.ReadWrite.All"?
I work at a small company whose mail is hosted through Google. As one of the administrators responsible for managing employee accounts I'm attempting to automate some tasks using Google APIs and one or more dedicated service accounts. I wrote the short Python script below to request an access token according to the documentation Google provides but I continue to get an "invalid_grant" error.
I've done the following:
Logged into the Google Developers Console as the service account and created a project
Created a client ID of type service account
Logged into the Google Admin Console and added client email address and scope URLs I wish the account to have access to
Searches online have yielded answers indicating that either the system time of the machine is off, the limit for refresh tokens has been exceeded or that the client ID instead of the client email has been used. I've synchronized the time on a Windows machine and a Linux machine prior to running the script and the same error appears. I'm not even getting an access token so I doubt the refresh limit has been exceeded. As can be seen below, the iss value is set to the client email address ending with "#developer.gserviceaccount.com".
I suspect that there is something else I am missing and, as I'm new to Python, I suspect it's something embarrassingly simple. Perhaps someone can assist?
import json
import time
import base64
import requests
from datetime import datetime
utc = datetime.utcnow()
iat = time.mktime(utc.timetuple())
exp = iat + 3600
jwt_header = {
"alg":"RS256",
"typ":"JWT"
}
jwt_claim_set = {
"iss":"pleasehelpme#developer.gserviceaccount.com",
"scope":"https://www.googleapis.com/auth/admin.directory.user",
"aud":"https://www.googleapis.com/oauth2/v3/token",
"iat":int(iat),
"exp":int(exp),
"sub":"someadminfrustrated#googleoauth.com"
}
jwt_jws = bytearray(str(jwt_header) + '.' + str(jwt_claim_set))
jwt_unencoded = str(jwt_header) + '.' + str(jwt_claim_set) + '.' + str(jwt_jws)
jwt_encoded = base64.urlsafe_b64encode(str(jwt_unencoded))
url = 'https://www.googleapis.com/oauth2/v3/token'
headers = {
'content-type': 'application/x-www-form-urlencoded'
}
payload = {
'grant_type': 'urn:ietf:params:oauth:grant-type:jwt-bearer',
'assertion': jwt_encoded
}
response = requests.post(url, headers=headers, params=payload)
print response
print response.json()
The output is the following:
<Response [400]>
{u'error_description': u'Bad Request', u'error': u'invalid_grant'}
I would look at the output http and url to make sure, but it does seem like you are having authentication issues.
I ran into a similar, albeit less complicated problem, and couldn't get my Google Developer credentials in through a python script. I ended up using my Chrome browser cookies with this script to get through that part: http://n8henrie.com/2014/05/decrypt-chrome-cookies-with-python/
Makes everything pretty simple:
url = 'http://www.example.com'
s = requests.Session()
cookies = pyCookieCheat.chrome_cookies(url)
s.get(url, cookies = cookies)
I have a weird problem with Flickr OAuth on Google App Engine:
I'm requesting for oauth token and secret from Flickr using the code attached.. it fails most of time when tested on App Engine.. Flickr returns a page saying
"Flickr has the hiccups. We're looking into the problem right now..."
At first I thought it might be the problem with Flickr.. but then if I copied the URL into chrome directly, I could get the oauth token and secret..
So I thought it could be the problem with my code fetching the URL.. but in fact, with the same piece of code, I'm also able to get token and secret at localhost..
Now I'm really confused.. because this used to work perfectly until recently.. is there any update on App Engine dev server that might cause the problem? Please help!!!
url = "http://www.flickr.com/services/oauth/request_token"
params = {
"oauth_timestamp": str(int(time())),
"oauth_signature_method": "HMAC-SHA1",
"oauth_version": "1.0",
"oauth_nonce": sha1(str(random())).hexdigest(),
"oauth_callback": API_CALLBACK,
"oauth_consumer_key": API_KEY,
}
# Setup the Consumer with the key-secret given by Flickr
consumer = oauth2.Consumer(key=API_KEY, secret=API_SECRET)
# Create request
req = oauth2.Request(method="GET", url=url, parameters=params)
# Create signature
signature = oauth2.SignatureMethod_HMAC_SHA1().sign(req, consumer, None)
# Add the Signature to the request
req['oauth_signature'] = signature
h = httplib2.Http()
resp, content = h.request(req.to_url(), "GET")
Update: I changed the code a little bit, keep requesting if I don't get the token (given a max try allowed). It works... still, it is very annoying that I have to write such work-around. Would appreciate if better alternative is available!
You need to use https instead of http (see the comment thread above)