Having trouble using cached tokens with Spotipy for Spotify? - python

I'm trying to use Spotipy to access a user's Spotify library but am running into a bit of trouble. For background, I'm using Flask, SQLAlchemy, and Flask-Login.
I looked off of this tutorial on github to get started, but this one doesn't quite work for me because if you use a cache, all users can access the playlist of the user whose token is cached, and since there is a cached token, any user after the first user can't login to Spotify. Here is some initial setup:
sp_oauth = oauth2.SpotifyOAuth(os.environ['SPOTIPY_CLIENT_ID'],
os.environ['SPOTIPY_CLIENT_SECRET'],
os.environ['SPOTIPY_REDIRECT_URI'],
scope="user-library-read")
To solve this, I first tried storing each user's access code in my database (I'm using SQLAlchemy as well). It looked something like this (under the method for the page that Spotipy redirects to with the access code):
if request.args.get("code"):
dbsession.query(User).get(current_user.uid).addService(
request.args["code"])
dbsession.commit()
However, this route is meant to return the names of the playlists the user owns, so I want it to be accessible without having to go through the Spotify authorization URL every time as long as the user is logged in. So, in the case where request.args["code"] is null, I try:
token_info = sp_oauth.get_access_token(dbsession.query(User)
.get(current_user.uid)
.getService())
spotify = spotipy.Spotify(token_info["access_token"])
Then I try to access the user using this instance of Spotify. However, using the stored access code (unsurprisingly) gives me a Bad Request error. I'm not sure what to do about getting a new code, or what I should store so that I don't need to cache but can still get credentials to access the playlists. Alternatively, is there a way that I can cache but only have certain users access certain tokens in the cache?
Thanks!

You can use the memory cache handler from the spotipy library to store the acess token in memory instead of the disk:
https://github.com/plamere/spotipy/blob/master/spotipy/cache_handler.py
You can also take a look at the example flask app in the examples directory:
https://github.com/plamere/spotipy/blob/master/examples/app.py

Related

Strange session behaviour with a Flask app on Heroku

I have a web application that uses GitHub's OAuth API in order to allow the app's users to interact with GitHub. However, I'm seeing some very odd behaviour with regards to the session cookie.
As a bit of background, I am using peewee to interface with Heroku's Postgres server, and have a User model like so:
class User(peewee.Model):
login = peewee.TextField(unique=False)
token = peewee.TextField()
I am using the web application flow described in the GitHub OAuth documentation, and am successfully getting called back with an access token, which I store in the database, and also in the session [1]:
#app.route('/callback')
def finishlogin():
# I've verified that `token` and `login` are both valid at this point
user = User.create(login=login, token=token)
session['token'] = token
return redirect(url_for('home'))
My route for home is as follows:
#app.route('/')
def home():
if 'token' in session:
user = User.get(token=session.get('token'))
return 'Your login is {}'.format(user.login)
else:
# ...
So far, so good, and this works correctly. However, I am experiencing instances of users logging in, refreshing the page and finding that they are suddenly logged in as someone else. Logging the requests to the app shows that on the second request the session cookie itself has sent the wrong value (i.e. session.get('token') in home() returns a valid, but incorrect value. Clearly the user's browser can't know any other session value, so it seems that there is some "leakage" in setting the session between different clients and requests.
I'm not sure what the problem might be. My database is stored on the Flask g object as described in the peewee docs and has before_request and teardown_request hooks set up to open and close the database connection, and from all the documentation and example code I have read (and I've read a lot!), I seem to be using the session object correctly. I have set up a working secret_key for the session store.
I'm wondering if this could be something going on with Heroku and their routing mesh? But then, how would one user suddenly send another user's session?
Any hints or advice would be appreciated—I've been staring at this for a long time and am at my wits' end.
[1] I'm aware that storing the token directly is a bad design choice. The application is non-public and this will be fixed, but for now I want to describe the problem as it exists, even though it's not ideal.
Answering my own question for future reference.
It seems that this was being caused by Flask's default session cookie behaviour, which is to send a Set-Cookie header with every single request, even for static assets. Our local Squid proxy was therefore gladly caching those requests and re-issuing Set-Cookie headers for every user.
Setting Cache-Control headers for the whole app seems to fix the issue.

Facebook api graph access token

there is any way to get the access token automatically with python using login informations ?
Something like this :
import requests
r=requests.get('https://graph.facebook.com/oauth/access_token?grant_type=get_token&
client_id=idclient_secret=password&privilege=')
print r.text
As far as I know you can't get users access token without users interaction.
You can get app token though like this:
facebook.get_app_access_token(APP_ID, APP_SECRET)
To get APP_ID and APP_SECRET you need to create new app here: https://developers.facebook.com/ Note that you will get much less meta data using app's token than using user's token.
I was writing script collecting data from facebook lately and I had same problem. I just switched to app token since my script runs every hour as cron job so it was impossible to deliver new token every time manually.

Python 3: Spotify Add Song To Public Playlist

So currently I have in place a system using Flask running on my localhost:8080 to add 1 song at a time to a public Spotify playlist. Unfortunately how I have implemented this it requires a browser to add a song. What I want to be able to do is URLLIB or possibly the REQUESTS library to do this without a browser. I have been unsuccessful in my attempts to do this bot URLLIB and REQUESTS only see the first page of my local host it is never redirected to my call back in the code that I linked below.
My Implementation
How would I go about implemented a non browser interface to add a song to a playlist? (Mind you this is python 3)
In order to add a song to a playlist, you need the playlist's owner to grant access to your application, so you will need a web interface at some point to carry out this step.
It's important that you obtain the access token using the Authorization Code Flow since that's how you will get an access token and a refresh token. Use that refresh token in your app to obtain access tokens without having the user to re-authorize your app.
So in brief:
Implement a web site that uses the Authorization Code. A user logs in and you obtain an access token and refresh token. Using the refresh token you will be able to generate access tokens without the user having to input their credentials.
Take the refresh token and include it in your script. Before making the request to add a track, obtain a fresh access token using the refresh token.
It's a bit cumbersome but that's the only way to use OAuth2 without exposing the user's username+password to an app.

How can I call an endpoint in my appengine instance without doing oAuth? (Mirror API)

I am trying to create some Glassware with the Mirror API. I am new to using AppEngine and Jinja2. I have python experience but never with a web framework before. So basically I am very new at this.
I have modified the Python quickstart for the mirror API to include many of my endpoints and designs. Basically I want to be able to be able to POST data from a constrained device to Glass. I have an endpoint all setup which works to accept and parse out the data and send the timeline item.
My problem is that the device itself is acting all on it's own and cannot provide input, therefore when I call my app from it e.g. https://foo.appspot.com?operation=deviceData the app presents the auth page and then nothing happens. I can see in the logs that the auth page is being sent, but the device has no idea what to do with this.
Basically, I need a way where I can hardcode credentials and get around having to do oauth everytime. What is the recommended way to do this? Another app which doesn't require auth which passes the data along? This would be fine as I only need to set this up with one user right now, it is for an internal demo only.
Is it possible to set my credentials in a header and auth automatically without handling any return, more like how basic auth works?
There are also the "Simple API access" keys. Would these work in this situation, I tried creating browser and server keys and tried them on the device and in the browser by doinghttps://foo.appspot.com?operation=deviceData&key=KEY_HERE but in both cases I was still prompted to login. Is this what simple access keys are for? Do they not work with the mirror API?
Basically my question is, what's the easiest way to allow access to my apps endpoints without having to oAuth or having a hard coded user which auto-auths?
Here is the project that I started with: https://github.com/googleglass/mirror-quickstart-python

Securing RESTapi in flask

The app I'm deving uses a lot of ajax calls. Unfortunately I hit a snag when researching on how to restrict access to the api. For example:
i have table that does an ajax call to http://site/api/tasks/bob
i need to make sure that only bob, logged in, can read that table
(otherwise somebody who knows the pattern might request to see bob's
tasks by simply entering the url in the browser).
on a different page,the same table needs to be able to call http://site/api/tasks/all and show the tasks of all users (only an admin should be able to do that)
Thank you for your time reading this and maybe answering it.
The thousand-foot view is you need to authenticate the user either with:
A) HTTP-Auth (either basic or digest) on each request.
B) Server-side sessions. (The user authenticates and receives a session key - their user information is stored in the session backend on the server, attached to that key Once they have a session they can make requests passing their session key back to you (either in the URL or in a cookie) and the information they have access to is returned to them.)
Flask has a pair of useful extensions that deal with a large part of this sort of thing - check out Flask-Login and Flask-Principal to see examples of how authorization can be added to a Flask application.

Categories