[GH-ISSUE #662] Can a cache file be made in a Heroku environment? Authorization trouble in Django app #396

Closed
opened 2026-02-27 23:22:23 +03:00 by kerem · 3 comments
Owner

Originally created by @xxristoskk on GitHub (Apr 2, 2021).
Original GitHub issue: https://github.com/spotipy-dev/spotipy/issues/662

So I'm trying to deploy an app that would have multiple users authorize their Spotify accounts, but I'm running into an issue with authorization. I have a button for users to authorize their account after giving their username, and everything seems to work with two exceptions: 1) the authorize URL doesn't bring the user to the authorize page, and 2) the tokens that are returned, and saved to the user's profile, are associated with my Spotify account. I thought maybe it was a cache issue, but i have ".cache" in my .gitignore file, so I have no idea how this is happening. Here is my code.

views.py:

from rest_framework.response import Response
from rest_framework import status
from rest_framework.views import APIView
import spotipy
from spotipy.oauth2 import SpotifyOAuth

class AuthURL(APIView):
    def get(self, request):
        # initialize spotify credentials
        oauth = SpotifyOAuth(
            client_id=client_id,
            client_secret=client_secret,
            redirect_uri='https://curation-station-2.herokuapp.com/redirect/',
            scope=scope,
            username=request.user.profile.spotify_username
        )    
        auth_url = oauth.get_authorize_url()
        return Response({'url': auth_url}, status=status.HTTP_200_OK)


def callback(request):
    user = request.user

    #check to see if the user has their profile filled
    if user.profile.spotify_username != '':
        oauth = SpotifyOAuth(
            client_id=client_id,
            client_secret=client_secret,
            redirect_uri='https://curation-station-2.herokuapp.com/redirect/',
            scope=scope,
            username=request.user.profile.spotify_username
        )    
        code = oauth.parse_response_code(request.build_absolute_uri())
        token_info = oauth.get_access_token(code)

        user.profile.spotify_token = token_info['access_token']
        user.profile.token_exp = token_info['expires_at']
        user.profile.spotify_refresh = token_info['refresh_token']
        user.profile.save(update_fields=['spotify_token','spotify_refresh','token_exp'])

        return redirect('dashboard')

html template:

<div class="col s6 center">
        <div class="card grey darken-4">
            <div class='card-content white-text'>
                <span class='card-title'><i class='medium material-icons' style='padding-top: 5px;'>check</i></span>
                <p>Authorize CurationStation to use Spotify</p>
            </div>
            <div class='card-action'>
                {% if request.user.profile.spotify_username == None %}
                    <button class="waves-effect waves-light btn disabled indigo accent-2" onclick="authSpotify()">Authorize</button>
                {% elif not is_valid %}
                    <button class="waves-effect waves-light btn pulse indigo accent-2" onclick="authSpotify()">Authorize</button>
                {% else %}
                    <button class="waves-effect waves-light btn indigo accent-2" onclick="authSpotify()">Authorize</button>
                {% endif %}
            </div>
        </div>
    </div>

<script>
function authSpotify() {
    fetch('/get-auth-url')
        .then((response) => response.json())
        .then((data) => {
            window.location.replace(data.url);
        });
}
</script>

At first I initialized oauth as a global variable without the username, but thought this way would solve the problem, and it didn't. Is it possible for Spotipy to create a cache file within the Heroku environment that I'm not seeing in my GitHub repo?

I'd really like to keep Spotipy for this project since I already had the scripts for finding the music already made.

Originally created by @xxristoskk on GitHub (Apr 2, 2021). Original GitHub issue: https://github.com/spotipy-dev/spotipy/issues/662 So I'm trying to deploy an app that would have multiple users authorize their Spotify accounts, but I'm running into an issue with authorization. I have a button for users to authorize their account after giving their username, and everything seems to work with two exceptions: 1) the authorize URL doesn't bring the user to the authorize page, and 2) the tokens that are returned, and saved to the user's profile, are associated with my Spotify account. I thought maybe it was a cache issue, but i have ".cache" in my .gitignore file, so I have no idea how this is happening. Here is my code. views.py: ``` from rest_framework.response import Response from rest_framework import status from rest_framework.views import APIView import spotipy from spotipy.oauth2 import SpotifyOAuth class AuthURL(APIView): def get(self, request): # initialize spotify credentials oauth = SpotifyOAuth( client_id=client_id, client_secret=client_secret, redirect_uri='https://curation-station-2.herokuapp.com/redirect/', scope=scope, username=request.user.profile.spotify_username ) auth_url = oauth.get_authorize_url() return Response({'url': auth_url}, status=status.HTTP_200_OK) def callback(request): user = request.user #check to see if the user has their profile filled if user.profile.spotify_username != '': oauth = SpotifyOAuth( client_id=client_id, client_secret=client_secret, redirect_uri='https://curation-station-2.herokuapp.com/redirect/', scope=scope, username=request.user.profile.spotify_username ) code = oauth.parse_response_code(request.build_absolute_uri()) token_info = oauth.get_access_token(code) user.profile.spotify_token = token_info['access_token'] user.profile.token_exp = token_info['expires_at'] user.profile.spotify_refresh = token_info['refresh_token'] user.profile.save(update_fields=['spotify_token','spotify_refresh','token_exp']) return redirect('dashboard') ``` html template: ``` <div class="col s6 center"> <div class="card grey darken-4"> <div class='card-content white-text'> <span class='card-title'><i class='medium material-icons' style='padding-top: 5px;'>check</i></span> <p>Authorize CurationStation to use Spotify</p> </div> <div class='card-action'> {% if request.user.profile.spotify_username == None %} <button class="waves-effect waves-light btn disabled indigo accent-2" onclick="authSpotify()">Authorize</button> {% elif not is_valid %} <button class="waves-effect waves-light btn pulse indigo accent-2" onclick="authSpotify()">Authorize</button> {% else %} <button class="waves-effect waves-light btn indigo accent-2" onclick="authSpotify()">Authorize</button> {% endif %} </div> </div> </div> <script> function authSpotify() { fetch('/get-auth-url') .then((response) => response.json()) .then((data) => { window.location.replace(data.url); }); } </script> ``` At first I initialized `oauth` as a global variable without the username, but thought this way would solve the problem, and it didn't. Is it possible for Spotipy to create a cache file within the Heroku environment that I'm not seeing in my GitHub repo? I'd really like to keep Spotipy for this project since I already had the scripts for finding the music already made.
kerem 2026-02-27 23:22:23 +03:00
  • closed this issue
  • added the
    question
    label
Author
Owner

@stephanebruckert commented on GitHub (Apr 2, 2021):

Here is how to make spotipy work in an API https://github.com/plamere/spotipy/blob/master/FAQ.md#how-to-use-spotipy-in-an-api

<!-- gh-comment-id:812482394 --> @stephanebruckert commented on GitHub (Apr 2, 2021): Here is how to make spotipy work in an API https://github.com/plamere/spotipy/blob/master/FAQ.md#how-to-use-spotipy-in-an-api
Author
Owner

@xxristoskk commented on GitHub (Apr 2, 2021):

Thanks @stephanebruckert! I didn't see the FAQ before and it was a bit helpful, but I'm having a hard time wrapping my head around the logic of creating a custom cache handler. I made a class, and it is getting me as far as the Spotify authorization page, but I'm getting a NotImplementedError when being redirected. Here is the class I made.

class CustomCacheHandler(spotipy.cache_handler.CacheHandler):
    def __init__(self, user):
        self.user = user 
    
    def get_token(self):
        token_info = None
        try:
            token_info = {
                'access_token': self.user.profile.spotify_token,
                'expires_at': self.user.profile.token_exp,
                'refresh_token': self.user.profile.spotify_refresh
            }
        except:
            print('No token info')
        return token_info
    
    def save_token(self, token_info):
        try:
            self.user.profile.spotify_token = token_info['access_token']
            self.user.profile.token_exp = token_info['expires_at']
            self.user.profile.spotify_refresh = token_info['refresh_token']
            self.user.profile.save(update_fields=['spotify_token','spotify_refresh','token_exp'])
        except:
            print("Couldn't save token info")

This error is very new to me and so is dealing with subclasses, so thank you in advance for your time and patience!

Edit:
Oops, I see now that those methods need to be renamed to match CacheHandler. I think it works now.

<!-- gh-comment-id:812656819 --> @xxristoskk commented on GitHub (Apr 2, 2021): Thanks @stephanebruckert! I didn't see the FAQ before and it was a bit helpful, but I'm having a hard time wrapping my head around the logic of creating a custom cache handler. I made a class, and it is getting me as far as the Spotify authorization page, but I'm getting a NotImplementedError when being redirected. Here is the class I made. ``` class CustomCacheHandler(spotipy.cache_handler.CacheHandler): def __init__(self, user): self.user = user def get_token(self): token_info = None try: token_info = { 'access_token': self.user.profile.spotify_token, 'expires_at': self.user.profile.token_exp, 'refresh_token': self.user.profile.spotify_refresh } except: print('No token info') return token_info def save_token(self, token_info): try: self.user.profile.spotify_token = token_info['access_token'] self.user.profile.token_exp = token_info['expires_at'] self.user.profile.spotify_refresh = token_info['refresh_token'] self.user.profile.save(update_fields=['spotify_token','spotify_refresh','token_exp']) except: print("Couldn't save token info") ``` This error is very new to me and so is dealing with subclasses, so thank you in advance for your time and patience! Edit: Oops, I see now that those methods need to be renamed to match CacheHandler. I think it works now.
Author
Owner

@xxristoskk commented on GitHub (Apr 5, 2021):

This custom cache handler definitely works in production, now that I changed the method names.

<!-- gh-comment-id:813587210 --> @xxristoskk commented on GitHub (Apr 5, 2021): This custom cache handler definitely works in production, now that I changed the method names.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/spotipy#396
No description provided.