1

In my app, I am using the Authorization Code flow for Spotify.

Here is the authorization callback endpoint, where I get the tokens from Spotify.


spotify_auth.py

from flask import Blueprint
from flask import Flask, request, session, redirect

spotify_auth_bp = Blueprint('spotify_auth', 
                    __name__, 
                    template_folder='templates',
                    static_url_path='static') 

@spotify_auth_bp.route("/callback", methods=['GET', 'POST'])
def spotify_callback():

    SPOTIFY_TOKEN_URL = "https://accounts.spotify.com/api/token"

    CLIENT_ID =   os.environ.get('SPOTIPY_CLIENT_ID')
    CLIENT_SECRET = os.environ.get('SPOTIPY_CLIENT_SECRET')
    REDIRECT_URI = os.environ.get('SPOTIPY_REDIRECT_URI')

    auth_token = request.args['code']

    code_payload = {
        "grant_type": "authorization_code",
        "code": auth_token,
        "redirect_uri": REDIRECT_URI,
        'client_id': CLIENT_ID,
        'client_secret': CLIENT_SECRET,
    }

    post_request = requests.post(SPOTIFY_TOKEN_URL, data=code_payload)

    response_data = json.loads(post_request.text)

    access_token = response_data["access_token"]
    refresh_token = response_data["refresh_token"]
    token_type = response_data["token_type"]
    expires_in = response_data["expires_in"]

   # At this point, there is to generate a custom token for the frontend
   # Either a self-contained signed JWT or a random token
   # In case the token is not a JWT, it should be stored in the session (in case of a stateful API)
   # or in the database (in case of a stateless API)
   # In case of a JWT, the authenticity can be tested by the backend with the signature so it doesn't need to be stored at all
   # Let's assume the resulting token is stored in a variable named "token"

res = Response('http://localhost/about', status=302)
res.set_cookie('auth_cookie', token)
return res

Now I have these functions to handle my access and refresh tokens:

def refresh_access_token():
    SPOTIFY_TOKEN_URL = "https://accounts.spotify.com/api/token"

    code_payload = {
        "grant_type": "refresh_token",
        "refresh_token": refresh_token,
    }

    encode = 'application/x-www-form-urlencoded'
    auth = base64.b64encode("{}:{}".format(client_id, client_secret).encode())
    headers = {"Content-Type" : encode, "Authorization" : "Basic {}".format(auth)} 

    post_request = requests.post(SPOTIFY_TOKEN_URL, data=code_payload, headers=headers)
    response_data = json.loads(post_request.text)

    access_token = response_data["access_token"]
    refresh_token = response_data["refresh_token"]
    token_type = response_data["token_type"]
    expires_in = response_data["expires_in"]

    # save new tokens to database
    user = User.query.filter_by(refresh_token=refresh_token).first()
    user.access_token = access_token
    user.refresh_token = refresh_token
    db.session.commit()

    return access_token



def get_token():
    # check for cookies 
    access_token_cookie = request.cookies.get('access_token')
    refresh_token_cookie = request.cookies.get('refresh_token')

    # check if this is first User login
    user = User.query.filter_by(access_token=access_token_cookie).first()
    if user:
        # Checking if token has expired
        now = int(time.time())
        token_is_expired = request.cookies.get('expires_in') - now < 60
         # Refreshing token if it has expired
        if token_is_expired:
            # get token for renewal from db
            refresh_token = user.refresh_token
            # request another access token
            access_token = refresh_access_token(refresh_token)
        else:
            access_token = user.access_token
    else:
        # first time user
        user = User.query.filter_by(id=1).first()

        user.access_token_cookie = access_token_cookie
        user.refresh_token = refresh_token_cookie
        db.session.commit()

        access_token = access_token_cookie

    return access_token

Ideally I would like to import theses functions into my modules and pass the token to my resources simply with:

spotify_utils.py

import get_token

token =  get_token()

How do I put these functions in context?


I've learned that copy_current_request_context could help me with this.

Any ideas?

ofirule
  • 4,233
  • 2
  • 26
  • 40
8-Bit Borges
  • 9,643
  • 29
  • 101
  • 198
  • This might help: [RuntimeError: working outside of request context](https://stackoverflow.com/questions/27220194/runtimeerror-working-outside-of-request-context#27224426) – Rene Mar 20 '20 at 21:42

0 Answers0