I´m currently mining facebook using python. Until now, I´m getting an access token for graph API version 1.0(I need it to be 1.0) via this website:
https://developers.facebook.com/tools/explorer/?method=GET&path=me&version=v1.0
but the token I get on this site expires in about 1 hour, so how can I extend this token in python? I already saw how to in php, but, unfotunately, I have to stick with only python for my project
Facebook has 4 types of tokens: user, app, page and client (https://developers.facebook.com/docs/facebook-login/access-tokens#usertokens). Each of these token types have their own permissions. For example, you can post on behalf of a user (once they've granted you permission) using the app access token but need a user access token to pull user/statuses. The web user access token are short-lived (~1-2 hrs) and need to be converted to a long-lived (60 days) access token.
In python you can extend the token server-side calling the GraphAPI extend_access_token method assuming you are using the facebook-sdk (pip install facebook-sdk).
views.py:
import facebook
user_access_token = 'USER_ACCESS_TOKEN' # initially generated client-side
app_id = 'YOUR_UNIQUE_APP_ID' # found at developer.facebook.com
app_secret = 'YOUR_APP_SECRET' # found at developer.facebook.com
# Create fb graph object
graph = facebook.GraphAPI(user_access_token)
# Now extend it with the extend_access_token method
extended_token = graph.extend_access_token(app_id=app_id, app_secret=app_secret)
# Confirm token now expires in ~ 60 days or 5184000 seconds
print extended_token
Now that the token is extended, you can store and use on the users behalf w/out an active web client.
Related
I'm creating an Airbyte connector for Docusign's E-signature Rest API.
Part of the process of implementing a connector is to write an authentication routine that extends the AuthBase class from requests.auth.
The issue is that Docusign does not support refresh tokens for JWT grants. According to the docusign documentation:
The access token granted by JWT Grant expires after one hour, and no refresh token is provided. After the token expires, you must generate a new JWT and exchange it for a new access token.
You can reuse most of the old assertion, just modifying the IAT and EXP values and updating the signature, then submit the updated JWT to get a new access token.
Generally, apps that use JWT should get a new access token about 15 minutes before their existing one expires.
However, all of the examples in the "backend application flow" from this part of the requests documentation (which links to this page in the requests-authlib docs) only seem to allow an Auth2 workflow that includes a refresh token.
How can I work around this to make it so that, each time a refresh token expires, a new request is made (with updated IAT EXP, and signature)?
Refresh tokens are a feature of the OAuth Authorization Code grant flow.
The Authorization Code grant flow requires a human to authenticate themself. The result is an 8 hour access token and a 30 day refresh token.
To obtain a new access token, either:
Ask the human to authenticate again
Or the app can use the refresh token to obtain a new access token. This can be done autonomously by the app, without bothering the human.
For the JWT grant flow, there is no human and no refresh token. Instead, the app simply re-runs the JWT grant flow and receive a new 1 hour access token.
When you re-do the JWT flow, create a new JWT (updated IAT, EXP, etc). Sign it with your private key, and send it to DocuSign to obtain a new access token.
The JWT operation is cheap enough to do once per hour per impersonated user. But you must cache the access token and not re-do the JWT grant flow for each API call...
Python authentication libraries
Most authentication libraries for most languages focus on the Authorization Code grant flow since that is the most commonly used OAuth flow.
But as you've pointed out, you're using the JWT flow. This means that you cannot use these libraries. Instead, you will need to roll your own. Good news is that it isn't too hard. Here's my pseudo code:
Send_an_API_request(url, request_details, etc):
access_token = Get_access_token(user_id);
api_results = send_api_request(access_token, url, request_details, etc)
return api_results;
Get_access_token(user_id):
(access_token, expire_time) = database_lookup(user_id);
# if access_token is about to expire or we don't have one,
# create a new access_token and store it
if (
((current_time + 10minutes) > expire_time)
or
(access_token is null)
):
# Make a new JWT request
jwt = make_jwt(user_id);
signed_jwt = sign(jwt, private_key)
(access_token, expire_sec) = send_jwt_request(signed_jwt)
database_store (user_id, access_token, current_time + expire_sec)
return access_token
Added
Re:
[I need to] extend the AuthBase class from requests.auth
If the app's architecture requires you to extend the AuthBase class, then you will need to implement the JWT grant flow within the AuthBase class.
If the AuthBase class doesn't give you access to the data you need for the JWT grant flow, then a hack is to stuff the needed data into an available attribute such as the "refresh token."
The documentation gives an example of how to convert an Azure access_token that the user already has from the login process, but I'm not seeing anything about how to refresh that token. I managed to roll my own using adal, the Azure AD library for python, but I'm wondering if there's a better way using the tools included in DRF social oauth 2 or other django oauth packages that I'm just not finding. Please advise. Below is the function that refreshes my Azure AD token.
def refresh_social_access_token(self, request):
"""
This function leverages adal
https://github.com/AzureAD/azure-activedirectory-library-for-python
to refresh an expired access token.
.acquire_token_with_refresh_token(self, refresh_token, azure_ad_app_key,
resource, azure_ad_app_secret)
"""
user_social_auth = request.user.social_auth.filter(user=request.user) \
.values('provider', 'extra_data')[0]
context = AuthenticationContext(f'https://login.microsoftonline.com/{self.TENANT_ID}')
token = context.acquire_token_with_refresh_token(
user_social_auth['extra_data']['refresh_token'],
SOCIAL_AUTH_AZUREAD_OAUTH2_KEY,
user_social_auth['extra_data']['resource'],
client_secret=SOCIAL_AUTH_AZUREAD_OAUTH2_SECRET
)
try:
expiry = convert_iso_to_epoch(token["expiresOn"])
user_social_auth = request.user.social_auth.get(user=request.user)
user_social_auth.extra_data['expires_on'] = expiry
user_social_auth.save()
except KeyError:
HttpError('Oauth2 token could not be refreshed as configured.')
Earlier I was using Spotify's Search API
without any kind of authentication. But just last week or so, they made their API usage with Authentication only.
So since the past 2-3 days I've not been able to figure how this authorization works for Search API where I as a developer can let users access responses from Search API without having them to login with their Spotify accounts.
Can someone help me with this authorization stuff(The docs from Spotify don't solve my problem :< )
So here's the python code that I was earlier using -
import requests
import json
def Spotify(keyword):
url = "https://api.spotify.com/v1/search?q="+keyword+"&type=track&limit=1"
headers = {
'accept': "application/json",
'access_token':''
}
r = requests.get(url=url,headers=headers).text
jsonwa = json.loads(r)
name = jsonwa["tracks"]["items"][0]["name"]
artists = jsonwa["tracks"]["items"][0]["artists"][0]["name"]
song_preview_url = jsonwa["tracks"]["items"][0]["preview_url"]
image = jsonwa["tracks"]["items"][0]["album"]["images"][1]["url"]
return_this = []
return_this.append(name)
return_this.append(artists)
return_this.append(song_preview_url)
return_this.append(image)
print return_this
return return_this
song = "hello"
Spotify(song)
Per the web authorization docs:
All requests to the Spotify Web API require authorization
You'll need your users to grant permission for your app in order to get an access token. The user must be logged in to gran permission.
Once your app is granted permission by the user, you can use the refresh_token from that point on, and the user shouldn't need to grant permission again unless they revoke permission for example. You'll need to manage the access_token expiration.
I am trying to fetch captions from YouTube video using YouTube Data API (v3)
https://developers.google.com/youtube/v3/guides/implementation/captions
So, first I tried to retrieve a captions list using this url:
https://www.googleapis.com/youtube/v3/captions?part=snippet&videoId=KK9bwTlAvgo&key={My API KEY}
I could retrieve the caption id that I'd like to download (jEDP-pmNCIqoB8QGlXWQf4Rh3faalD_l) from the above link.
Then, I followed this instruction to download the caption:
https://developers.google.com/youtube/v3/docs/captions/download
However, even though I input the caption id and my api key correctly, it shows "Login Required" error.
I suppose I need OAuth authentication, but what I am trying to do is not related to my users's account, but simply downloading public caption data automatically.
My question is: Is there any way to process OAuth authentication just once to get an access token of my own YouTube account and then reuse it whenever I need it in my application?
I can't speak to the permissions needed for the captions API in particular, but in general, yes, you can OAuth to your app once using your own account and use the access and refresh tokens to make subsequent OAuth'd requests to the API. You can find the details of generating tokens here:
https://developers.google.com/youtube/v3/guides/auth/server-side-web-apps#Obtaining_Access_Tokens
To perform the steps manually (fortunately, you only need to do this once):
If access has already been granted for an app, it needs to be removed so that new auth credentials can be established. Go to https://security.google.com/settings/security/permissions (while logged into your account) and remove access to the app. If the client ID or secret change (or you need to create one), find them at https://console.developers.google.com under API Manager.
To grant access and receive a temporary code, enter this URL in a browser:
https://accounts.google.com/o/oauth2/auth?
client_id=<client_id>&
redirect_uri=http://www.google.com&
scope=https://www.googleapis.com/auth/youtube.force-ssl&
response_type=code&
access_type=offline&
approval_prompt=force
Follow the prompt to grant access to the app.
This will redirect to google.com with a code parameter (e.g.,
https://www.google.com/?code=4/ux5gNj-_mIu4DOD_gNZdjX9EtOFf&gws_rd=ssl#). Save the code.
Send a POST request (e.g., via Postman Chrome plugin) to https://accounts.google.com/o/oauth2/token with the following in the request body:
code=<code>&
client_id=<client_id>&
client_secret=<client_secret>&
redirect_uri=http://www.google.com&
grant_type=authorization_code
The response will contain both an access token and refresh token. Save both, but particularly the refresh token (because the access token will expire in 1 hour).
You can then use the access token to send an OAuth'd request manually, following one of the options here, essentially:
curl -H "Authorization: Bearer ACCESS_TOKEN" https://www.googleapis.com/youtube/v3/captions/<id>
or
curl https://www.googleapis.com/youtube/v3/captions/<id>?access_token=ACCESS_TOKEN
(When I tried the second option for captions, however, I got the message: "The OAuth token was received in the query string, which this API forbids for response formats other than JSON or XML. If possible, try sending the OAuth token in the Authorization header instead.")
You can also use the refresh token in your code to create the credential needed when building your YouTube object. In Java, this looks like the following:
String clientId = <your client ID>
String clientSecret = <your client secret>
String refreshToken = <refresh token>
HttpTransport transport = new NetHttpTransport();
JsonFactory jsonFactory = new JacksonFactory();
GoogleCredential credential = new GoogleCredential.Builder()
.setTransport(transport)
.setJsonFactory(jsonFactory)
.setClientSecrets(clientId, clientSecret)
.build()
.setRefreshToken(refreshToken);
try {
credential.refreshToken();
} catch (IOException e) {
e.printStackTrace();
}
youtube = new YouTube.Builder(transport, jsonFactory, credential).build();
I imagine you can do something similar in Python with the API Client Libraries, although I haven't tried Python.
I'm trying to use the Google Docs API with Python+Django and OAuth 2. I've got the OAuth access token, etc. via google-api-python-client, with the code essentially copied from http://code.google.com/p/google-api-python-client/source/browse/samples/django_sample/plus/views.py
Now, I assume I should be using the google gdata API, v 2.0.17. If so, I'm unable to find exactly how to authorize queries made using the gdata client. The docs at http://packages.python.org/gdata/docs/auth.html#upgrading-to-an-access-token (which appear outdated anyway), say to set the auth_token attribute on the client to an instance of gdata.oauth.OAuthToken. If that's the case, what parameters should I pass to OAuthToken?
In short, I'm looking for a brief example on how to authorize queries made using the gdata API, given an OAuth access token.
The OAuth 2.0 sequence is something like the following (given suitably defined application constants for your registered app).
Generate the request token.
token = gdata.gauth.OAuth2Token(client_id=CLIENT_ID,
client_secret=CLIENT_SECRET,
scope=" ".join(SCOPES),
user_agent=USER_AGENT)
Authorise the request token. For a simple command-line app, you can do something like:
print 'Visit the following URL in your browser to authorise this app:'
print str(token.generate_authorize_url(redirect_url=REDIRECT_URI))
print 'After agreeing to authorise the app, copy the verification code from the browser.'
access_code = raw_input('Please enter the verification code: ')
Get the access token.
token.get_access_token(access_code)
Create a gdata client.
client = gdata.docs.client.DocsClient(source=APP_NAME)
Authorize the client.
client = token.authorize(client)
You can save the access token for later use (and so avoid having to do the manual auth step until the token expires again) by doing:
f = open(tokenfile, 'w')
blob = gdata.gauth.token_to_blob(token)
f.write(blob)
f.close()
The next time you start, you can reuse the saved token by doing:
f = open(tokenfile, 'r')
blob = f.read()
f.close()
if blob:
token = gdata.gauth.token_from_blob(blob)
Then, the only change to the authentication sequence is that you pass this token to OAuth2Token by specifying a refresh_token argument:
token = gdata.gauth.OAuth2Token(client_id=CLIENT_ID,
client_secret=CLIENT_SECRET,
scope=" ".join(SCOPES),
user_agent=USER_AGENT,
refresh_token=token.refresh_token)
Hope this helps. It took a while to work it out :-).
This is from https://developers.google.com/gdata/docs/auth/overview:
Warning: Most newer Google APIs are not Google Data APIs. The Google Data APIs documentation applies only to the older APIs that are listed in the Google Data APIs directory. For information about a specific new API, see that API's documentation. For information about authorizing requests with a newer API, see Google Accounts Authentication and Authorization.
You should either use OAuth for both authorization and access or OAuth 2.0 for both.
For OAuth 2.0 API are now at https://developers.google.com/gdata/docs/directory.