Spotipy can't authenticate on Azure Functions (OAuth) - python

I made a script that works perfectly when it runs locally but isn't able to authenticate in my Azure Functions app. At first, I thought it was because it couldn't read the .cache file.
After looking at the logs it's because it can't open a browser window to create the authentication token. I'm fairly new to Azure functions so I'm not sure how I can enable opening a browser if that's even possible.
I looked into the oauth2.py file in spotipy and found it's optional to open the browser but instead, the console asks for the redirected URL. Is there a way for me to get the redirected URL and enter it into the console instead?
Here's my code:
def create_playlist(cred):
"""Creates the playlist for Discover weekly to be copied to"""
# Gain authorization to create playlist
logging.info('Authenticating spotify secrets to create new playlist...')
# spotipy.CacheFileHandler(cache_path='')
sp = spotipy.Spotify(auth_manager=SpotifyOAuth(client_id=cred[0],
client_secret=cred[1],
redirect_uri=cred[2],
scope='playlist-modify-private',
open_browser=False,
))
# Get returned list from get_playlist_info function
logging.info('Determining playlist descriptors...')
info = get_playlist_info()
# New playlist for Discover Weekly
logging.info('Creating new playlist...')
new_playlist = sp.user_playlist_create(user=cred[4],
name=info[0],
public=False,
collaborative=False,
description=info[1])
logging.info('Returning new playlist.')
return new_playlist

In Redirect URIs you enters one or more addresses which you want to whitelist with Spotify. And this URI enables the Spotify authentication service to automatically re-launch your app every time the user logs in.
You can set your Redirect URL by navigating to your Spotify developer dashboard and open the project you are working on. Then click "edit settings" and look for the redirect URIs field and put your redirect URI in the field and lastly save it.
The Authorization Code Flow needs you to add a redirect URI to your application at My Dashboard. The redirect_uri argument or SPOTIPY_REDIRECT_URI environment variable must match the redirect URI added to your application in your Dashboard.
Following are some examples that you can use as redirect URIs.
http://example.com, http://localhost or http://127.0.0.1:9090
The correct way in which you should authenticate yourself is shown in the code snippet below.
token = util.prompt_for_user_token(
username=USERNAME,
scope=SCOPE,
client_id=CLIENT_ID,
client_secret=CLIENT_SECRET,
redirect_uri=REDIRECT_URI)
You should also export your redirect_uri, client ID, and secret before running your script and trying to authenticate. If you don't pass the values directly to the util.prompt_for_user_token function, it will read them from the environment.
Try running these in your terminal before running your script.
export SPOTIPY_CLIENT_ID="YOUR CLIENT ID"
export SPOTIPY_CLIENT_SECRET="YOUR CLIENT SECRET"
export SPOTIPY_REDIRECT_URI='http://localhost/'
For more information you can read this Authorization Code Flow document for Spotipy.

Related

Automating 3-factor authentication through a script for the Lyft Api

I'm trying to use the Lyft rides python API to access Lyft data. Specifically, I'm trying to access the ride estimate endpoint .
from lyft_rides.auth import ClientCredentialGrant
from lyft_rides.session import Session
from lyft_rides.client import LyftRidesClient
auth_flow = ClientCredentialGrant(client_id=MY_ID, client_secret=MY_SECRET, scopes="public")
session = auth_flow.get_session()
client = LyftRidesClient(session)
response = client.get_cost_estimates(start_latitude=start_lat, start_longitude=start_long, end_latitude=end_lat, end_longitude=end_long)
However, the surge rate in the response data is always 0, even during surge hours, and I've diagnosed that it's because I'm not utilizing the 3-legged authentication.
From the lyft developer docs,
3-Legged flow for accessing user-specific endpoints.
To make ride
requests or otherwise access user data, the user must grant you
access. Users who don't have a Lyft account will be prompted to create
a new account if they are directed through the following flow.
From the python docs,
Authorization
If you need access to a Lyft user’s account in order to make requests
on their behalf, you will go through a “3-legged” flow. In this case,
you will need the user to grant access to your application through the
OAuth 2.0 Authorization Code flow. See Lyft API docs.
The Authorization Code flow is a two-step authorization process. The
first step is having the user authorize your app and the second
involves requesting an OAuth 2.0 access token from Lyft. This process
is mandatory if you want to take actions on behalf of a user or access
their information.
from lyft_rides.auth import AuthorizationCodeGrant
auth_flow = AuthorizationCodeGrant(
YOUR_CLIENT_ID,
YOUR_CLIENT_SECRET,
YOUR_PERMISSION_SCOPES,
)
auth_url = auth_flow.get_authorization_url()
Navigate the user to the auth_url where they can grant access to your
application. After, they will be redirected to a redirect_url with the
format REDIRECT_URL?code=UNIQUE_AUTH_CODE. Use this redirect_url to
create a session and start LyftRidesClient.
session = auth_flow.get_session(redirect_url)
client = LyftRidesClient(session)
credentials = session.oauth2credential
Keep credentials information in a secure data store and reuse them to
make API calls on behalf of your user. The SDK will handle the token
refresh for you automatically when it makes API requests with a
LyftRidesClient.
Question
I'm trying to automate the python request within a script. Given that the 3rd leg of the authentication requires manually visiting a url and obtaining a code, is it possible to do this through a script?
[Full Disclosure: I'm one of Lyft's Developer Advocates]
The only way to get that data is by requesting therides.request scope is through the 3-legged OAuth flow (sorry about that). However, you only need to request this external authorization once if you ask for the offline scope as part of the initial authorization. If you have that scope requested initially, you can use refresh_tokens as outlined here and not get prompted for the external URL:
https://developer.lyft.com/docs/authentication#section-step-5-refreshing-the-access-token
If you're only using this script locally I'd recommend going through this authorization once and then building in refresh token logic into your script if your token has expired. Hope that helps!

python3 upload files to ondrive or sharepoint?

Anyone know if this is possible?
I just want to automate dropping some documents into my onedrive for business account.
I tried
import onedrivesdk
from onedrivesdk.helpers import GetAuthCodeServer
from onedrivesdk.helpers.resource_discovery import ResourceDiscoveryRequest
redirect_uri = 'http://localhost:8080'
client_id = 'appid'
client_secret = 'mysecret'
discovery_uri = 'https://api.office.com/discovery/'
auth_server_url='https://login.live.com/oauth20_authorize.srf?scope=wl.skydrive_update'
#auth_server_url='https://login.microsoftonline.com/common/oauth2/authorize',
auth_token_url='https://login.microsoftonline.com/common/oauth2/token'
http = onedrivesdk.HttpProvider()
auth = onedrivesdk.AuthProvider(http,
client_id,
auth_server_url=auth_server_url,
auth_token_url=auth_token_url)
auth_url = auth.get_auth_url(redirect_uri)
code = GetAuthCodeServer.get_auth_code(auth_url, redirect_uri)
auth.authenticate(code, redirect_uri, client_secret, resource=resource)
# If you have access to more than one service, you'll need to decide
# which ServiceInfo to use instead of just using the first one, as below.
service_info = ResourceDiscoveryRequest().get_service_info(auth.access_token)[0]
auth.redeem_refresh_token(service_info.service_resource_id)
client = onedrivesdk.OneDriveClient(service_info.service_resource_id + '/_api/v2.0/', auth, http)
I registered an APP and got a secret and id. But when I ran this I got scope is invalid errors. Plus it tries to launch a webpage which isn't great for a command line kinda environment. I think this SDK might be outdated as well because originally this script had login.microsoftonline, but that wasn't reachable so I changed it to login.live.com.
I wrote this sample code you posted. You replaced the auth_server_URLwith the authentication URL for Microsoft Account authentication, which can only be used to access OneDrive (the consumer product). You need to continue using the login.microsoftonline.com URL to log into your OneDrive for Business account.
You are correct that this pops up a dialog. However, you can write a little supporting code so that only happens the first time you log into a particular app. Follow these steps (assuming you are using the default implementation of AuthProvider:
Use the sample code above up through the line auth.redeem_refresh_token()
The AuthProvider will now have a Session object, which caches the credentials of the current user and session. Use AuthProvider.save_session() to save the credentials for later.
Next time you start your app, use AuthProvider.load_session() and AuthProvider.refresh_token() to retrieve the previous session and refresh the auth token. This will all be headless.
Take note that the default implementation of SessionBase (found here) uses Pickle and is not safe for product use. Make sure to create a new implementation of Session if you intend to deploy this app to other users.
Onerive's website shows "Not Yet" on "OneDrive SDK for Python" to "OneDrive for Business"
https://dev.onedrive.com/SDKs.htm
The github sample codes did not work for me either, it tried to popup a window of authentication, but IE can not find the address:
http://('https//login.microsoftonline.com/common/oauth2/authorize',)?redirect_uri=http%3A%2F%2Flocalhost%3A8080&client_id=034xxxx9-9xx8-4xxf-bexx-1bc5xxxxbd0c&response_type=code
or removed all the "-" in client id
http://('https//login.microsoftonline.com/common/oauth2/authorize',)?redirect_uri=http%3A%2F%2Flocalhost%3A8080&client_id=034xxxx99xx84xxfbexx1bc5xxxxbd0c&response_type=code
Either way, I got the same result, IE did not show the popup with a line "This page can’t be displayed"

Get access token for Soundcloud desktop application?

Toying around with Soundclouds SDK for Python with an impact of TKinter as GUI. Now I want to generate a access token for each user so that I could access more API-endpoints.
I have created an applicaton in Soundclouds Developer portal with a link to my callback.
There is nothing corresponding to generating a access token for an desktop application. Only for server-side application. I tried this code below:
import soundcloud
# create client object with app credentials
client = soundcloud.Client(client_id='YOUR_CLIENT_ID',
client_secret='YOUR_CLIENT_SECRET',
redirect_uri='REDIRECT_URL')
# redirect user to authorize URL
redirect client.authorize_url()
I have set my keys, and redirect_uri as the callback on my webserver. When I run my python file from the terminal, I get this:
File "token.py", line 9
redirect client.authorize_url()
^
SyntaxError: invalid syntax
Using Python 2.7.5+
What is causing this? I want to generete my access token and print in later on.
The solution might be that I need to create an instance of an web browser window, make the user accept the app using Soundcloud connect. The I grab the url and sort out the "code" in the url. Exchanges the code against an access-token and stores it inside a text-file. So that I could grab it later on.
A simple way of obtaining an access token is by first authenticating via the User Credentials flow, which exchanges your username and password for an access token:
client = soundcloud.Client(client_id = 'CLIENT_ID',
client_secret = 'CLIENT_SECRET',
username = 'USERNAME',
password = 'PASSWORD')
print client.access_token
try:
redirect(client.authorize_url())

Get facebook user/app token in a python desktop app

I am writing a python desktop app that will access a user's facebook photos. The app currently supports flickr, which uses a similar oauth authentication process, but I am struggling to figure out how to authenticate the app for facebook. For flickr, the basic steps are:
App opens a browser on the authentication page
user gives the app permission to access the account
App receives a token as a http response that can then be used with flickr's api
I am hoping that there is something similar for facebook, but I haven't been able to figure it out.
There are a variety of facebook API libraries for python, such as Pyfb, which provides a simple way of accessing graph data, but none of them provide an obvious way to do the authentication steps above and retrieve a token that can be used. Here's the example from Pyfb, which presumes that the user token will be manually entered by the user, which is totally ridiculous for a desktop app...
from pyfb import Pyfb
#Your APP ID. You Need to register the application on facebook
#http://developers.facebook.com/
FACEBOOK_APP_ID = 'YOUR_APP_ID'
pyfb = Pyfb(FACEBOOK_APP_ID)
#Opens a new browser tab instance and authenticates with the facebook API
#It redirects to an url like http://www.facebook.com/connect/login_success.html#access_token=[access_token]&expires_in=0
pyfb.authenticate()
#Copy the [access_token] and enter it below
token = raw_input("Enter the access_token\n")
#Sets the authentication token
pyfb.set_access_token(token)
#Gets info about myself
me = pyfb.get_myself()
Here's a shot at answering my own question.
First, the reason the code fragment above doesn't work. The call to pyfb.authenticate opens the authentication link in the default browser. After the user logs in and allows the app access, facebook is supposed to redirect the URL in the browser to something like
https://www.facebook.com/connect/login_success.html#access_token=ACCESS_TOKEN&
expires_in=SOMETIME
In the pyfb code sample, the user is supposed to copy the access token from the URL bar and all should be well. But... presumably because of some security concerns, facebook will perform some Javascript shenanigans which will instead leave you with:
https://www.facebook.com/connect/blank.html#_=_
(It turns out that you can work around this by digging through the browser history on some browsers -- see https://bugs.kde.org/show_bug.cgi?id=319252)
The solution to this for a desktop app is to open a web view within the app. The Javascript code apparently will correctly detect you are authenticating within an app and spit out the full URL with token. So here's an example using Python gtk and webkit:
import gtk
import webkit
view = webkit.WebView()
sw = gtk.ScrolledWindow()
sw.add(view)
win = gtk.Window(gtk.WINDOW_TOPLEVEL)
win.add(sw)
win.show_all()
win.connect("destroy", lambda *args:gtk.main_quit())
client_id = 'XXXXXXXXXXXXX' #your unique app id
auth_url = 'https://www.facebook.com/dialog/oauth?response_type=token&client_id=%s&redirect_uri=https://www.facebook.com/connect/login_success.html'%(client_id,)
view.open(auth_url)
def load_finished(view,frame):
#function will print the url with token second time
print frame.get_uri()
view.connect("document-load-finished",load_finished)
gtk.main()

How to create python test script to access services hosted in GAE which require login

buddies
One of my GAE restful service needs login with admin account. And I'm writing an automation script in python for testing this service. The script simply do a HTTP POST and then check the returned response. The difficult part for me is how to authenticate the test script as an admin user.
I created an admin account for testing purpose. But I'm not sure how to use that account in my test script. Is there a way that my test script can use oath2 or other approach to authenticate itself as a test admin account?
Ok I think this might be what you are looking for, client libraries to authenticate and yeah I believe appengine now recommends using the oauth2 for any kind of authentication:
https://developers.google.com/accounts/docs/OAuth2#libraries
Then you get an auth token where you pass in headers on your restful request like:
# Your authenticated request
Authorization: Bearer TokenHere
Then in your handler you get it like:
try:
user = oauth.get_current_user('https://www.googleapis.com/auth/userinfo')
except NotAllowedError:
user = None
# then from the first link you should be able to access if
user.is_current_user_admin()
This is how I authenticate on android, but I only do this once and store it in session and just enable cookie jar on the httpclient.

Categories